繁体   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