简体   繁体   English

Joda Time to Java Time Migration 在迁移时显示不同的结果

[英]Joda Time to Java Time Migration show different result while migration

Given the following code鉴于以下代码

public static void main(String[] args) {
     org.joda.time.format.DateTimeFormatter _timestampFomatNYCJoda = org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd HHmmss.SSS").withZone(DateTimeZone.forID("America/New_York"));
     DateTimeFormatter _timestampFomatNYC = DateTimeFormatter.ofPattern("yyyyMMdd HHmmss.SSS").withZone(ZoneId.of("America/New_York"));
     LocalDateTime localDateTime = LocalDateTime.now();
     org.joda.time.LocalDateTime jodaLocalDateTime = new org.joda.time.LocalDateTime();
     System.out.println("System Time " + new Date());
     System.out.println("Java Version " +  localDateTime.format(_timestampFomatNYC));
     System.out.println("Joda Version " +  _timestampFomatNYCJoda.print(jodaLocalDateTime.toDateTime(DateTimeZone.UTC)));
} 

Why does the Java Version and Joda Version dont match ?为什么 Java 版本和 Joda 版本不匹配? I am running this on IST clock.我在 IST 时钟上运行它。

Below is the output下面是输出

System Time Fri Mar 27 17:01:33 IST 2020
Java Version 20200327 170133.933
Joda Version 20200327 130133.938

I can reproduce your results.我可以重现你的结果。 I can also explain them.我也可以解释它们。 Joda-Time and java.time have been designed to behave differently in this case.在这种情况下,Joda-Time 和 java.time 的行为方式有所不同。 Let's look at them in turn.让我们依次看看它们。

Joda-Time乔达时间

In Joda-Time DateTimeFormatter.withZone() gives you a formatter with an override zone , that is, a zone that will always be used for formatting dates and times.在 Joda-Time DateTimeFormatter.withZone()为您提供了一个带有覆盖 zone的格式化程序,即一个始终用于格式化日期和时间的区域。 In other words, any date and time will be converted to this zone for printing.换句话说,任何日期和时间都将转换到该区域进行打印。 The documentation says:文档说:

When printing, this zone will be used in preference to the zone from the datetime that would otherwise be used.打印时,此区域将优先于日期时间中的区域使用,否则将使用该区域。

When you do new org.joda.time.LocalDateTime() , you are getting a LocalDateTime representing the current date and time in your default time zone.当您执行new org.joda.time.LocalDateTime() ,您将获得一个LocalDateTime表示默认时区中的当前日期和时间。 The Local in some class names means without time zone or offset from UTC .某些类名中的Local表示没有时区或与 UTC 的偏移量 I figure that you must have got a value equal to 2020-03-27T17:01:33.938 .我认为您的值必须等于2020-03-27T17:01:33.938

Apparently what happens when you format a LocalDateTime with a formatter with an override zone, is that the formatter assumes that your LocalDateTime is in UTC (which yours isn't) and converts it from there, in your case to America/New_York time zone.显然,当您使用带有覆盖区域的格式化程序格式化LocalDateTime时会发生什么,格式化程序假定您的LocalDateTime是 UTC(您的不是)并将其从那里转换,在您的情况下为 America/New_York 时区。 Since summer time (DST) is in effect in New York, the offset is -04:00, so 17:01 becomes 13:01.由于夏令时 (DST) 在纽约生效,偏移量为 -04:00,因此 17:01 变为 13:01。

This is the wrong result.这是错误的结果。 When the time is 17:01 in your time zone, it is not 17:01 UTC, so the conversion is based on a false premise.当时间是您所在时区的 17:01 时,它不是 17:01 UTC,因此转换是基于错误的前提。 It is also not 13:01 in New York, so the converted result is telling a lie.纽约也不是 13:01,因此转换后的结果是在撒谎。

java.time时间

With java.time setting an override zone on a formatter works similarly for formatting, but with a difference that matters here: the override zone is only used when printing a date-time object that identifies an instant (a point in time).使用 java.time 在格式化程序上设置覆盖区域的工作方式与格式化类似,但这里有一个重要区别:覆盖区域仅在打印标识瞬间(时间点)的日期时间对象时使用。 From the docs:从文档:

When formatting, if the temporal object contains an instant, then it will be converted to a zoned date-time using the override zone.格式化时,如果时间对象包含一个瞬间,则将使用覆盖区域将其转换为分区日期时间。 Whether the temporal is an instant is determined by querying the INSTANT_SECONDS field.时间是否为瞬间通过查询INSTANT_SECONDS字段来确定。 If the input has a chronology then it will be retained unless overridden.如果输入有一个年表,那么它将被保留,除非被覆盖。 If the input does not have a chronology, such as Instant, then the ISO chronology will be used.如果输入没有年表,例如 Instant,则将使用 ISO 年表。

… In all other cases, the override zone is added to the temporal, replacing any previous zone, but without changing the date/time. ... 在所有其他情况下,覆盖区域被添加到临时区域,替换任何先前的区域,但不更改日期/时间。

Again LocalDateTime.now() gives you the current date and time of day (a few milliseconds earlier than the query through Joda-Time), 2020-03-27T17:01:33.933 . LocalDateTime.now()再次为您提供当前日期和时间(比通过 Joda-Time 查询早几毫秒), 2020-03-27T17:01:33.933 Local still means without offset or time zone. Local仍然意味着没有偏移或时区。

Because your LocalDateTIme hasn't got offset or time zone, it cannot identify an unambigous point in time, an instant.因为您的LocalDateTIme没有偏移量或时区,所以它无法识别一个明确的时间点,即瞬间。 Therefore when formatting it neither the date nor the time of day is changed.因此,在格式化它时,日期和时间都不会改变。 And since your format pattern contains no time zone or offset, none is printed.由于您的格式模式不包含时区或偏移量,因此不会打印任何内容。 So you just get the date and time in your time zone (not in New York), 20200327 170133.933 .因此,您只需获取您所在时区(而非纽约)的日期和时间,即20200327 170133.933

To get the date and time in New York time zone获取纽约时区的日期和时间

    DateTimeFormatter timestampFormat
            = DateTimeFormatter.ofPattern("yyyyMMdd HHmmss.SSS");
    ZonedDateTime timeInNy = ZonedDateTime.now(ZoneId.of("America/New_York"));
    System.out.println(timeInNy.format(timestampFormat));

When I ran this code just now, the output was:当我刚刚运行这段代码时,输​​出是:

20200327 122359.683 20200327 122359.683

Documentation links文档链接

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

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