Java 使用带有时区的Joda解析日期

Java 使用带有时区的Joda解析日期,java,datetime,date,timezone,jodatime,Java,Datetime,Date,Timezone,Jodatime,我有两个时间戳,它们以两种不同的格式描述同一时刻 2010-10-0318:58:07和2010-10-03T16:58:07.000+02:00 我使用两个不同的日期格式化程序和Joda Time解析时间戳。最后,我希望有两个DateTime对象,它们在时间的同一瞬间是相等的 DateFormatter提供了几种控制时区和地区的方法,但我无法让它工作 这是我想使用的代码: final String date1 = "2010-10-03 18:58:07"; // Europe/Ber

我有两个时间戳,它们以两种不同的格式描述同一时刻

2010-10-0318:58:07
2010-10-03T16:58:07.000+02:00

我使用两个不同的日期格式化程序和Joda Time解析时间戳。最后,我希望有两个DateTime对象,它们在时间的同一瞬间是相等的

DateFormatter提供了几种控制时区和地区的方法,但我无法让它工作

这是我想使用的代码:

    final String date1 = "2010-10-03 18:58:07"; // Europe/Berlin local time
    final DateTimeFormatter formatter1 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
    final DateTime dateTime1 = formatter1.parseDateTime(date1);

    final String date2 = "2010-10-03T16:58:07.000+02:00"; // Europe/Berlin local time with time zone
    final DateTimeFormatter formatter2 = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    final DateTime dateTime2 = formatter2.parseDateTime(date2);

    Assert.assertTrue(dateTime1.isEqual(dateTime2));

如果您的默认时间僵尸是欧洲/柏林,则2010-10-03 18:58:07对应于2010-10-03T16:58:07.000+00:00


您可能误解了字符串表示法中的时区字段。你的时间戳2010-10-03T16:58:07.000+02:00意味着“它是16:58:07,在一个时区,与格林尼治标准时间的偏移量为+2小时),或者用另一种措辞来说,“现在柏林是16:58:07”。我想你希望它是指格林尼治标准时间16:58:07?

你的两个时间戳在时间上并不代表同一个瞬间(正如jambjo已经说过的那样).见维基百科

另请参阅有关其工作原理的文档。如果您不提供任何时区,则将应用默认时区(如果您在柏林,则为柏林时区UTC+2)。因此:

  • 2010-10-03 18:58:07
    变为
    2010-10-03T18:58:07.000+02:00
    (柏林的18:58与UTC的偏移为2小时,即UTC的16:58)
  • 2010-10-03T16:58:07.000+02:00
    保持原样,因为提供了一个时区(即柏林的16:58与UTC的偏移为2小时,即UTC的14:58)

希望您能理解。您需要使用该方法调整时间以获得所需的结果。

我遇到了与您相同的问题,我发现的最佳方法是解析数据。 我最初的格式是:2018-01-22 09:25:14.000+0000

只需选择列并单击数据选项卡中的“文本到列”

我使用带空格的分隔符在3个不同的列中解析此格式。 所以在最后,我有

Col A 2018-01-22 Col B 09:25:14.000 C+0000列

tl;dr 使用取代Joda time的现代java.time类

真的

细节 这是正确的,因为您误解了和值的含义

现在在2018年,该项目处于维护模式。该项目的主要作者斯蒂芬·科尔伯恩(Stephen Colebourne)继续发现并编写了其实现,即在中发现的类

首次输入

你的输入字符串<代码> 201010-03 18:58:07 几乎是标准格式。要遵守,用“<代码> T < /代码>替换中间的空间。

String input1 = "2010-10-03 18:58:07".replace( " " , "T" ) ;
该字符串缺少时区或UTC偏移量的任何指示符。因此将其解析为
LocalDateTime

LocalDateTime ldt = LocalDateTime.parse( input1 ) ;
此值不代表某个时刻,也不是时间线上的某个点。如果没有区域或偏移的上下文,它可能是全球时区范围内约26-27小时内的任意时刻

在您的评论中,您发现输入字符串显然是用来表示
欧洲/莫斯科
时区中的日期和时间。因此,我们可以指定该区域来确定时间线上的某个时刻和点

ZoneId zMoscow = ZoneId.of( "Europe/Moscow" ) ;
ZonedDateTime zdtMoscow = ldt.atZone( zMoscow ) ;  // Determine a moment by assigning a time zone.
zdtMoscow.toString():2010-10-03T18:58:07+04:00[欧洲/莫斯科]

第二输入 您的第二次输入符合标准格式

此输入与UTC的偏移量比UTC提前两小时。因此,此字符串表示UTC中14:58:07的时间

我们可以解析为一个
OffsetDateTime
,以尊重给定的偏移量

OffsetDateTime odt2 = OffsetDateTime.parse( "2010-10-03T16:58:07.000+02:00" ) ;
odt2.toString():2010-10-03T16:58:07+02:00

比较 这两个输入是否代表同一时刻,时间线上的同一点

比较的一种方法是将两者都调整为UTC。根据定义,
即时
始终为UTC

提示:养成思考、工作、存储、交换和登录UTC的习惯。将UTC视为一个真实的时间

运行时,我们看到的结果末尾有一个
Z
。这意味着UTC,发音为
Zulu
。事实上,我们看到这两个值代表同一时刻,UTC时间几乎为下午3点

instant1.toString():2010-10-03T14:58:07Z

instant2.toString():2010-10-03T14:58:07Z

平等:真的


关于java.time 该框架内置于Java8及更高版本中。这些类取代了麻烦的旧日期时间类,如,&

该项目现已启动,建议迁移到类

要了解更多信息,请参阅.和搜索堆栈溢出以获取许多示例和解释。规范为

您可以直接与数据库交换java.time对象。使用兼容的或更高版本。不需要字符串,也不需要
java.sql.*
classes

从哪里获得java.time类

  • 、和更高版本-标准Java API的一部分,带有捆绑实现。
    • Java9添加了一些次要功能和修复
    • 大多数java.time功能都在中向后移植到Java6和Java7
    • 更高版本的Android捆绑包实现了java.time类

    • 对于早期的Android(您在“2010-10-03T16:58:07.000+02:00”中有一个类型,表示它不是位于与格林尼治标准时间偏移+2小时的时区中的16:58:07)”。该类型必须为:“2010-10-03T16:58:07.000+02:00表示它位于与UTC偏移+2小时的时区中)“是的,我预计是格林威治标准时间16:58:07。然后,时间戳似乎被打破了。这些是来自不同服务器的两个不同日志文件的时间戳。我很确定他们指定了相同的事件。这就是我的困惑所在。@MacSim:当然,我在那里写得有点太快了。当我们想到在欧洲/莫斯科时区t生成的第一个时间戳时,这一切都是有道理的
      OffsetDateTime odt2 = OffsetDateTime.parse( "2010-10-03T16:58:07.000+02:00" ) ;
      
      Instant instant1 = zdtMoscow.toInstant() ;  // Adjust from time zone to UTC.
      Instant instant2 = odt2.toInstant() ;       // Adjust from offset to UTC.
      
      boolean equality = instant1.equals( instant2 );