当前位置: 首页 > 知识库问答 >
问题:

与Java时间解析的混淆

邵华皓
2023-03-14

我对java时间中的时间处理感到困惑。长期以来,我一直在这样一种假设下工作,即如果将时间戳指定为祖鲁时间,java将处理与本地时间相关的偏移量。

来说明。我目前在BST,它有UTC 1的偏移量。考虑到这一点,我希望这个祖鲁语时间:

2016-09-12T13:15:17.309Z

成为

2016-09-12T14:15:17.309 

解析后的LocalDateTime。这是因为我的默认systemtime设置为BST,并且上面的时间戳(zulu time)指定它是UTC时间。

然而,请考虑这个样本:

        String ts = "2016-09-12T13:15:17.309Z";
        LocalDateTime parse = LocalDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println(parse);

这将打印:

2016-09-12T13:15:17.309

因此,被解析为LocalDateTime的时间戳不会被识别为UTC时间,而是直接被视为localtime。所以我想,也许我需要将其解析为ZonedDateTime,并将其转换为LocalDateTime,以便获得正确的本地时间。通过这个测试:

        String ts = "2016-09-12T13:15:17.309Z";
        ZonedDateTime parse = ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME);
        System.out.println(parse);
        System.out.println(parse.toLocalDateTime());

我得到的结果是:

2016-09-12T13:15:17.309Z
2016-09-12T13:15:17.309

两个日期的输出相同。

我能找到的正确解析这个的唯一方法是:

    String ts = "2016-09-12T13:15:17.309Z";
    Instant instant = Instant.parse(ts); // parses UTC
    LocalDateTime ofInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    System.out.println(instant);
    System.out.println(ofInstant);

这张照片是:

2016-09-12T13:15:17.309Z
2016-09-12T14:15:17.309

这是正确的。

因此,问题是:

  • java time不应该识别UTC时间戳并将其解析为正确的系统默认值吗?
  • 如何使用LocalDateTime#parse方法来获得正确的结果?
  • 我现在应该对所有内容使用Instant并放弃解析吗?

问题是jersey/jackson的java时间模块使用ISO格式和常规的LocalDateTime#parse方法解析时间戳。我意识到我的时间没有关闭,因为它们被视为LocalTime,而事实上它们是在祖鲁语时间。

共有2个答案

许远航
2023-03-14
  • 不要使用LocalDateTime.
  • 使用即时

示例:

Instant.parse( "2016-09-12T13:15:17.309Z" )
       .atZone( ZoneId.of( "Europe/London" ) )
       .toString();

2016-09-12T14:15:17.309 01:00[欧洲/伦敦]

在IdeOne中运行。通用域名格式。

克鲁斯克的答案是正确的。您误解了LocalDateTime类的含义。它不代表特定地点的日期时间。恰恰相反,它根本不代表一个实际的时刻。

我建议将Instant作为java中的基本构建块类。时间Instant类以UTC表示时间线上的一个时刻,分辨率为纳秒(最多九(9)位小数)。

输入字符串符合Instant类中默认使用的ISO 8601格式,用于解析和生成字符串表示。结尾的ZZulu的缩写,表示UTC。无需指定格式模式。

Instant instant = Instant.parse( "2016-09-12T13:15:17.309Z" );

作为一名程序员,你应该学会在UTC中思考和工作。忘记你自己的时区。把UTC看作一个真正的时间。仅在需要时应用时区作为变体。

指定一个适当的时区名称,格式为大陆/地区,例如美国/蒙特利尔非洲/卡萨布兰卡,或太平洋/奥克兰。永远不要使用3-4个字母的缩写,如BSTESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。如果BST的意思是英国夏季时间,那么实际的时区名称将是Europe/London。java.time类将决定如何调整任何异常,包括夏令时(DST)。

ZoneId z = ZoneId.of( "Europe/London" );
ZonedDateTime zdt = instant.atZone( z );

爪哇。时间框架内置于Java8及更高版本中。这些类取代了麻烦的旧遗留日期时间类,比如java。util。日期日历

Joda Time项目目前处于维护模式,建议迁移到java。时间

要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR 310。

在哪里获得java.time类?

  • Java SE 8和SE 9及更高版本
  • 许多java.time功能被反向移植到Java6
  • ThreeTenABP项目专门为Android改编了ThreeTen Backport(如上所述)

额外的Three Ten项目扩展了java。有额外课程的时间。这个项目是java未来可能增加的一个试验场。时间您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter,等等。

凌琦
2023-03-14

您误解了LocalDateTime的目的。

引用类留档:

ISO-8601日历系统中没有时区的日期时间,例如{@code 2007-12-03T10:15:30}。

...

此类不存储或表示时区。相反,它是对日期的描述,用于生日,与挂钟上显示的当地时间相结合。如果没有偏移量或时区等附加信息,它不能表示时间线上的某个瞬间。

所以它的明确目的只是表示一个没有时区的日期和时间。这不是为了表示当地时区中的日期和时间。

因此,每次转换只会剥离时区。

因此,出于您的目的,您需要一个带有ZoneId.systemDefault()的ZonedDateTime,正如您在第三个示例中已经使用的那样。

第二个例子是:

String ts = "2016-09-12T13:15:17.309Z";
ZonedDateTime parse = 
    ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME)
        .withZoneSameInstant(ZoneId.systemDefault());
System.out.println(parse);
System.out.println(parse.toLocalDateTime());
 类似资料:
  • 本文向大家介绍Java日期与时间类原理解析,包括了Java日期与时间类原理解析的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了Java日期与时间类原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 基础知识 日期: 类似于 2018-12-12 时间: 类似于 2018-12-12 12:12:12 时刻: 类似于 2018-12

  • 我希望能够解析一段时间(天、小时、分钟)可选字符串,以便输入如下:

  • 这是我的用户类,我要在我的数据库中保存符合ISO的日期时间。 这是我的球衣控制器: 我如何使用像泽西岛这样的日期时间格式?是否可以发送一个datatime并自动创建Java8日期时间对象?

  • 我有一个带有数据和时间戳的记录日志,我的Flink应用程序按时间戳升序接收记录。在某个键的第一个项到达窗口后,我想在X事件时间后关闭窗口,检查是否有足够的项到达某个条件,并为该键发出通过或失败消息。 对于Flink中的基本窗口功能,这是不可能的吗?例如,如果我希望我的窗口有30秒长,但是键的第一个项在15秒到达,最后一个项在40秒到达,似乎窗口将在30秒关闭,并且该键的记录轨迹将是分成两个窗口。在

  • 问题内容: 在Go中,尝试使用时间包的Parse方法将字符串转换为时,不会返回预期结果。似乎时区有问题。我想将UTC中的日期和时间更改为ISO 8601。 提前致谢! 问题答案: 使用特殊值进行时间格式化,并期望格式与这些值一起传递。 如果您传递正确的值,它将以正确的方式解析时间。 因此,过去的年份为2006年,月份为01年,然后继续这样…

  • 但这就是我卡住的地方..我不确定这个错误到底是什么意思,但它肯定与输入字符串的AM/PM部分有关。我也尝试搜索类似的错误,但我没有找到任何东西。我有一种感觉,我可能在定义格式化程序模式时犯了一个简单的错误,但我卡住了。任何帮助都将不胜感激!