获得时间范围在午夜和当前时间JDK 8之间 [英] Getting time range between midnight and current time JDK 8

查看:991
本文介绍了获得时间范围在午夜和当前时间JDK 8之间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个方法来计算midnigt和当前时间的长值:

  / ** 
*返回午夜和当前时间之间的时间范围,以毫秒为单位。
*
* @param zoneId时区ID。
* @return {@code long}数组,其中索引:0 - 午夜时间; 1 - 当前时间。
* /

public static long [] todayDateRange(ZoneId zoneId){
long [] toReturn = new long [2];

LocalTime midnight = LocalTime.MIDNIGHT;
LocalDate today = LocalDate.now(zoneId);
LocalDateTime todayMidnight = LocalDateTime.of(今天,午夜);
ZonedDateTime todayMidnightZdt = todayMidnight.atZone(zoneId);
toReturn [0] = todayMidnightZdt.toInstant()。toEpochMilli();

ZonedDateTime nowZdt = LocalDateTime.now()。atZone(zoneId);
toReturn [1] = nowZdt.toInstant()。toEpochMilli();
返回返回;
}

也许有更简单的方法可以做到这一点?

解决方案

你也可以这样做:

  ZonedDateTime nowZdt = ZonedDateTime.now(zoneId); 

ZonedDateTime todayAtMidnightZdt = nowZdt.with(LocalTime.MIDNIGHT);

我想不出更简单的方法。






LocalDateTime vs ZonedDateTime



LocalDateTime之间存在(棘手的)差异.now()。atZone(zoneId) ZonedDateTime.now(zoneId)



对于下面的代码,我使用的是默认时区 America / Sao_Paulo 的JVM,并将尝试获取当前日期时间在另一个时区(欧洲/伦敦)。目前我运行此代码的时间是2017年8月20日 th ,但在圣保罗时间 17:56 ,伦敦时间 21:56



当我这样做时:

  LocalDateTime nowLdt = LocalDateTime 。现在(); 

它使用当前日期创建 LocalDateTime 和时间在JVM的默认时区。在这种情况下,它将获得圣保罗时区的当前日期和时间(2017年8月20日 th 17:56 ):


2017-08-20T 17:56 :05.159


当我调用 atZone 方法时,它会创建一个与对应的 ZonedDateTime 指定区域中的日期和时间:

  ZoneId zoneId = ZoneId.of(Europe / London) ; 
ZonedDateTime nowAtZone = nowLdt.atZone(zoneId);

nowAtZone 变量将是:


2017-08-20T 17:56 :05.159 + 01:00 [欧洲/伦敦]


相同的日期(2017年8月20日 th )和时间(17:56)在伦敦时区。请注意,伦敦的当前日期/时间。如果我得到等效的epochMilli:

  System.out.println(nowAtZone.toInstant()。toEpochMilli()); 

它将是:


1503248165159


现在,如果我不使用 LocalDateTime 和direclty改为使用 ZonedDateTime

  ZonedDateTime nowZdt = ZonedDateTime 。现在(了zoneid); 

它将获得伦敦的当前日期和时间,即:


2017-08-20T 21:56 :05.170 + 01:00 [欧洲/伦敦]


请注意时间已更改( 21:56 )。那是因为现在,在这一刻,这是伦敦的当前时间。如果我得到了epochMilli值:

  System.out.println(nowZdt.toInstant()。toEpochMilli()); 

价值将是:


1503262565170


请注意,它与使用 LocalDateTime (即使您忽略毫秒值的差异,因为小时不同)。如果您希望在指定时区显示当前日期和时间,则必须使用 ZonedDateTime.now(zoneId)



使用 LocalDateTime.now()。atZone()不仅会给出不同的结果,但如果您在不同的JVM中运行,或者JVM默认时区更改,它也会更改(有人可能会错误配置它,或者在同一个VM中运行的另一个应用程序调用 TimeZone.setDefault())。






夏令时



只需提醒由于DST(夏令时)问题导致的拐角情况。我将使用我居住的时区作为示例( America / Sao_Paulo )。



在圣保罗, DST于2016年10月16日 th 开始:在午夜,时钟从午夜向凌晨1点移动1小时前进(偏移量从 -03变化: 00 -02:00 )。因此,在这个时区中,00:00到00:59之间的所有当地时间都不存在(你也可以认为时钟从23:59:59.999999999直接变为01:00)。如果我在此时间间隔内创建了本地日期,则会将其调整为下一个有效时间:

  ZoneId zone = ZoneId.of(美国/圣保罗); 

// 2016年10月16日午夜,DST在圣保罗开始
LocalDateTime d = LocalDateTime.of(2016,10,16,0,0,0,0);
ZonedDateTime z = d.atZone(zone);
System.out.println(z); //调整为2017-10-15T01:00-02:00 [America / Sao_Paulo]

当DST结束时:2017年2月19日 th 午夜,时钟从<午夜到晚上23点从返回 1小时 18 th (偏移量从 -02:00 变为 -03:00 )。因此,从23:00到23:59的所有当地时间都存在两次(在两个偏移中: -03:00 -02:00 ),你必须决定你想要哪一个。
默认情况下,它使用DST结束前的偏移量,但您可以使用 withLaterOffsetAtOverlap()方法获取DST结束后的偏移量:

  // 2017年2月19日午夜,DST在圣保罗结束
//当地时间23:00至23:59 18存在两次
LocalDateTime d = LocalDateTime.of(2017,2,18,23,0,0,0);
//默认情况下,它在DST结束前得到偏移量
ZonedDateTime beforeDST = d.atZone(zone);
System.out.println(beforeDST); //在夏令时结束之前:2018-02-17T23:00-02:00 [America / Sao_Paulo]

//获取DST结束后的偏移量
ZonedDateTime afterDST = beforeDST.withLaterOffsetAtOverlap() ;
System.out.println(afterDST); // DST结束后:2018-02-17T23:00-03:00 [America / Sao_Paulo]

请注意,DST结束前后的日期有不同的偏移量( -02:00 -03:00 ) 。这会影响epochMilli的值。



如果使用使用方法调整时间,也会发生上述情况。 / p>

I have this method to calculate midnigt and current time as long values:

/**
 * Returns the time range between the midnight and current time in milliseconds.
 *
 * @param zoneId time zone ID.
 * @return a {@code long} array, where at index: 0 - midnight time; 1 - current time.
 */

public static long[] todayDateRange(ZoneId zoneId) {
    long[] toReturn = new long[2];

    LocalTime midnight = LocalTime.MIDNIGHT;
    LocalDate today = LocalDate.now(zoneId);
    LocalDateTime todayMidnight = LocalDateTime.of(today, midnight);
    ZonedDateTime todayMidnightZdt = todayMidnight.atZone(zoneId);
    toReturn[0] = todayMidnightZdt.toInstant().toEpochMilli();

    ZonedDateTime nowZdt = LocalDateTime.now().atZone(zoneId);
    toReturn[1] = nowZdt.toInstant().toEpochMilli();
    return toReturn;
}

Perhaps there is the simpler way to do that?

解决方案

You could also do:

ZonedDateTime nowZdt = ZonedDateTime.now(zoneId);

ZonedDateTime todayAtMidnightZdt = nowZdt.with(LocalTime.MIDNIGHT);

I can't think of a simpler way to do it.


LocalDateTime vs ZonedDateTime

There's a (tricky) difference between LocalDateTime.now().atZone(zoneId) and ZonedDateTime.now(zoneId).

For the code below, I'm using a JVM in which the default timezone is America/Sao_Paulo and will try to get the current date and time in another timezone (Europe/London). At the moment I run this code, it's August 20th 2017, but in São Paulo the time is 17:56 and in London is 21:56.

When I do:

LocalDateTime nowLdt = LocalDateTime.now();

It creates a LocalDateTime with the current date and time in the JVM's default timezone. In this case, it'll get the current date and time in São Paulo's timezone (which is August 20th 2017, at 17:56):

2017-08-20T17:56:05.159

When I call the atZone method, it creates a ZonedDateTime that corresponds to this date and time in the specified zone:

ZoneId zoneId = ZoneId.of("Europe/London");
ZonedDateTime nowAtZone = nowLdt.atZone(zoneId);

The nowAtZone variable will be:

2017-08-20T17:56:05.159+01:00[Europe/London]

The same date (August 20th 2017) and time (17:56) in London timezone. Note that it's not the current date/time in London. If I get the equivalent epochMilli:

System.out.println(nowAtZone.toInstant().toEpochMilli());

It will be:

1503248165159

Now, if I don't use the LocalDateTime and direclty use the ZonedDateTime instead:

ZonedDateTime nowZdt = ZonedDateTime.now(zoneId);

It will get the current date and time in London, which will be:

2017-08-20T21:56:05.170+01:00[Europe/London]

Note that the time changed (it's 21:56). That's because right now, at this moment, that's the current time in London. If I get the epochMilli value:

System.out.println(nowZdt.toInstant().toEpochMilli());

The value will be:

1503262565170

Note that it's different from the first case using LocalDateTime (even if you ignore the difference in the milliseconds value, because the hour is different). If you want the current date and time at the specified timezone, you must use ZonedDateTime.now(zoneId).

Using LocalDateTime.now().atZone() not only gives a different result, but it will also change if you run in different JVM's, or if the JVM default timezone changes (someone might misconfigure it, or another application running in the same VM calls TimeZone.setDefault()).


Daylight Saving Time

Just remind about corner cases due to DST (Daylight Saving Time) issues. I'm gonna use the timezone I live in as example (America/Sao_Paulo).

In São Paulo, DST started at October 16th 2016: at midnight, clocks shifted 1 hour forward from midnight to 1 AM (and the offset changes from -03:00 to -02:00). So all local times between 00:00 and 00:59 didn't exist in this timezone (you can also think that clocks changed from 23:59:59.999999999 directly to 01:00). If I create a local date in this interval, it's adjusted to the next valid moment:

ZoneId zone = ZoneId.of("America/Sao_Paulo");

// October 16th 2016 at midnight, DST started in Sao Paulo
LocalDateTime d = LocalDateTime.of(2016, 10, 16, 0, 0, 0, 0);
ZonedDateTime z = d.atZone(zone);
System.out.println(z);// adjusted to 2017-10-15T01:00-02:00[America/Sao_Paulo]

When DST ends: in February 19th 2017 at midnight, clocks shifted back 1 hour, from midnight to 23 PM of 18th (and the offset changes from -02:00 to -03:00). So all local times from 23:00 to 23:59 existed twice (in both offsets: -03:00 and -02:00), and you must decide which one you want. By default, it uses the offset before DST ends, but you can use the withLaterOffsetAtOverlap() method to get the offset after DST ends:

// February 19th 2017 at midnight, DST ends in Sao Paulo
// local times from 23:00 to 23:59 at 18th exist twice
LocalDateTime d = LocalDateTime.of(2017, 2, 18, 23, 0, 0, 0);
// by default, it gets the offset before DST ends
ZonedDateTime beforeDST = d.atZone(zone);
System.out.println(beforeDST); // before DST end: 2018-02-17T23:00-02:00[America/Sao_Paulo]

// get the offset after DST ends
ZonedDateTime afterDST = beforeDST.withLaterOffsetAtOverlap();
System.out.println(afterDST); // after DST end: 2018-02-17T23:00-03:00[America/Sao_Paulo]

Note that the dates before and after DST ends have different offsets (-02:00 and -03:00). This affects the value of epochMilli.

The above can also happen if you adjust the time using with method.

这篇关于获得时间范围在午夜和当前时间JDK 8之间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆