>我正在使用一些遗留代码,并且正在循环访问一些值,旧代码正在使用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
,因此只有在i >= throughputEntries.size()
时才会进入if
我无法理解他是如何获得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;
}
可能比我写的方法更干净地检查新日期,但时间不等人。
原始代码的作者可能使用了合成的"圆形"数据。也许使用(现在已弃用的)java.sql.Timestamp构造函数...
new Timestamp(116, 1, 25, 0, 0, 0, 0)
或者可能使用(也已弃用的)Date 构造函数...
new Timestamp(new Date(116, 1, 25).getTime())
或者他可能已经解析了一些测试数据,例如'2016-01-25'......
看妈,没有毫! ;-)
无论如何,检查"新的一天"取决于您如何定义它。通常,您需要一个参考日期,例如之前处理的条目。
更新:
第四次查看代码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(关于Stackoverflow的建议)开始。要么使用Apache Commons Lang的DateUtils(在Stackoverflow上也建议使用;评论是相关的),要么,我最喜欢的,获取JodaTime并停止担心(建议也在Stackoverflow上;评论是相关的)。我个人一直对JodaTime感到满意。
附言
不要忘记(感谢@Leo对这个问题的评论,我仍然生活在Java 6-7世界中:-/...):如果使用Java 8或更高版本,请选择新的java.time类。
t0r0X 的答案是正确的,但使用过时的类。
此外,您通常不应该使用 java.sql.* 类来执行业务逻辑。它们用于传入和传出数据库的数据传输,但仅此而已。立即转换 java.sql.Timestamp/。日期/。时间到 java.time 类型。使用 java.time 类型执行业务逻辑。希望有一天,在JDBC驱动程序更新为直接处理java.time之后,java.sql类型会消失。
问题和评论不清楚。但我会试一试,因为它似乎与按日期累积数字有关。
java.time
Java 8及更高版本带有出色的java.time框架。请参阅教程。这些新类取代了java.util.Date/的旧麻烦类。日历。
在这些新类中,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 的当前默认时区可以在应用程序运行之前的任何时刻更改,甚至在应用程序运行时更改!如果按日期对数字求和,则业务逻辑必须考虑到该日期含义的某个时区。显式指定该时区。在这里,我任意选择了America/Montreal
.
早些时候,您会将 LocalDate 的Map
实例化为正在收集的数字的总和。我假设我们正在处理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
方法来缩短。