使用 UTC 时区将 ISO8601 日期字符串解析为日期tl;博士详java.time关于 java.time 城大时间

2022-09-02 23:13:17

我正在尝试序列化/反序列化来自/到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,只是需要一个快速有效的解决方案,


答案 1

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

答案 2

tl;博士

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

2015-10-27T10:42:27.405Z

您的问题既不清晰也不具体。也许这些小例子会有所帮助。混合旧的 java.util.Date 和 .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 后七个小时的偏移量调整为 UTC 本身,我们需要在一天中的时间上添加七个小时,并在需要时滚动日期。该类可以为我们完成这项工作。使用常量指定 UTC。OffsetDateTimeZoneOffset.UTC

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

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

如果您在代码中经常使用此UTC值,并且通常应该使用此UTC值,那么您可能会发现使用对象更清晰。根据定义,An 始终采用 UTC 格式。我们可以从 中提取 .InstantInstantInstantOffsetDateTime

Instant instant = odt.toInstant() ;

瞬视(): 2015-10-27T23:22:27.605Z

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

ZonedDateTime

顺便说一句,如果您想看到同一时刻调整为某个地区的人们使用的挂钟时间,请指定一个时区,以获取对象。ZoneIdZonedDateTime

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文档解释说,他们的设计旨在让我们在应用程序中使用更低更具体的类。通常,抽象仅在框架内供内部使用。

在此问题的特定情况下,类是适当的,而不是 。OffsetDateTimeTemporalAccessor


关于 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 和 .日历,并坚持使用Joda-Time及其类,例如.用。仅在其他类需要时才显示日期。DateTime

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