java 使用带时区的 Joda 解析日期
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4624992/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Parsing date with Joda with time zone
提问by wilfried
I have two timestamps which describe the same instant of time in two different formats.
我有两个时间戳,它们以两种不同的格式描述同一时刻。
2010-10-03 18:58:07
and 2010-10-03T16:58:07.000+02:00
.
2010-10-03 18:58:07
和2010-10-03T16:58:07.000+02:00
。
I parse the timestamps with two different date formatters with Joda-Time. In the end I want to have two DateTime objects that are equal in terms of being the same instant of time.
我用 Joda-Time 用两个不同的日期格式化程序解析时间戳。最后,我想要两个 DateTime 对象,它们在同一时刻是相等的。
The DateFormatter offers several methods to control time zones and locales but i couldn't get it to work.
DateFormatter 提供了多种方法来控制时区和语言环境,但我无法让它工作。
This is the code that i would like to work:
这是我想要工作的代码:
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));
采纳答案by jarnbjo
If your default time zome is Europe/Berlin, 2010-10-03 18:58:07 corresponds to 2010-10-03T16:58:07.000+00:00.
如果您的默认时区是欧洲/柏林,则 2010-10-03 18:58:07 对应于 2010-10-03T16:58:07.000+00:00。
You probably misunderstand the time zone field in the string representation. Your time stamp 2010-10-03T16:58:07.000+02:00 means that "it is 16:58:07 in a time zone with a +2 hour offset from GMT), or in an other wording "it is now 16:58:07 in Berlin". I assume that you expected it to mean that it's 16:58:07 GMT?
您可能误解了字符串表示中的时区字段。您的时间戳 2010-10-03T16:58:07.000+02:00 意味着“它是 16:58:07 在与格林威治标准时间有 +2 小时偏移的时区中),或者换句话说“现在是 16 :58:07 在柏林”。我假设您认为它意味着格林威治标准时间 16:58:07?
回答by MicSim
Your two timestamps don't represent the same instant in time (as jambjo already remarked). See Time zone as offsets from UTCon wikipedia.
您的两个时间戳不代表同一时刻(正如 jambjo 已经指出的那样)。见时区从UTC偏移维基百科。
Also see the parseDateTimedocumentation on how it works. If you don't provide any time zone, then the default time zone will be applied (that is Berlin time zone UTC+2 if you are there). So:
另请参阅有关其工作原理的parseDateTime文档。如果您不提供任何时区,则将应用默认时区(如果您在那里,则为柏林时区 UTC+2)。所以:
2010-10-03 18:58:07
becomes2010-10-03T18:58:07.000+02:00
(18:58 in Berlin with offset of 2 hours to UTC, that means 16:58 in UTC) as expected.2010-10-03T16:58:07.000+02:00
stays as it is, because there is a time zone provided (i.e. 16:58 in Berlin with offset of 2 hours to UTC, that means 14:58 in UTC)
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)
Hope you got the idea. You will need to adjust the times with the withZonemethod to get the desired results.
希望你有这个想法。您需要使用withZone方法调整时间以获得所需的结果。
回答by Basil Bourque
tl;dr
tl;博士
Use the modern java.timeclasses that supplanted Joda-Time.
使用取代Joda-Time的现代java.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
真的
Details
细节
The Answer by jarnbjois correct in that you misunderstood the meanings of the offset-from-UTCand time zonevalues.
jarnbjo的答案是正确的,因为您误解了offset-from-UTC和时区值的含义。
Now in 2018, the Joda-Timeproject is in maintenance-mode. That project's principal author, Stephen Colebourne, went on to found JSR 310and author its implementation, the java.timeclasses found in OpenJDK.
现在在 2018 年,Joda-Time项目处于维护模式。该项目的主要作者 Stephen Colebourne 继续创建了JSR 310并编写了它的实现,即OpenJDK 中的java.time类。
First input
第一次输入
Your input string 2010-10-03 18:58:07
is nearly in standard ISO 8601format. To comply, replace the SPACE in the middle with a T
.
您的输入字符串2010-10-03 18:58:07
几乎采用标准ISO 8601格式。为了遵守,请将中间的 SPACE 替换为T
.
String input1 = "2010-10-03 18:58:07".replace( " " , "T" ) ;
That string lacks any indicator of time zone or offset-from-UTC. So parse as a LocalDateTime
.
该字符串缺少时区或UTC 偏移量的任何指示符。所以解析为LocalDateTime
.
LocalDateTime ldt = LocalDateTime.parse( input1 ) ;
This value does notrepresent a moment, is nota point on the timeline. Without the context of a zone or offset, it could be any of many moments within a range of about 26-27 hours, the range of time zones around the globe.
此值也不会代表了一下,是不是在时间轴上的一个点。如果没有区域或偏移的上下文,它可以是大约 26-27 小时范围内的许多时刻中的任何一个,即全球时区的范围。
In your comments you revealed that apparently that input string was meant to represent a date and time-of-day in the Europe/Moscow
time zone. So we can assign that zone to determine a moment, a point on the timeline.
在您的评论中,您透露显然该输入字符串旨在表示时区中的日期和时间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[Europe/Moscow]
zdtMoscow.toString(): 2010-10-03T18:58:07+04:00[欧洲/莫斯科]
Second input
第二个输入
Your second input 2010-10-03T16:58:07.000+02:00
complies with standard ISO 8601format.
您的第二个输入2010-10-03T16:58:07.000+02:00
符合标准ISO 8601格式。
This input carries an offset-from-UTC of two hours ahead of UTC. So this string represents the time-of-day of 14:58:07 in UTC.
此输入比 UTC 提前两小时从 UTC 偏移。因此,此字符串表示 UTC 中 14:58:07 的时间。
We can parse as a OffsetDateTime
to respect the given offset.
我们可以解析为 aOffsetDateTime
以尊重给定的偏移量。
OffsetDateTime odt2 = OffsetDateTime.parse( "2010-10-03T16:58:07.000+02:00" ) ;
odt2.toString(): 2010-10-03T16:58:07+02:00
odt2.toString(): 2010-10-03T16:58:07+02:00
Compare
比较
Do these two inputs represent the same moment, the same point on the timeline?
这两个输入是否代表同一时刻,时间线上的同一点?
One way to compare is by adjusting both to UTC. An Instant
is always in UTC, by definition.
一种比较方法是将两者都调整为 UTC。根据Instant
定义,An始终采用 UTC。
Tip: Get in the habit of thinking, working, storing, exchanging, and logging in UTC. Think of UTC as The One True Time.
提示:养成在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 );
When run, we see results with a Z
on the end. That means UTC, and is pronounced Zulu
. And, indeed, we see these two values represent the same moment, almost 3 PM in UTC.
运行时,我们会看到Z
结尾带有 a的结果。这意味着UTC,并发音为Zulu
。事实上,我们看到这两个值代表同一时刻,UTC 时间几乎是下午 3 点。
instant1.toString(): 2010-10-03T14:58:07Z
instant2.toString(): 2010-10-03T14:58:07Z
equality: true
Instant1.toString(): 2010-10-03T14:58:07Z
Instant2.toString(): 2010-10-03T14:58:07Z
平等:真的
About java.time
关于java.time
The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
该java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date
, Calendar
, & SimpleDateFormat
。
The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310。
You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*
classes.
您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*
Where to obtain the java.time classes?
从哪里获得 java.time 类?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6and Java SE 7
- Most of the java.timefunctionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.timeclasses.
- For earlier Android (<26), the ThreeTenABPproject adapts ThreeTen-Backport(mentioned above). See How to use ThreeTenABP….
- Java SE 8、Java SE 9、Java SE 10、Java SE 11及更高版本 - 标准 Java API 的一部分,具有捆绑实现。
- Java 9 添加了一些小功能和修复。
- Java SE 6和Java SE 7
- 大多数java.time功能在ThreeTen-Backport 中被反向移植到 Java 6 & 7 。
- 安卓
- 更高版本的 Android 捆绑实现java.time类。
- 对于早期的 Android(<26),ThreeTenABP项目采用了ThreeTen-Backport(上面提到过)。请参阅如何使用ThreeTenABP ...。
The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
该ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如Interval
,YearWeek
,YearQuarter
,和更多。
回答by Mathieu Laporte
I had the same issue as you and the best way I found is to parse the data. I originally had this format: 2018-01-22 09:25:14.000 +0000
我和你有同样的问题,我发现最好的方法是解析数据。我原来有这种格式:2018-01-22 09:25:14.000 +0000
Simply select the column and click on "Text to Columns" in Data's tab.
只需选择该列,然后单击“数据”选项卡中的“文本到列”。
I used Delimited with space to parse this format in 3 different columns. So at the end, I have;
我使用带空格的分隔来解析 3 个不同列中的这种格式。所以最后,我有;
Col A 2018-01-22 Col B 09:25:14.000 Col C +0000
Col A 2018-01-22 Col B 09:25:14.000 Col C +0000