簡體   English   中英

將UTC ISO 8601字符串轉換為毫秒可得到+12小時的時間

[英]Converting a UTC ISO 8601 string to milliseconds gives a time of +12 hours

我從服務器收到UTC ISO8601格式的時間,如下所示:

2018-01-25T05:14:03.4973436

我將此string轉換為milliseconds並使用當前time generating一個經過時間的值,如下所示:

public static CharSequence getRelativeTimeSpan(String timeStamp) {

    DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
    format.setTimeZone(TimeZone.getTimeZone("UTC"));

    Date date = format.parse(timeStamp);

    long past = date.getTime();

    int offset = TimeZone.getDefault().getRawOffset() + TimeZone.getDefault().getDSTSavings();
    long now = System.currentTimeMillis() + offset;

    return DateUtils.getRelativeTimeSpanString(
            past,
            now,
            DateUtils.MINUTE_IN_MILLIS);
}

但是,由於某種原因,該代碼在過去現在之間會立即產生12 hours差異。 我不確定為什么會有這樣的差異,但是例如,這個UTC字符串( 2018-01-25T05:14:03.4973436 )生成以下milliseconds( 1516857243000 ) ,該值實際上與以milliseconds的當前time並不對應。

所有這些有趣的部分是,這個自動的12 hour時差。 我確保使用"HH"而不是"hh"來解決AM/PM差異,所以我不知道是什么原因造成了這種差異。

使用JAVA8時間更新-仍然是相同的行為

我已使用以下代碼段更新了代碼,並且得到了完全相同的行為(12小時立即差異)

public static CharSequence getRelativeTimeSpan(String timeStamp) {
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSSS");
    LocalDateTime fromCustomPattern = LocalDateTime.parse(timeStamp, formatter);
    return DateUtils.getRelativeTimeSpanString(
            fromCustomPattern.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(),
            Instant.now().toEpochMilli(),
            DateUtils.MINUTE_IN_MILLIS);
}

兩個問題:

  1. 來自DateSystem.currentTimeInMillis() long毫秒時間以UTC表示。 比較這些值時,無需添加時區偏移量。 您不應該像這樣調整時區。

  2. DateSimpleDateFormat等僅支持毫秒級分辨率,但是您的源字符串具有100納秒分辨率。 有些實現會將4973436 2018-01-25T05:14:03.4973436視為毫秒,導致436毫秒並將4973000溢出到其他字段。 在某些較舊的API級別上會發生這種情況,在較新的API級別上會截斷/填充millis部分到精確的3位數字。

    要解決此問題,您可以將輸入自己截斷為3 java.time數位,或使用較新的java.time API(API 26+,例如,ThreeTenABP庫中的反向移植)。

當然,可以使其與java.time(現代Java日期和時間API,也稱為JSR-310)一起使用:

public static CharSequence getRelativeTimeSpan(String timeStamp) {
    LocalDateTime fromIso8601 = LocalDateTime.parse(timeStamp);
    return DateUtils.getRelativeTimeSpanString(
            fromIso8601.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli(),
            Instant.now().toEpochMilli(),
            DateUtils.MINUTE_IN_MILLIS);
}

您不需要顯式的格式化程序。 現代日期和時間類將ISO 8601解析為其默認值。 由於您的日期時間字符串采用UTC格式,因此請使用atOffset(ZoneOffset.UTC) (而不是默認時區,將其轉換為錯誤的結果)進行轉換。

要將以上代碼與ThreeTenABP一起使用,請確保從org.threeten.bp導入:

import org.threeten.bp.Instant;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.ZoneOffset;

鏈接

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM