繁体   English   中英

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

[英]Parse ISO8601 date string to date with UTC Timezone

我正在尝试从/到 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,只需要一个快速有效的解决方案,

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

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。 我们可以从OffsetDateTime中提取Instant

Instant instant = odt.toInstant() ;

即时.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" ) );

Java8中的原生解决方案

Date.from(ZonedDateTime.parse("1994-11-05T08:15:30+05:30").toInstant())

Date.from(ZonedDateTime.parse("1994-11-05T13:15:30Z").toInstant())

如果您的日期采用ISO 8601 UTC格式(例如: 2022-06-04T10:50:27Z ),那么您可以直接使用Instant来解析它:

Instant.parse("2022-06-04T10:50:27Z")

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM