Scala 中两个纪元日之间的天数

Number of days between two epoch days in scala

我有两个纪元时间戳,我想找出这两个时间戳之间的天数。

这是我现在拥有的:

dateFrom = inputEntry.getValue(inputFields(0).get).asInstanceOf[String].toLong
dateTo =inputEntry.getValue(inputFields(1).get).asInstanceOf[String].toLong

示例:

dateFrom    dateTo      result
1501583232  1501641000  1
1501583232  1501986600  5

我从这里的两个纪元日期开始

tl;博士

ChronoUnit.DAYS.between( … , … )

详情

这已在 Stack Overflow 上多次介绍。在这里简单介绍一下……

对于日期时间值,使用日期时间对象。仅使用 java.time 类,避免麻烦的遗留日期时间 类(日期、日历等)。

您是指日期差异还是 24 小时时间块差异?

我会在这里选择日期。

首先,将似乎是从纪元参考日期 1970-01-01T00:00:00Z 开始的整秒数转换为 UTC 时间轴中的一个点。

请注意数字文字末尾的 L 表示 long 而不是 int。

Instant instant = Instant.ofEpochSecond( 1_501_583_232L ) ; 

指定要考虑日期的时区。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z );

转换为仅日期。

LocalDate ld = zdt.toLocalDate() ;

获得差异。

long days = ChronoUnit.DAYS.between( ld , ld2 ) ;

要获得您想要的结果,您必须定义计算差异的方式。

以你的第一个例子(1501583232 和 1501641000 之间的差异应该是 1 天):

纪元 1501583232 和 1501641000 是自 1970-01-01T00:00Z 以来的秒数,因此它们等同于以下 UTC 日期:

1501583232: 2017-08-01T10:27:12Z
1501641000: 2017-08-02T02:30:00Z

请注意,它们之间的差异是 16 小时 2 分 48 秒(因此,不到一天)。如果您得到天数差异,从技术上讲,它将为零。

但是如果你只考虑日期(2017-08-012017-08-02)而忽略时间( hour/minute/second),则差异可以为零或 1,具体取决于您所在的时区。

如果只考虑 UTC 日期(2017-08-012017-08-02),则相差 1 天。

但是,如果您在 America/Los_Angeles 时区采用相同的 UTC 日期,您将得到:

1501583232: 2017-08-01T03:27:12-07:00
1501641000: 2017-08-01T19:30-07:00

现在差异是零天,无论你只考虑日期(都是2017-08-01),还是日期和时间(小时差异将是 16,不到一天)。

因此,您必须定义计算差异的方式(仅考虑日期,或同时考虑日期和时间,以及将使用的时区)。


在你的情况下,你似乎只考虑了日期而忽略了时间,但不清楚它使用的是哪个时区。无论如何,您可以使用 JDK 的 8 new java.time API for that (for JDK <= 7 you can use the ThreeTen Backport - 下面的代码适用于两者。唯一的区别是包名称(在 Java 8 中是 java.time,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp),但是 classes 和方法 names 相同)。

代码与 基本相同,因为它与新的 API 非常直接(我只是想补充上面的见解)。

首先,您根据纪元值创建 Instant

Instant instant1 = Instant.ofEpochSecond(1501583232L);
Instant instant2 = Instant.ofEpochSecond(1501641000L);

如果你想考虑日期和时间的差异,你可以使用:

ChronoUnit.DAYS.between(instant1, instant2);

结果将为零。

如果只想考虑 UTC 日期(忽略时间),只需执行以下操作:

// convert to UTC and get just the date (day/month/year)
LocalDate d1 = instant1.atZone(ZoneOffset.UTC).toLocalDate();
LocalDate d2 = instant2.atZone(ZoneOffset.UTC).toLocalDate();
long days = ChronoUnit.DAYS.between(d1, d2);

结果将为 1。

要转换为不同的时区(而不是 UTC),请使用 ZoneId class:

// use a specific timezone
ZoneId zone = ZoneId.of("Asia/Kolkata");
// convert the Instant to a timezone and get only the date
LocalDate d1 = instant1.atZone(zone).toLocalDate();
LocalDate d2 = instant2.atZone(zone).toLocalDate();
long days = ChronoUnit.DAYS.between(d1, d2);

在这种情况下,差异是1,但正如我上面所说,不同的时区会产生不同的结果(可以是零或1 - 例如,将上面的代码更改为ZoneId.of("America/Los_Angeles"),结果为零)。


请注意,API 使用 IANA timezones names(始终采用 Region/City 格式,如 Asia/KolkataEurope/Berlin)。 避免使用 3 个字母的缩写(如 CSTIST),因为它们是 ambiguous and not standard.

您可以通过调用 ZoneId.getAvailableZoneIds().

获取可用时区列表(并选择最适合您的系统的时区)

您还可以将系统的默认时区与 ZoneId.systemDefault() 一起使用,但这可以在不通知的情况下更改,即使在运行时也是如此,因此最好明确使用特定的时区。