Calendar.setTimeInMillis 错误 - 为啥会这样? [复制]

Posted

技术标签:

【中文标题】Calendar.setTimeInMillis 错误 - 为啥会这样? [复制]【英文标题】:Calendar.setTimeInMillis error - why is that? [duplicate]Calendar.setTimeInMillis 错误 - 为什么会这样? [复制] 【发布时间】:2020-01-19 12:43:36 【问题描述】:

日历得到错误的 unix 时间。

long millis = 1568814839L;
System.out.println(millis); //1568814839
Calendar.getInstance(TimeZone.getTimeZone("Asia/Tashkent"));
calendar.setTimeInMillis(millis);
System.out.println(calendar.get(Calendar.MILLISECOND));//839

我该怎么办? Calendar.YEAR 应该是 2019 年的毫秒。但是,日历给我的是 1970,为什么?

【问题讨论】:

这是因为 1568814839 是以毫秒为单位的时间,但总体而言它包含一分钟、一小时、一天、一个月和一年。 我什么都不懂 你的 1568814839 是:2019 年 9 月 18 日星期三 1:53:59 和 839 秒,所以当你 get(Calendar.MILLISECOND) 它会返回给你 839 但是 Calendar.YEAR 用那个毫秒返回我 1970 年。月为 1,日为 19(自 1970 年以来为 839 1 1) 删除TimeZone.getTimeZone("Asia/Tashkent") 【参考方案1】:

错误是由于您混淆了以毫秒为单位的时间和以秒为单位的时间。 1568814839L 是自 1970 年 1 月 1 日以来的秒数,但您将其视为毫秒。这很容易检查:

long millis = 1568814839L;
System.out.println(millis); //1568814839
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Tashkent"));
System.out.println(calendar.getTimeInMillis()); //1568820981321
calendar.setTimeInMillis(millis);
System.out.println(calendar.get(Calendar.YEAR));//839

这将产生:

1568814839
1568820981321
1970

如您所见,您的数字减少了 3 个数量级。在毫秒数的末尾添加三个 0:

long millis = 1568814839000L;
...
System.out.println(calendar.get(Calendar.YEAR));

现在你得到:

1568814839000
1568821211006
2019

【讨论】:

【参考方案2】:

java.time

现代代码将使用 java.time,即现代 Java 日期和时间 API。

将自 1970-01-01T00:00Z 以来的整秒数提供给 Instant 类:

    ZonedDateTime zdt = Instant.ofEpochSecond(1_568_814_839L)
                               .atZone(ZoneId.of("Asia/Tashkent"));
    System.out.println(zdt);
    System.out.println("Year: " + zdt.getYear());
    System.out.println("Millisecond of second: "
                        + zdt.get(ChronoField.MILLI_OF_SECOND));

输出是:

2019-09-18T18:53:59+05:00[Asia/Tashkent]
Year: 2019
Millisecond of second: 0

正如其他人所说,您的数字是自纪元以来的秒数,而不是毫秒。

问题:我可以在 android 上使用 java.time 吗?

是的,java.time 在较旧和较新的 Android 设备上运行良好。它只需要至少 Java 6

在 Java 8 及更高版本以及更新的 Android 设备(从 API 级别 26 起)中,现代 API 是内置的。 在 Java 6 和 7 中获得 ThreeTen Backport,这是现代类的后向端口(JSR 310 的 ThreeTen;请参阅底部的链接)。 在(较旧的)Android 上使用 ThreeTen Backport 的 Android 版本。它被称为 ThreeTenABP。并确保从 org.threeten.bp 导入日期和时间类以及子包。

链接

Oracle tutorial: Date Time 解释如何使用 java.time。 Java Specification Request (JSR) 310,其中首次描述了 java.time。 ThreeTen Backport project,java.time 的向后移植到 Java 6 和 7(JSR-310 的 ThreeTen)。 ThreeTenABP,Android 版 ThreeTen Backport Question: How to use ThreeTenABP in Android Project,解释得很透彻。

【讨论】:

以上是关于Calendar.setTimeInMillis 错误 - 为啥会这样? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

DB/Rest 支持 Java 日历/日期最小值

如何检查时间戳(纪元时间)是今天还是昨天的[android]