使用 sql.timestamp 检查新的一天
Checking for a new day using sql.timestamp
我正在使用一些遗留代码并迭代一些值,遗留代码正在使用 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 constructor ...
new Timestamp(116, 1, 25, 0, 0, 0, 0)
或者可能使用(也已弃用)Date constructor ...
new Timestamp(new Date(116, 1, 25).getTime())
或者他可能已经解析了一些测试数据,例如'2016-01-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 Whosebug). Either use DateUtils from Apache Commons Lang (also suggested here on Whosebug; comments are relevant), or, my favourite, get JodaTime and stop worring (suggestion also on Whosebug; comments are relevant) 开头。我个人一直对 JodaTime 很满意。
PS
不要忘记(感谢@Leo 对这个问题的评论,我仍然生活,咳咳,工作,在一个 Java 6-7 的世界 :-/ ...):如果使用 Java 8 或更高版本,选择新的 java.time 类.
是正确的,但使用过时的 类。
此外,您通常不应使用 java.sql.* 类 来处理业务逻辑。它们旨在用于进出数据库的数据传输,仅此而已。立即将 java.sql.Timestamp/.Date/.Time 转换为 java.time 类型。使用 java.time 类型执行您的业务逻辑。希望有一天 java.sql 类型会在 JDBC 驱动程序更新为直接处理 java.time 后消失。
问题和评论不清楚。但我会尝试一下,因为它似乎与按日期累积数字有关。
java.time
Java8及以后自带的优秀java.time framework. See Tutorial。这些新的 类 取代了 java.util.Date/.Calendar.
的旧的麻烦 类
其中新的类是LocalDate
for a date-only value without time-of-day nor time zone. The java.sql.Timestamp
is a date-time value rather than date-only. But we can convert to java.time.Instant
, a moment on the timeline in UTC. Then we apply a time zone (ZoneId
) to get a ZonedDateTime
. From that we may extract a LocalDate
. That LocalDate
is just what we need as keys for a 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
of LocalDate to a sum of the numbers being collected. I will assume we are dealing with BigInteger
作为我们此演示的数字类型。
Map< LocalDate , BigInteger ) map = new HashMap<>();
我们为遇到的每个 LocalDate
日期值在该地图中添加一个条目。我们假设我们有一个 BigInteger myNumber
通过 JDBC.
从数据库中获取
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 及更高版本中新的 Map::merge
方法使用新的 Lambda 语法功能来缩短。
我正在使用一些遗留代码并迭代一些值,遗留代码正在使用 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 constructor ...
new Timestamp(116, 1, 25, 0, 0, 0, 0)
或者可能使用(也已弃用)Date constructor ...
new Timestamp(new Date(116, 1, 25).getTime())
或者他可能已经解析了一些测试数据,例如'2016-01-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 Whosebug). Either use DateUtils from Apache Commons Lang (also suggested here on Whosebug; comments are relevant), or, my favourite, get JodaTime and stop worring (suggestion also on Whosebug; comments are relevant) 开头。我个人一直对 JodaTime 很满意。
PS
不要忘记(感谢@Leo 对这个问题的评论,我仍然生活,咳咳,工作,在一个 Java 6-7 的世界 :-/ ...):如果使用 Java 8 或更高版本,选择新的 java.time 类.
此外,您通常不应使用 java.sql.* 类 来处理业务逻辑。它们旨在用于进出数据库的数据传输,仅此而已。立即将 java.sql.Timestamp/.Date/.Time 转换为 java.time 类型。使用 java.time 类型执行您的业务逻辑。希望有一天 java.sql 类型会在 JDBC 驱动程序更新为直接处理 java.time 后消失。
问题和评论不清楚。但我会尝试一下,因为它似乎与按日期累积数字有关。
java.time
Java8及以后自带的优秀java.time framework. See Tutorial。这些新的 类 取代了 java.util.Date/.Calendar.
的旧的麻烦 类其中新的类是LocalDate
for a date-only value without time-of-day nor time zone. The java.sql.Timestamp
is a date-time value rather than date-only. But we can convert to java.time.Instant
, a moment on the timeline in UTC. Then we apply a time zone (ZoneId
) to get a ZonedDateTime
. From that we may extract a LocalDate
. That LocalDate
is just what we need as keys for a 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
of LocalDate to a sum of the numbers being collected. I will assume we are dealing with BigInteger
作为我们此演示的数字类型。
Map< LocalDate , BigInteger ) map = new HashMap<>();
我们为遇到的每个 LocalDate
日期值在该地图中添加一个条目。我们假设我们有一个 BigInteger myNumber
通过 JDBC.
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 及更高版本中新的 Map::merge
方法使用新的 Lambda 语法功能来缩短。