我有两个时间戳,用两种不同的格式描述同一时刻。
2010-10-03 18: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));
答案 0 :(得分:7)
如果您的默认时间是欧洲/柏林,2010-10-03 18:58:07对应2010-10-03T16:58:07.000 + 00:00。
您可能会误解字符串表示中的时区字段。您的时间戳2010-10-03T16:58:07.000 + 02:00意味着“在格林尼治标准时间偏离+2小时的时区是16:58:07”,或者用其他措辞“现在是16 :58:07在柏林“。我认为你预计这意味着它是格林尼治标准时间16:58:07?
答案 1 :(得分:4)
你的两个时间戳并不代表同一时刻(正如jambjo已经评论过的那样)。请参阅维基百科上的Time zone as offsets from UTC。
另请参阅parseDateTime文档,了解其工作原理。如果您未提供任何时区,则将应用默认时区(如果您在那里,则为柏林时区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)希望你明白了。您需要使用withZone方法调整时间以获得所需的结果。
答案 2 :(得分:1)
使用现代的 java.time 类取代 Joda-Time 。
LocalDateTime // Represent a date and time-of-day without the context of a time zone or offset-from-UTC. *Not* a moment, *not* a point on the timeline.
.parse( // Parse text into a date-time value.
"2010-10-03 18:58:07".replace( " " , "T" ) // Replace SPACE in middle with a `T` to comply with ISO 8601 standard used by default in *java.time* when parsing/generating strings.
) // Returns a `LocalDateTime` object.
.atZone( // Assign the time zone we know for certain was intended for this input.
ZoneId.of( "Europe/Moscow" ) // Real time zones are named in `Continent/Region` format, never 2-4 letter codes such as CST, PST, IST, CEST, etc.
) // Returns a `ZonedDateTime` object, a date with time-of-day and with a time zone assigned to determine a moment.
.toInstant() // Adjust from time zone to UTC.
.equals(
OffsetDateTime // Represent a date and time-of-day with an offset-from-UTC but not a full time zone.
.parse( "2010-10-03T16:58:07.000+02:00" ) // Parse a standard ISO 8601 string.
.toInstant() // Adjust from offset to UTC (in other words, an offset of zero hours-minutes-seconds).
) // Returns `boolean`.
true
Answer by jarnbjo是正确的,因为您误解了offset-from-UTC和time zone值的含义。
现在,Joda-Time项目在2018年处于维护模式。该项目的主要作者斯蒂芬·科尔本(Stephen Colebourne)继续找到JSR 310,并编写了其实现,即java.time中的OpenJDK类。
您的输入字符串2010-10-03 18:58:07
几乎是标准的ISO 8601格式。为了符合要求,请将中间的空格替换为T
。
String input1 = "2010-10-03 18:58:07".replace( " " , "T" ) ;
该字符串缺少时区或UTC偏移量的任何指示。因此解析为LocalDateTime
。
LocalDateTime ldt = LocalDateTime.parse( input1 ) ;
此值 not 表示一个时刻,是 not 在时间轴上的一个点。如果没有时区或偏移量的上下文,则可能是世界各地时区范围约26-27小时内的许多时刻中的任何时刻。
在您的评论中,您揭示了输入字符串显然旨在表示Europe/Moscow
时区中的日期和时间。因此,我们可以分配该区域来确定时刻,即时间轴上的一个点。
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 [欧洲/莫斯科]
您的第二个输入2010-10-03T16:58:07.000+02:00
符合标准ISO 8601格式。
此输入的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。根据定义,Instant
始终采用UTC。
提示:养成思考,工作,存储,交换和登录UTC的习惯。将UTC视为唯一的真实时间。
Instant instant1 = zdtMoscow.toInstant() ; // Adjust from time zone to UTC.
Instant instant2 = odt2.toInstant() ; // Adjust from offset to UTC.
boolean equality = instant1.equals( instant2 );
运行时,我们看到结果的末尾带有Z
。这表示UTC,并且发音为Zulu
。而且,的确,我们看到这两个值表示同一时刻,在UTC几乎是下午3点。
instant1.toString():2010-10-03T14:58:07Z
instant2.toString():2010-10-03T14:58:07Z
平等:真实
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。
答案 3 :(得分:0)
我遇到了与您相同的问题,发现的最佳方法是解析数据。 我本来是这样的格式:2018-01-22 09:25:14.000 +0000
只需选择该列,然后在“数据”标签中单击“文本到列”即可。
我使用带空格的Delimited在3个不同的列中解析此格式。 所以最后,我有了;
颜色A 2018-01-22 B座09:25:14.000 C +0000