我想从特定时区的Java(也在UTC中(中获取UTC即时信息(因为我的DB是以UTC存储的(,这是我迄今为止尝试过的:
public static Instant getStartOfTheDayDateTime(Instant instant, String zoneId) {
ZonedDateTime zoned = instant.atZone(ZONE_ID_TO_ZONE_MAP.get(zoneId));
ZoneId zone = ZoneId.of(zoneId);
return zoned.toLocalDate().atStartOfDay(zone).toInstant();
// ZonedDateTime startOfTheDay = zoned.withHour(0)
// .withMinute(0)
// .withSecond(0)
// .withNano(0);
//
// return startOfTheDay.toInstant();
}
public static Instant getEndOfTheDayDateTime(Instant instant, String zoneId) {
ZonedDateTime zoned = instant.atZone(ZONE_ID_TO_ZONE_MAP.get(zoneId));
ZonedDateTime endOfTheDay = zoned.withHour(0)
.withMinute(0)
.withSecond(0)
.withNano(0)
.plusDays(1);
return endOfTheDay.toInstant();
}
每次尝试都显示:
2020-04-10 22:00:00.0(Timestamp), 2020-04-11 22:00:00.0(Timestamp)
- 这是欧洲/巴黎地区一天的开始/结束UTC时间吗
- 我本来希望有
2020-04-11 02:00:00.0(Timestamp), 2020-04-12 02:00:00.0(Timestamp)
现在,巴黎是夏令时间:UTC+2。巴黎比UTC领先2小时。
因此,巴黎当地时间00:00:00是协调世界时22:00:00。
这是欧洲/巴黎地区一天的开始/结束UTC时间吗?
是。欧洲/巴黎处于夏令时。巴黎午夜发生在协调世界时22:00。
我原本预计会有2020-04-11 02:00:00.0(时间戳(,2020-04-12 02:00:00.0[时间戳]
这不对,02:00 UTC在巴黎时间应该是04:00。
以编程方式询问某个时刻是否处于夏令时
这是欧洲/巴黎地区一天的开始/结束UTC时间吗?
开始新的一天。
ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtStartOfDay = instant.atZone( z ).toLocalDate().atStartOfDay( z ) ;
询问该时刻是否处于该区域的夏令时。
ZoneRules rules = z.getRules();
boolean isDst = rules.isDaylightSavings( zdtStartOfDay.toInstant() );
传递日期-时间对象,而不仅仅是字符串
public static Instant getStartOfTheDayDateTime(Instant instant, String zoneId)
我建议您让调用程序员传递一个有效的ZoneId
对象,而不仅仅是一个字符串。验证其字符串输入不应该是该方法的工作。如果期望Instant
是合理的,那么期望ZoneId
也是合理的。
public static Instant getStartOfTheDayDateTime(Instant instant, ZoneID zoneId )
半开
public static Instant getEndOfTheDayDateTime(Instant instant, String zoneId) {
试图确定一天中的最后时刻是不可能的,因为最后一秒是无限可分的。
此外,这种定义时间跨度的方法也很尴尬。这使得对接多个跨度变得棘手。各种软件系统和协议在使用毫秒、微秒、纳秒或其他分数的最后一秒的分辨率上有所不同。
日期时间处理的常见做法是使用半开放方法跟踪时间跨度。在Half-Open中,开头是包含的,而结尾是不包含的。
因此,一整天从一天中的第一刻开始,一直持续到下一天的第一刻,但不包括。
ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtStartOfDay = instant.atZone( z ).toLocalDate().atStartOfDay( z ) ;
ZonedDateTime zdtStartOfNextDay = instant.atZone( z ).toLocalDate().plusDays( 1 ).atStartOfDay( z ) ;
您可能希望将代码分解为更多的行,以便更容易地读取/调试。
Instant instant = Instant.now() ; // Or passed in.
ZoneId z = ZoneId.of( "Europe/Paris" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
LocalDate ld = zdt.toLocalDate() ;
LocalDate ldNextDay = ld.plusDays( 1 ) ;
ZonedDateTime zdtStartOfNextDay = ldNextDay.atStartOfDay( z ) ;
请参阅IdeOne.com上实时运行的代码。例如:
System.out.println( instant ) ; // 2020-04-13T00:15:25.235341Z
System.out.println( zdt ) ; // 2020-04-13T02:15:25.235341+02:00[Europe/Paris]
System.out.println( ld ) ; // 2020-04-13
System.out.println( ldNextDay ) ; // 2020-04-14
System.out.println( zdtStartOfNextDay ) ; // 2020-04-14T00:00+02:00[Europe/Paris]
ThreeTen ExtraInterval
如果你经常在时间跨度内进行这种工作,那么我建议将ThreeTen Extra库添加到你的项目中。该库包括作为一对Instant
对象跟踪一段时间的Interval
类。
Interval interval = Interval.of( zdtStartOfDay.toInstant() , zdtStartOfNextDay.toInstant() ) ;
然后可以使用几种方便的比较方法,如abuts
、contains
、encloses
、intersection
、overlaps
和union
。
Timestamp
切勿使用java.sql.Timestamp
类。这个类是Java最早版本附带的糟糕的日期-时间类的一部分。这些类现在是遗留的,完全被JSR310中定义的现代java.time类所取代,并构建到Java8及更高版本中。
从JDBC 4.2开始,我们可以用数据库交换java.time对象。使用getObject
和setObject
以及updateObject
。
JDBC规范奇怪地要求支持OffsetDateTime
,但不支持更常用的Instant
和ZonedDateTime
。您的特定驱动程序可能支持这些其他类型。如果没有,请转换。
从数据库检索。
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;
正在发送到数据库。
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;