使用 UTC 时区解析 ISO8601 日期字符串

新手上路,请多包涵

我正在尝试从 JavaScript 应用程序序列化/反序列化日期。

服务器端,我使用Java,上面安装了JodaTime。我发现了如何使用 UTC 时区序列化为 ISO,但无法找到如何进行反向操作。

这是我的代码

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();
}

我不介意使用或不使用 Joda,只需要一个快速有效的解决方案,

原文由 Dimitri Kopriwa 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 852
2 个回答

如果您使用的是 Java 7 或更早版本,您可以参考这篇 文章

如果你使用的是 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);

更新

正如@BasilBourque 在评论中指出的那样, TemporalAccessor 是 java 框架级接口,不建议在应用程序代码中使用,建议使用具体类而不是接口。

此接口是框架级接口,不应在应用程序代码中广泛使用。相反,应用程序应该创建并传递具体类型的实例,例如 LocalDate。这有很多原因,部分原因是该接口的实现可能在 ISO 以外的日历系统中。有关这些问题的更全面讨论,请参阅 ChronoLocalDate。

有一些具体的类可供使用,如 LocalDateLocalDateTimeOffsetDateTimeZonedDateTime 等。

 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);

原文由 always_a_rookie 发布,翻译遵循 CC BY-SA 4.0 许可协议

tl;博士

OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" )
.toInstant()
.toString()

2015-10-27T23:22:27.605Z

细节

你的问题不明确也不具体。也许这些小例子会有所帮助。将旧的 java.util.Date 和 .Calendar 类与 Joda-Time 混合使用可能会让您感到困惑。 Joda-Time 完全 取代了 这些类而不是扩充了这些类。

java.time

现代的 java.time 类取代了 Java 中遗留的日期时间类以及提供它们灵感的 Joda-Time 库。

OffsetDateTime

OffsetDateTime 类表示时间轴上的一个时刻,其与 UTC 的特定偏移量决定了它的挂钟时间。

java.time 类在解析/生成字符串时默认使用标准 ISO 8601 格式。因此无需指定格式化模式。

 OffsetDateTime odt = OffsetDateTime.parse( "2015-10-27T16:22:27.605-07:00" ) ;

Instant

要将 UTC 后 7 小时的偏移量调整为 UTC 本身,我们需要将时间增加 7 小时,并在需要时翻转日期。 OffsetDateTime 类可以为我们完成这项工作。使用 ZoneOffset.UTC 常量指定 UTC。

 OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;

odtUtc.toString(): 2015-10-27T23:22:27.605Z

如果您在代码中经常使用此 UTC 值,通常您应该使用,那么您可能会发现使用 Instant 对象会更清楚。 Instant 根据定义 始终 采用 UTC。我们可以从 — 中提取一个 Instant OffsetDateTime

 Instant instant = odt.toInstant() ;

instant.toString(): 2015-10-27T23:22:27.605Z

请注意,我们上面的所有三个对象( odtodtUtcinstant )都代表了同时时间线上的同一点。唯一不同的是他们的挂钟时间。

ZonedDateTime

顺便说一句,如果你想看到同一时刻调整为某个地区的人使用的挂钟时间,请通过 ZoneId 指定时区以获得 ZonedDateTime 对象。

 ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

zdt.toString(): 2015-10-27T19:22:27.605-04:00[美国/蒙特利尔]

java.time 中使用具体类

always_a_rookie_to_learn 的答案 与上述方法类似,但使用接口 TemporalAccessor 。通常,在 Java 中使用更高的接口和超类是个好主意。但不是在这里。 java.time 文档解释说,他们的设计旨在让我们在我们的应用程序中使用更底层、更具体的类。通常,抽象仅供框架内部使用。

在这个问题的具体情况下,类 OffsetDateTime 是合适的,而不是 TemporalAccessor


关于 java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

现在处于 维护模式Joda-Time 项目建议迁移到 java.time 类。

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

您可以直接与数据库交换 java.time 对象。使用符合 JDBC 4.2 或更高版本的 JDBC 驱动程序。不需要字符串,不需要 java.sql.* 类。

在哪里获取 java.time 类?

ThreeTen-Extra 项目用附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 IntervalYearWeekYearQuarter 等等


乔达时间

更新:Joda-Time 项目处于维护模式,它建议迁移到 java.time 类。此部分保留完整以供历史参考。

Joda-Time 默认为字符串的 ISO 8601 ,包括解析和生成。 Joda-Time 内置了 ISO 8601 的默认解析器,因此只需将您的兼容字符串传递给构造函数或静态 parse 方法。

 java.util.Date date = new DateTime( "2010-01-01T12:00:00+01:00Z" ).toDate();

如果可能,请避免使用 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.

对于演示,调整到用户期望的时区。

 DateTime dateTimeMontréal = dateTimeUtc.withZone( DateTimeZone.forID( "America/Montreal" ) );

原文由 Basil Bourque 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题