簡體   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