[英]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);
}
两个问题:
来自Date
和System.currentTimeInMillis()
long
毫秒时间以UTC表示。 比较这些值时,无需添加时区偏移量。 您不应该像这样调整时区。
Date
, SimpleDateFormat
等仅支持毫秒级分辨率,但是您的源字符串具有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;
java.time
。 java.time
。 java.time
到Java 6和7的java.time
移植(JSR-310的ThreeTen)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.