我正在使用一些遗留代码并且我正在迭代一些值,遗留代码使用sql.timestamp值检查新一天的开始:
public static final long MILLIS_PER_SECOND = 1000;
public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
if (entry.getPeriodEnd().getTime() % TimestampUtils.MILLIS_PER_DAY == 0 || i >= throughputEntries.size()) {
...
}
结果永远不会0
所以它只会在if
i >= throughputEntries.size()
我无法理解他是如何获得0
结果的,可能他的数据不同,并且总是以某个时间段结束,这会产生0
我可以重写代码,可能会对日期进行检查,但想知道他是如何用他的代码实现的。
我不确定这可以用我提供的代码解决,但也许我错过了一些东西......
修改
所以我最终了解了这个问题,感谢@ t0r0X& @Leo
我修改了我的代码以使用Joda-Time,如下所示:
LocalDate newDay = null;
int count = 0;
public void calcAvg(){
DateTimeZone zone = DateTimeZone.getDefault();
LocalDate throughtputDate = entry.getPeriodEnd().toDateTime(zone).toLocalDate();
if ( this.newDay(throughtputDate) || i >= throughputEntries.size()) {
...
}
}
public boolean newDay(LocalDate date){
boolean go = false;
if(count !=0){
if(date.isAfter(newDay)){
newDay = date;
go = true;
}
}
else{
newDay = date;
count++;
}
return go;
}
可能比我写的方法更清晰地检查新日期,但时间不等人。
答案 0 :(得分:3)
原始代码的作者可能使用了合成的“圆形”数据。也许使用(现在已弃用)java.sql.Timestamp constructor ...
new Timestamp(116, 1, 25, 0, 0, 0, 0)
或者可能使用(也已弃用)Date constructor ...
new Timestamp(new Date(116, 1, 25).getTime())
或者他可能已经解析了一些测试数据,例如'2016年1月25日' ...
看,马,没有毫米! ; - )
无论如何,检查“新的一天”取决于你如何定义它。通常您需要一个参考日期,就像之前处理的条目一样。
第4次查看代码entry.getPeriodEnd().getTime()
:条目看起来像时间段......所以必须有getPeriodBegin()
方法......我想所需的检查是验证是否期末是在另一天开始的时间......我是对的吗?
脏代码(不推荐使用的方法):
Timestamp begin = entry.getPeriodBegin()
Timestamp end = entry.getPeriodEnd()
if (begin.getYear() != end.getYear() || begin.getMonth() != end.getMonth() || begin.getDay() != end.getDay() ....)
清洁代码:
我的建议:甚至不要以java.util.Calendar (proposal on Stackoverflow)开头。使用DateUtils from Apache Commons Lang(也建议here on Stackoverflow; comments are relevant),或者我最喜欢的是JodaTime和stop worring (suggestion also on Stackoverflow; comments are relevant)。我个人总是对JodaTime感到满意。
不要忘记(感谢@Leo对这个问题的评论,我仍然生活,咳嗽,工作,在Java 6-7世界: - / ...):如果使用Java 8或更高版本,去寻找新的java.time课程。
答案 1 :(得分:1)
Answer by t0r0X是正确的,但使用过时的类。
此外,您通常不应该使用java.sql。*类来执行业务逻辑。它们用于数据传入和传出数据库,但仅此而已。立即将java.sql.Timestamp / .Date / .Time转换为java.time类型。使用java.time类型执行业务逻辑。希望有一天,在更新JDBC驱动程序以直接处理java.time之后,java.sql类型将逐渐消失。
问题和意见不明确。但我会采取刺戳,因为它似乎与按日期累积数字有关。
Java 8及更高版本附带了优秀的java.time框架。见Tutorial。这些新类取代了旧的麻烦的java.util.Date/.Calendar类。
在这些新类中,LocalDate
表示没有时间或时区的仅限日期的值。 java.sql.Timestamp
是日期时间值而不是仅日期。但我们可以在java.time.Instant
的时间轴上转换为UTC。然后我们应用时区(ZoneId
)来获取ZonedDateTime
。由此我们可以提取LocalDate
。 LocalDate
正是我们所需要的Map
积累一个数字总和的关键。
Instant instant = myJavaSqlTimestamp.toInstant();
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
LocalDate localDate = zdt.toLocalDate();
请注意时区至关重要。虽然LocalDate
不保留时区,但日期仅在时区的上下文中有意义。在任何特定时刻,世界各地的日期都不一样。如果未指定,则应用JVM的当前默认时区。此页面上的其他代码明确询问当前默认值。我强烈反对在此问题中使用默认值。 JVM的当前默认时区可以在应用程序运行之前的任何时刻更改,甚至,而您的应用程序运行!如果按日期计算总数,则业务逻辑必须考虑该日期的含义。 Specify that time zone explicitly。在这里,我随意选择了America/Montreal
。
之前您会将Map
的LocalDate实例化为所收集数字的总和。我将假设我们正在处理BigInteger
作为此演示的数字类型。
Map< LocalDate , BigInteger ) map = new HashMap<>();
我们在遇到的每个LocalDate
日期值的地图中添加一个条目。我们假设我们有一个通过JDBC从数据库获得的BigInteger myNumber
。
BigInteger oldTotalForDate = map.get( localDate );
BigInteger newTotalForDate = ( null == oldTotalForDate ) ? myNumber : oldTotalForDate.add( myNumber) ;
if ( null == newTotalForDate ) { // If we failed to get new sum.
// TODO: Handle error condition. Perhaps: map.remove(key);
} else { // Else normal, we have a new total. Store it in map.
map.put( localDate , newTotalForDate ); // Replaces any old value.
}
通过在Java 8及更高版本中使用新的Lambda语法功能使用新的Map::merge
方法,可以缩短上面的代码。