简体   繁体   English

如何在特定时区(“欧洲/巴黎”)中获取今天的 startDate 和 endDate 的 UTC 瞬间

[英]How can I get UTC Instant of startDate and endDate of today in a specific time zone (“Europe/Paris”)

I want to get the UTC instant (since my DB is storing in UTC) from Java (which is also in UTC) of a particular time zone, this is what I have tried so far:我想从特定时区的 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();

    }

Every attempt shows:每一次尝试都表明:

2020-04-10 22:00:00.0(Timestamp), 2020-04-11 22:00:00.0(Timestamp)
  • Is this the start/end of the day UTC time in Europe/Paris zone?这是欧洲/巴黎地区一天 UTC 时间的开始/结束吗?
  • I was expecting to have 2020-04-11 02:00:00.0(Timestamp), 2020-04-12 02:00:00.0(Timestamp)我期待有2020-04-11 02:00:00.0(Timestamp), 2020-04-12 02:00:00.0(Timestamp)

Right now, Paris is on summer time: UTC+2.现在,巴黎正处于夏令时:UTC+2。 Paris is 'ahead' of UTC by 2 hours.巴黎比世界标准时间“领先” 2 小时。

So 00:00:00 in Paris local time is 22:00:00 UTC.所以巴黎当地时间的 00:00:00 是 22:00:00 UTC。

Is this the start/end of the day UTC time in Europe/Paris zone?这是欧洲/巴黎地区一天 UTC 时间的开始/结束吗?

Yes.是的。 Europe/Paris is in daylight savings time.欧洲/巴黎处于夏令时。 Midnight in Paris occurred at 22:00 UTC time.巴黎的午夜发生在 UTC 时间 22:00。

I was expecting to have 2020-04-11 02:00:00.0(Timestamp), 2020-04-12 02:00:00.0(Timestamp)我期待有 2020-04-11 02:00:00.0(Timestamp), 2020-04-12 02:00:00.0(Timestamp)

That's not right, 02:00 UTC would have been 04:00 in Paris time.这是不对的,02:00 UTC 在巴黎时间应该是 04:00。

Ask programmatically if a moment is in DST以编程方式询问某个时刻是否在 DST

Is this the start/end of the day UTC time in Europe/Paris zone?这是欧洲/巴黎地区一天 UTC 时间的开始/结束吗?

Get start of day.开始一天。

ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtStartOfDay = instant.atZone( z ).toLocalDate().atStartOfDay( z ) ; 

Ask if that moment is in DST for that zone.询问那个时刻是否在那个区域的夏令时。

ZoneRules rules = z.getRules();
boolean isDst = rules.isDaylightSavings( zdtStartOfDay.toInstant() );

Pass date-time objects rather than mere strings传递日期时间对象而不仅仅是字符串

public static Instant getStartOfTheDayDateTime(Instant instant, String zoneId)

I suggest you ask the calling programmer to pass a valid ZoneId object rather than a mere string.我建议你让调用程序员传递一个有效的ZoneId object 而不是一个字符串。 It should not be the job of this method to validate their string input.这种方法的工作不应该是验证他们的字符串输入。 If it is reasonable to expect a Instant then it is also reasonable to expect a ZoneId .如果期望Instant是合理的,那么期望ZoneId也是合理的。

 public static Instant getStartOfTheDayDateTime(Instant instant, ZoneID zoneId )

Half-Open半开

public static Instant getEndOfTheDayDateTime(Instant instant, String zoneId) {

Trying to determine the last moment of the day is impossible because of infinitely divisible last second.试图确定一天中的最后一刻是不可能的,因为最后一秒是无限可分的。

Also this approach to defining a span of time is awkward.这种定义时间跨度的方法也很尴尬。 It makes abutting multiple spans tricky.这使得邻接多个跨度变得棘手。 Various software systems and protocols differ in their resolution of that last fractional second, using milliseconds, microseconds, nanoseconds, or some other fraction.各种软件系统和协议在最后一个小数秒的分辨率上有所不同,使用毫秒、微秒、纳秒或其他分数。

The common practice in date-time handling is to track a span of time using the Half-Open approach.日期时间处理的常见做法是使用半开方法跟踪时间跨度。 In Half-Open, the beginning is inclusive while the ending is exclusive .在 Half-Open 中,开始是包容的,而结束是排斥的。

So a full day begins with the first moment of the day and runs up to, but does not include, the first moment of the next day.因此,一整天从一天的第一刻开始,一直持续到但不包括第二天的第一刻。

ZoneId z = ZoneId.of( "Europe/Paris" );
ZonedDateTime zdtStartOfDay = instant.atZone( z ).toLocalDate().atStartOfDay( z ) ; 
ZonedDateTime zdtStartOfNextDay = instant.atZone( z ).toLocalDate().plusDays( 1 ).atStartOfDay( z ) ;

You might want to break that code out to more lines, for easier 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 ) ;

See this code run live at IdeOne.com .请参阅在 IdeOne.com 上实时运行的代码 For example:例如:

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-Extra Interval三十-额外Interval

If you do this kind of work with spans of time often, then I suggest adding the ThreeTen-Extra library to your project.如果您经常在一段时间内进行此类工作,那么我建议将ThreeTen-Extra库添加到您的项目中。 That library includes the Interval class to track a span-of-time as aa pair of Instant objects.该库包括Interval class 以跟踪时间跨度作为一对Instant对象。

Interval interval = Interval.of( zdtStartOfDay.toInstant() , zdtStartOfNextDay.toInstant() ) ;

You can then make use the several handy comparison methods such as abuts , contains , encloses , intersection , overlaps , and union .然后,您可以使用几种方便的比较方法,例如abutscontainsenclosesintersectionoverlapsunion

Timestamp

Never use the java.sql.Timestamp class.切勿使用java.sql.Timestamp class。 This class is part of the terrible date-time classes that shipped with the earliest versions of Java.这个 class 是最早版本的 Java 附带的可怕日期时间类的一部分。 These classes are now legacy, supplanted entirely by the modern java.time classes defined in JSR 310 and built into Java 8 and later.这些类现在是遗留的,完全被 JSR 310 中定义的现代java.time类所取代,并内置在 Java 8 及更高版本中。

As of JDBC 4.2 we can exchange java.time objects with a database.从 JDBC 4.2 开始,我们可以将java.time对象与数据库交换。 Use getObject and setObject and updateObject .使用getObjectsetObjectupdateObject

The JDBC spec oddly requires support for OffsetDateTime but not the more commonly used Instant and ZonedDateTime . JDBC 规范奇怪地需要支持OffsetDateTime但不是更常用的InstantZonedDateTime Your particular driver may support these other types.您的特定驱动程序可能支持这些其他类型。 If not, convert.如果没有,请转换。

Retrieval from database.从数据库中检索。

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

Sending to the database.发送到数据库。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM