如何获取特定时区的开始日期和结束日期的UTC即时("Europe/Paris")



我想从特定时区的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() ) ;

然后可以使用几种方便的比较方法,如abutscontainsenclosesintersectionoverlapsunion

Timestamp

切勿使用java.sql.Timestamp类。这个类是Java最早版本附带的糟糕的日期-时间类的一部分。这些类现在是遗留的,完全被JSR310中定义的现代java.time类所取代,并构建到Java8及更高版本中。

从JDBC 4.2开始,我们可以用数据库交换java.time对象。使用getObjectsetObject以及updateObject

JDBC规范奇怪地要求支持OffsetDateTime,但不支持更常用的InstantZonedDateTime。您的特定驱动程序可能支持这些其他类型。如果没有,请转换。

从数据库检索。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Instant instant = odt.toInstant() ;

正在发送到数据库。

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
myPreparedStatement.setObject( … , odt ) ;

最新更新