LocalDate and LocalDateTime in a server which runs in EST vs UTC

huangapple go评论90阅读模式
英文:

LocalDate and LocalDateTime in a server which runs in EST vs UTC

问题

我正试图理解LocalDate和LocalDateTime。由于它们不包含时区信息,那么在两个不同的时区中,对于now()方法是如何工作的呢?

示例:

服务器1(美东时区):

LocalDateTime.now() -> 2020-04-06T23:00:00.040
LocalDate.now(). -> 2020-04-06

服务器2(UTC时区):

LocalDateTime.now() -> 将会是什么值?
LocalDate.now(). -> 将会是什么值?(注意在美东时区执行时是晚上11点)

另外,
如果我将下面的日期字符串转换为LocalDateTime,然后再转换为LocalDate,结果会是什么?

2020-04-06T23:00:00.000

英文:

I am trying to understand LocalDate and LocalDateTime. Since they do not carry zone info, how does it work for now() on two different time zone.

Example:

Server 1(EST time zone):

LocalDateTime.now() -> 2020-04-06T23:00:00.040
LocalDate.now(). -> 2020-04-06

Server 2(UTC time zone):

LocalDateTime.now() -> What would be the value?
LocalDate.now(). -> What would be the value? (Note in EST, time it executed was 11 PM)

Also,
If I convert below date string to LocalDateTime and then toLocalDate, what would be the outcome?

2020-04-06T23:00:00.000

答案1

得分: 8

# 时间偏移随时间变化

2020年4月6日,北美东部的大多数时区,如 `America/Montreal` 和 `America/New_York`,与UTC相差4小时。

因此,在这些时区,2020年4月6日晚上11点同时相当于UTC时间的第二天凌晨3点。将2020-04-06T23:00增加4小时,得到2020-04-07T03:00。增加4小时将我们从 `America/Port-au-Prince` 和 `America/Nassau` 使用的壁钟时间转换到UTC时间。

上述时区在一年中仅有半年使用UTC时间差4小时。这些地区的政府决定大约一半的时间遵循夏时制(DST)。因此,一年中的一半时间他们将时钟拨快一小时,UTC偏移为-04:00;而在年底的时候,他们会将时钟拨回一小时,UTC偏移为-05:00。例如,一年的早些时候,`America/New_York` 的晚上11点会对应UTC时间的04:00,而不是四月份所见的03:00。

一月的标准时间比UTC时间晚*五*小时。因此,晚上11点再加五个小时,就是次日凌晨4点。

    ZoneId z = ZoneId.of("America/New_York");
    ZonedDateTime zdt = ZonedDateTime.of(2020, 1, 6, 23, 0, 0, 0, zNewYork);
    Instant instant = zdt.toInstant();  // 2020-01-07T04:00Z

四月的夏时制时间比UTC时间晚*四*小时。因此,晚上11点再加四个小时,就是次日凌晨3点。

    ZoneId z = ZoneId.of("America/New_York");
    ZonedDateTime zdt = ZonedDateTime.of(2020, 4, 6, 23, 0, 0, 0, zNewYork);
    Instant instant = zdt.toInstant();  // 2020-04-07T03:00Z

顺便说一句,夏时制仅仅是政府改变其辖区时区偏移的众多原因之一。世界各地的政治家经常会意外地改变时区偏移。你的编程应始终预期时区会改变其偏移。仅因为你关注的特定区域当前不观察夏时制,并不意味着偏移永远不会改变。

至于将 `2020-04-06T23:00:00.000` 解析为 `LocalDateTime`,你将得到 `2020-04-06T23:00:00.000`。忽略时区是 `LocalDateTime` 的主要特点。因此不会进行任何调整。

[![Java中不同日期时间类型的表格,包括现代和传统类型][1]][1]

你可能认为 `LocalDateTime` 表示特定的地点。但实际上它代表*任何*地点或*所有*地点,而不是特定的一个地点。对于特定地点,请使用 `ZonedDateTime`。

# 伪时区

另一个要注意的地方是,`EST` 不是一个时区。这种由2-4个字母组成的代码不是真正的时区,没有标准化,并且甚至不是唯一的。例如,按 `EST`,你是指 *澳大利亚东部标准时间* 还是 *北美东部标准时间*?`CST` 是指 *中部标准时间* 还是 *中国标准时间*?在处理日期时间时,避免使用这些伪时区。

而且你在代码中使用了错误的伪代码。在2020年4月6日,大多数东海岸时区都在观察夏时制(DST)。因此,它们应被视为“EDT”,而不是“EST”。通过指定真正的时区名称来避免问题。

真正的时区使用 `Continent/Region` 格式进行命名。参见 [维基百科][2] 上的真正时区列表。

# 永远不要调用 `LocalDateTime.now`

我无法想象何时调用 `LocalDateTime.now` 会是正确的做法。确定当前时刻需要一个时区(或偏移量)。而 `LocalDateTime` 的定义中没有包含时区或偏移量。当程序员调用 `LocalDateTime.now` 时,可以肯定他们并不完全理解必要的概念。

当你调用 `LocalDateTime.now` 时,JVM 的当前默认时区隐式用于捕获当前时间,正如人们在该区域中所见。然后该时区的信息被删除。

这:

    LocalDateTime.now()

…与此相同:

    LocalDateDate.now(ZoneId.systemDefault())

…这与获取在特定时区中所见的当前时刻,然后删除时区信息相同:

    ZonedDateTime.now(ZoneId.systemDefault()).toLocalDateTime()

有关展示 `LocalDateTime.now` 的更多代码示例,请参见 [Ole V.V. 的正确答案][3]。

# 何时使用 `LocalDateTime`

如果 `LocalDateTime` 不适用于获取当前时刻,并且不适用于跟踪任何时刻,那么这个类的适用范围是什么?有三种情况:表示任何地点,表示所有地点,以及预约未来。

- 表示任何地点可以是指定圣诞节开始的时间。今年圣诞节在世界各地的时间都是2020-12-25T00:00。当然,这意味着圣诞节首先在基里巴斯的午夜后开始

<details>
<summary>英文:</summary>

# Offsets vary over time

On April 6, 2020, most time zones on the east coast of North America such as `America/Montreal` and `America/New_York` use an offset of four hours behind UTC. 

So, in those zones 11 PM on 2020-04-06 is simultaneously 3 AM on the 7th in UTC. Add four hours to 2020-04-06T23:00 to get 2020-04-07T03:00. Adding four hours brings us from the wall-clock time used in `America/Port-au-Prince` and `America/Nassau` to UTC. 

The offset used by the time zones mentioned above are four hours behind UTC only half the year. The politicians in those locations have decided to observe Daylight Saving Time (DST) for about half the year. So half the year they jump their clocks ahead an hour for an offset-from-UTC of -04:00, and later in the year they fall back an hour for an offset-from-UTC of -05:00. For example, earlier in the year 11 PM in `America/New_York` would be 04:00 in UTC rather than the 03:00 time seen in April.



Standard time, in January, is *five* hours behind UTC. So, 11 PM plus five hours is 4 AM next day.

    ZoneId z = ZoneId.of( &quot;America/New_York&quot; ) ;
    ZonedDateTime zdt = ZonedDateTime.of( 2020 , 1 , 6 , 23 , 0 , 0 , 0 , zNewYork ) ; 
    Instant instant = zdt.toInstant() ;  // 2020-01-07T04:00Z

Daylight Saving Time, in April, is *four* hours behind UTC. So, 11 PM plus four hours is 3 AM next day.

    ZoneId z = ZoneId.of( &quot;America/New_York&quot; ) ;
    ZonedDateTime zdt = ZonedDateTime.of( 2020 , 4 , 6 , 23 , 0 , 0 , 0 , zNewYork ) ; 
    Instant instant = zdt.toInstant() ;  // 2020-04-07T03:00Z

By the way, DST is only one of many reasons politicians have for changing the offset used by the time zone(s) of their jurisdiction. Politicians around the world have shown a penchant for changing their offsets surprisingly often. Your programming should always expect a time zone to change its offset. Just because your particular zone of concern does not currently observe DST does *not* mean the offset will never change.


As for parsing `2020-04-06T23:00:00.000` as a `LocalDateTime`, you will get `2020-04-06T23:00:00.000`. Ignoring time zones is the entire point of `LocalDateTime`. So no adjustments are made.

[![Table of date-time types in Java, both modern and legacy][1]][1]

You may be thinking of `LocalDateTime` as representing a particular locality. But, no, it represents *any* locality or *all* localities. But never any one particular locality. For a particular locality, use `ZonedDateTime`. 

# Pseudo time zones

Another point: `EST` is *not* a time zone. Such 2-4 letter letter codes are not real time zones, are not standardized, and are not even unique. For example, by `EST`, did you mean *Australian Eastern Standard Time* or *North American Eastern Standard Time*? Is `CST` *Central Standard Time* or *China Standard Time*? Avoid these pseudo-zones in your date-time-handling. 

And you happened to use the wrong pseudo-code. On April 6 2020, most of those east coast time zones are observing Daylight Saving Time (DST). So they would be considered to be in “EDT” rather than “EST”. Avoid the problem by specifying the real time zone name.

Real time zones are named using `Continent/Region` format. See [Wikipedia][2] for a list of real time zones.

# Never call `LocalDateTime.now`

I cannot imagine a case where calling `LocalDateTime.now` would be the right thing to do. Determining the current moment requires a time zone (or offset). And `LocalDateTime` by definition has no time zone or offset. When a programmer writes `LocalDateTime.now`, you can bet they do not fully understand the necessary concepts.

When you call `LocalDateTime.now`, the JVM’s current default time zone is implicitly used to capture the current time as seen by the people in the region of that zone. And then the fact of that time zone is deleted. 

This:

    LocalDateTime.now() 

…is the same as this:

    LocalDateDate.now( ZoneId.systemDefault() )

…which is the same as getting the current moment as seen in a particular time zone, followed by removing the time zone information:

    ZonedDateTime.now( ZoneId.systemDefault() ).toLocalDateTime()

For more code examples demonstrating `LocalDateTime.now`, see the [correct Answer by Ole V.V.][3]

# Where to use `LocalDateTime`

If `LocalDateTime` is not appropriate for getting the current moment, and is not appropriate for tracking any moment, what is the appropriate use for this class? Three things: representing any locality, representing all localities, and booking future appointments. 

 - Any locality would be something like stating when Christmas starts. This year Christmas starts at 2020-12-25T00:00 wherever you are in the world. Of course this means Christmas starts first in Kiribati after midnight, later in Japan after midnight, even later in Tunisia after midnight, and still later in Chicago after midnight.
 - All localities would be something like stating our company policy that lunch breaks at all our factories in Delhi, D&#252;sseldorf, and Detroit are scheduled for 12:30. So on April 6 2020, the break will be at 2020-04-06T12:30:00. This break will occur first in Delhi, several hours later in D&#252;sseldorf, and even more hours later in Detroit.
 - Booking future appointments where you intend to keep the same time-of-day regardless of changes to the time zone’s offset must recorded without the offset. If your next dental appointments is in six months at 3 PM, we want to record the 3 PM without regard for the offset. If the offset were to be changed by politicians, we still want the appointment to start when the clock strikes three on that date in that zone. 

Set the appointment.

    LocalDateTime appointment = LocalDateTime.of( 2021 , 1 , 23 , 15 , 0 , 0 , 0 ) ;

Determine a moment for producing a calendar. Every time you do this, you may get a different result if the politicians have changed the rules of this time zone.

    ZoneId z = ZoneId.of ( &quot;America/Panama&quot; ) ;
    ZonedDateTime dueToArrive = appointment.atZone( z ) ;

# `LocalDate`

As for `LocalDate`, we saw in the examples above that the date depends on time zone. For any given moment, the date varies around the globe by time zone. It may be “tomorrow” in Tokyo Japan while still “yesterday” in Montr&#233;al Qu&#233;bec Canada. 

So, you must specify a time zone when asking for the current date.

    LocalDate ld = LocalDate.now( ZoneId.of( &quot;Asia/Kolkata&quot; ) ) ;

If you omit the time zone, the JVM’s current default time zone is implicitly applied. So `LocalDate.now()` becomes `LocalDate.now( ZoneId.systemDefault() )`. I recommend specifying your desired/expected zone explicitly, rather than rely on implicit default.

# Server time zone

You said:

&gt;server which runs in EST vs UTC

FYI, servers should generally be set to UTC. Most of your thinking, programming, logging, and so on should be done in UTC. Learn to think of UTC as The One True Time, with all other zones but mere variations.

As a programmer, you should never rely on the default time zone. That is far outside your control. That default can be changed so easily by the user or sysadmin. Furthermore, any code in any thread of any app within the JVM can instantly change the JVM’s current default time with a call to `TimeZone.setDefault`. So even *during* execution of your app, the default can be changed at any moment. 


  [1]: https://i.stack.imgur.com/HNQS7.png
  [2]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
  [3]: https://stackoverflow.com/a/61061492/642706

</details>



# 答案2
**得分**: 5

为了避免混淆,请向`now()`传递明确的时区并自行查看:

```java
ZoneId easternTime = ZoneId.of("America/Montreal");
System.out.println(LocalDateTime.now(easternTime));
System.out.println(LocalDateTime.now(ZoneOffset.UTC));
System.out.println(LocalDate.now(easternTime));
System.out.println(LocalDate.now(ZoneOffset.UTC));

我刚才运行的输出:

2020-04-06T09:56:17.381558
2020-04-06T13:56:17.385215
2020-04-06
2020-04-06

尽管你正确地指出了LocalDateTimeLocalDate不包含任何时区信息,但它们的now方法确实使用时区。可以传递给它们的时区,或者如果使用无参的变体,则使用JVM的默认时区。

你还问道:

另外,如果我将下面的日期字符串转换为LocalDateTime,然后再转换为LocalDate,结果会是什么?
2020-04-06T23:00:00.000

为什么不试试呢?

LocalDateTime ldt = LocalDateTime.parse("2020-04-06T23:00:00.000");
System.out.println(ldt);
LocalDate ld = ldt.toLocalDate();
System.out.println(ld);

输出:

2020-04-06T23:00
2020-04-06

LocalDateTime转换到LocalDate不涉及任何时区(或UTC偏移)。时间部分被简单丢弃,日期部分保持不变。

英文:

To prevent confusion pass explicit time zone to now() and see for yourself:

	ZoneId easternTime = ZoneId.of(&quot;America/Montreal&quot;);
System.out.println(LocalDateTime.now(easternTime));
System.out.println(LocalDateTime.now(ZoneOffset.UTC));
System.out.println(LocalDate.now(easternTime));
System.out.println(LocalDate.now(ZoneOffset.UTC));

Output when I ran just now:

> 2020-04-06T09:56:17.381558
> 2020-04-06T13:56:17.385215
> 2020-04-06
> 2020-04-06

While you are correct that LocalDateTime and LocalDate don’t contain any time zone information, their now methods do use time zones. Either the one passed to them, or if you use the no-arg variant, the default time zone of the JVM.

You also asked:

> Also, If I convert below date string to LocalDateTime and then
> toLocalDate, what would be the outcome?
>
> 2020-04-06T23:00:00.000

Why not try out that too?

	LocalDateTime ldt = LocalDateTime.parse(&quot;2020-04-06T23:00:00.000&quot;);
System.out.println(ldt);
LocalDate ld = ldt.toLocalDate();
System.out.println(ld);

> 2020-04-06T23:00
> 2020-04-06

Converting from LocalDateTime to LocalDate involves no time zone (or UTC offset) whatsoever. The time part is simply discarded and the date part kept unchanged.

huangapple
  • 本文由 发表于 2020年4月6日 21:47:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/61061324.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定