如何在特定时区 ("Europe/Paris") 获取今天的开始日期和结束日期的 UTC Instant
How can I get UTC Instant of startDate and endDate of today in a specific time zone ("Europe/Paris")
我想从特定时区的 Java(也是 UTC)获取 UTC 即时(因为我的数据库存储在 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)
- 这是 Europe/Paris 时区的 UTC 时间的 start/end 吗?
- 我期待
2020-04-11 02:00:00.0(Timestamp), 2020-04-12 02:00:00.0(Timestamp)
现在,巴黎是夏令时:UTC+2。巴黎 'ahead' UTC 时差 2 小时。
所以 00:00:00 在巴黎当地时间是 22:00:00 UTC。
Is this the start/end of the day UTC time in Europe/Paris zone ?
是的。 Europe/Paris 现在是夏令时。巴黎的午夜发生在 22:00 UTC 时间。
I was expecting to have 2020-04-11 02:00:00.0(Timestamp), 2020-04-12 02:00:00.0(Timestamp)
不对,02:00 UTC 在巴黎时间应该是 04:00。
以编程方式询问时刻是否在夏令时
Is this the start/end of the day UTC time in Europe/Paris zone ?
获取一天的开始。
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 中,开头是 inclusive,结尾是 exclusive。
所以一整天从一天的第一刻开始,一直到但不包括 下一个 天的第一刻。
ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtStartOfDay = instant.atZone( z ).toLocalDate().atStartOfDay( z ) ;
ZonedDateTime zdtStartOfNextDay = instant.atZone( z ).toLocalDate().plusDays( 1 ).atStartOfDay( z ) ;
您可能希望将该代码分成更多行,以便更容易 reading/debugging。
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 ) ;
看到这个 code run live at 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]
三十加 Interval
如果你经常用时间跨度做这种工作,那么我建议添加 ThreeTen-Extra library to your project. That library includes the Interval
class 来跟踪时间跨度作为一对 Instant
对象。
Interval interval = Interval.of( zdtStartOfDay.toInstant() , zdtStartOfNextDay.toInstant() ) ;
然后您可以使用几种方便的比较方法,例如 abuts
、contains
、encloses
、intersection
、overlaps
和 union
。
Timestamp
切勿使用 java.sql.Timestamp
class。这个 class 是 Java 最早版本附带的可怕的日期时间 classes 的一部分。这些 classes 现在是遗留的,完全被现代 java.time classes 所取代,在 JSR 310 中定义并内置于 Java 8然后。
从 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 ) ;
我想从特定时区的 Java(也是 UTC)获取 UTC 即时(因为我的数据库存储在 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)
- 这是 Europe/Paris 时区的 UTC 时间的 start/end 吗?
- 我期待
2020-04-11 02:00:00.0(Timestamp), 2020-04-12 02:00:00.0(Timestamp)
现在,巴黎是夏令时:UTC+2。巴黎 'ahead' UTC 时差 2 小时。
所以 00:00:00 在巴黎当地时间是 22:00:00 UTC。
Is this the start/end of the day UTC time in Europe/Paris zone ?
是的。 Europe/Paris 现在是夏令时。巴黎的午夜发生在 22:00 UTC 时间。
I was expecting to have 2020-04-11 02:00:00.0(Timestamp), 2020-04-12 02:00:00.0(Timestamp)
不对,02:00 UTC 在巴黎时间应该是 04:00。
以编程方式询问时刻是否在夏令时
Is this the start/end of the day UTC time in Europe/Paris zone ?
获取一天的开始。
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 中,开头是 inclusive,结尾是 exclusive。
所以一整天从一天的第一刻开始,一直到但不包括 下一个 天的第一刻。
ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtStartOfDay = instant.atZone( z ).toLocalDate().atStartOfDay( z ) ;
ZonedDateTime zdtStartOfNextDay = instant.atZone( z ).toLocalDate().plusDays( 1 ).atStartOfDay( z ) ;
您可能希望将该代码分成更多行,以便更容易 reading/debugging。
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 ) ;
看到这个 code run live at 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]
三十加 Interval
如果你经常用时间跨度做这种工作,那么我建议添加 ThreeTen-Extra library to your project. That library includes the Interval
class 来跟踪时间跨度作为一对 Instant
对象。
Interval interval = Interval.of( zdtStartOfDay.toInstant() , zdtStartOfNextDay.toInstant() ) ;
然后您可以使用几种方便的比较方法,例如 abuts
、contains
、encloses
、intersection
、overlaps
和 union
。
Timestamp
切勿使用 java.sql.Timestamp
class。这个 class 是 Java 最早版本附带的可怕的日期时间 classes 的一部分。这些 classes 现在是遗留的,完全被现代 java.time classes 所取代,在 JSR 310 中定义并内置于 Java 8然后。
从 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 ) ;