Java 使用 UTC 时区将 ISO8601 日期字符串解析为日期
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25938560/
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
Parse ISO8601 date string to date with UTC Timezone
提问by Dimitri Kopriwa
I am trying to serialize/deserialize a date from/to a JavaScript application.
我正在尝试从/向 JavaScript 应用程序序列化/反序列化日期。
Server side, I use Java, JodaTime is installed on it. I found out how to serialize to ISO with UTC Time zone, but can't find out how to do the reverse operation.
服务器端,我用的是Java,上面安装了JodaTime。我找到了如何使用 UTC 时区序列化到 ISO,但无法找到如何进行反向操作。
Here is my code
这是我的代码
public static String getIsoDate( Date date )
{
SimpleDateFormat dateToIsoDateString = new SimpleDateFormat( ISO_8601_DATE_FORMAT );
TimeZone tz = TimeZone.getTimeZone("UTC");
dateToIsoDateString.setTimeZone( tz );
return dateToIsoDateString.format( date );
}
// this will return a date with GMT timezone
public static Date getDateFromIsoDateString( String iso8601date )
{
DateTimeFormatter jodaParser = ISODateTimeFormat.dateTimeNoMillis();
return jodaParser.parseDateTime( iso8601date ).toDate();
}
I don't mind using or not Joda, just need a quick and working solution,
我不介意使用或不使用 Joda,只需要一个快速有效的解决方案,
采纳答案by always_a_rookie_to_learn
If you are using Java 7 or earlier you can refer to this post.
如果您使用的是 Java 7 或更早版本,您可以参考这篇文章。
If you are using Java 8 you could do:
如果您使用的是 Java 8,则可以执行以下操作:
DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
TemporalAccessor accessor = timeFormatter.parse("2015-10-27T16:22:27.605-07:00");
Date date = Date.from(Instant.from(accessor));
System.out.println(date);
Update
更新
As pointed out by @BasilBourque in the comment, TemporalAccessoris java framework level interface, and is not advisable to use in the application code and it is advisable to use concrete classes rather than the interfaces.
正如@BasilBourque 在评论中指出的那样,TemporalAccessor是java 框架级接口,不建议在应用程序代码中使用,建议使用具体类而不是接口。
This interface is a framework-level interface that should not be widely used in application code. Instead, applications should create and pass around instances of concrete types, such as LocalDate. There are many reasons for this, part of which is that implementations of this interface may be in calendar systems other than ISO. See ChronoLocalDate for a fuller discussion of the issues.
此接口是框架级接口,不应在应用程序代码中广泛使用。相反,应用程序应该创建并传递具体类型的实例,例如 LocalDate。造成这种情况的原因有很多,部分原因是该接口的实现可能在 ISO 以外的日历系统中。有关这些问题的更全面讨论,请参阅 ChronoLocalDate。
There a few concrete classes available to use, like LocalDate, LocalDateTime, OffsetDateTime, ZonedDateTimeand etc..
有一些具体的类可供使用,如LocalDate、LocalDateTime、OffsetDateTime、ZonedDateTime等。
DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_DATE_TIME;
OffsetDateTime offsetDateTime = OffsetDateTime.parse("2015-10-27T16:22:27.605-07:00", timeFormatter);
Date date = Date.from(Instant.from(offsetDateTime));
System.out.println(date);
回答by Basil Bourque
tl;dr
tl;博士
OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" )
.toInstant()
.toString()
2015-10-27T23:22:27.605Z
2015-10-27T23:22:27.605Z
Details
细节
Your question is not clear and specific. Perhaps these little examples will help. Mixing the old java.util.Date and .Calendar classes with Joda-Time may be confusing you. Joda-Time completely replacesthose classes rather than augments.
你的问题不明确和具体。也许这些小例子会有所帮助。将旧的 java.util.Date 和 .Calendar 类与 Joda-Time 混合使用可能会让您感到困惑。Joda-Time 完全取代了这些类而不是增强。
java.time
时间
The modern java.timeclasses supplant both the legacy date-time classes in Java as well as the Joda-Time library which provided their inspiration.
现代java.time类取代了 Java 中遗留的日期时间类以及提供它们灵感的 Joda-Time 库。
OffsetDateTime
OffsetDateTime
The OffsetDateTime
class represents a moment on the timeline with a particular offset-from-UTC determining its wall-clock time.
所述OffsetDateTime
类表示在时间轴上的力矩与特定偏移从-UTC确定其挂钟时间。
The java.timeclasses use the standard ISO 8601formats by default when parsing/generating strings. So no need to specify a formatting pattern.
所述java.time类使用标准ISO 8601解析/生成字符串时默认格式。所以不需要指定格式模式。
OffsetDateTime odt = OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" ) ;
Instant
Instant
To adjust from the offset of seven hours behind UTC to UTC itself, we need to add seven hours to the time-of-day and rollover the date if need be. The OffsetDateTime
class can do this work for us. Specify UTC using the ZoneOffset.UTC
constant.
要将 UTC 后 7 小时的偏移调整为 UTC 本身,我们需要将时间添加到一天中的 7 小时,并在需要时滚动日期。该OffsetDateTime
班能为我们做这项工作。使用ZoneOffset.UTC
常量指定 UTC 。
OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;
odtUtc.toString(): 2015-10-27T23:22:27.605Z
odtUtc.toString(): 2015-10-27T23:22:27.605Z
If you are using this UTC value much in your code, and generally you should be, then you may find it more clear to use Instant
objects. An Instant
is alwaysin UTC by definition. We can extract an Instant
from the OffsetDateTime
.
如果您在代码中经常使用这个 UTC 值,并且通常应该如此,那么您可能会发现使用Instant
对象更清晰。一个Instant
是始终以UTC定义。我们可以Instant
从OffsetDateTime
.
Instant instant = odt.toInstant() ;
instant.toString(): 2015-10-27T23:22:27.605Z
Instant.toString(): 2015-10-27T23:22:27.605Z
Note that all three of our objects above (odt
, odtUtc
, instant
) all represent the very same simultaneous moment, the same point on the timeline. The only thing different is their wall-clock time.
请注意,我们上面的所有三个对象 ( odt
, odtUtc
, instant
) 都代表同一时刻,时间轴上的同一点。唯一不同的是他们的挂钟时间。
ZonedDateTime
ZonedDateTime
By the way, if you want to see that same moment adjusted to the wall-clock time in use by the people of a certain region, specify a time zone via ZoneId
to get a ZonedDateTime
object.
顺便说一句,如果您想看到同一时刻调整为某个地区的人们使用的挂钟时间,请指定时区 viaZoneId
以获取ZonedDateTime
对象。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString(): 2015-10-27T19:22:27.605-04:00[America/Montreal]
zdt.toString(): 2015-10-27T19:22:27.605-04:00[美国/蒙特利尔]
Use concrete classes in java.time
在java.time 中使用具体类
The Answer by always_a_rookie_to_learnis similar to the above approach but uses the interface TemporalAccessor
. Generally, using the higher interfaces and superclasses is a good idea in Java. But not here. The java.timedocumentation explains that their design intends us to use the lower more concrete classes in our apps. The abstractions are for internal use only within the framework, generally.
always_a_rookie_to_learn的答案与上述方法类似,但使用了 interface TemporalAccessor
。通常,在 Java 中使用更高的接口和超类是一个好主意。但不是这里。该java.time文档解释自己的设计意图我们在应用程序使用较低的更具体的类。通常,抽象仅在框架内供内部使用。
In the specific case of this Question, the class OffsetDateTime
is appropriate rather than TemporalAccessor
.
在这个问题的特定情况下,类OffsetDateTime
是合适的,而不是TemporalAccessor
。
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, and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.time classes.
- 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 API 的一部分。
- Java 9 添加了一些小功能和修复。
- Java SE 6和Java SE 7
- 多的java.time功能后移植到Java 6和7在ThreeTen-反向移植。
- 安卓
- java.time 类的更高版本的 Android 捆绑实现。
- 对于早期的 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
,和更多。
Joda-Time
乔达时间
UPDATE: The Joda-Time project in is maintenance mode, and it advises migration to the java.timeclasses. This section is left intact for history.
更新:Joda-Time 项目处于维护模式,它建议迁移到java.time类。这部分保留完整以供历史使用。
Joda-Time defaults to ISO 8601for strings, both parsing and generating. Joda-Timehas built-in default parsers for ISO 8601, so simply pass your compliant string to the constructor or to the static parse
method.
Joda-Time对于字符串的解析和生成默认为ISO 8601。Joda-Time具有 ISO 8601 的内置默认解析器,因此只需将您的兼容字符串传递给构造函数或静态parse
方法。
java.util.Date date = new DateTime( "2010-01-01T12:00:00+01:00Z" ).toDate();
When possible, avoid java.util.Date and .Calendar, and stick with Joda-Timeand it's classes such as DateTime
. Use .Date only where required by other classes.
如果可能,请避免使用 java.util.Date 和 .Calendar,并坚持使用 Joda-Time及其类,例如DateTime
. 仅在其他类需要时使用 .Date。
DateTime dateTimeUtc = new DateTime( someJavaDotUtilDotDate, DateTimeZone.UTC ); // Joda-Time can convert from java.util.Date type which has no time zone.
String output = dateTime.toString(); // Defaults to ISO 8601 format.
DateTime dateTimeUtc2 = new DateTime( output, DateTimeZone.UTC ); // Joda-Time can parse ISO 8601 strings.
For presentation, adjust to time zone expected by the user.
对于演示,请调整到用户期望的时区。
DateTime dateTimeMontréal = dateTimeUtc.withZone( DateTimeZone.forID( "America/Montreal" ) );
回答by stonelazy
Native solution in Java8
Java8 中的原生解决方案
Date.from(ZonedDateTime.parse("1994-11-05T08:15:30+05:30").toInstant())
Date.from(ZonedDateTime.parse("1994-11-05T13:15:30Z").toInstant())