Java日历:在两个日期/时间之间获得差异 - 关闭一个

Sco*_*ggs 7 java calendar datediff date

我在这个主题上看到了很多问题和答案,但没有一个能解决我的特殊问题.我扩展了Java Calendar类(标准 - 没有第三方库),并且需要找到两个任意日期之间的天数差异.

方法:

  1. 将两个日期的时间更改为午夜.
  2. 将日期转换为毫秒.
  3. 找出两个日期之间的差异.
  4. 将结果除以一天中的毫秒数(24*60*60*1000).
  5. 结果应该是天数的差异.

它有时是,而有时则不是.即使是在同一天进行的测试也可能会被一个人关闭.这是怎么回事?

Arn*_*ter 7

约达时间库中有这样的问题很好的支持:

LocalDate d1 = new LocalDate(calendar1.getTimeInMillis());
LocalDate d2 = new LocalDate(calendar2.getTimeInMillis());
int days = Days.daysBetween(d1, d2).getDays();
Run Code Online (Sandbox Code Playgroud)

更新(来自@ basil-bourque的反馈):

从Java 8 java.time开始,引入了新的时间库,现在提供了一个没有外部依赖关系的类似选项:

int days = Duration.between(calendar1.toInstant(), calendar2.toInstant()).toDays();
Run Code Online (Sandbox Code Playgroud)


Dun*_*nes 5

根据其他用户的建议,您还需要将日历的毫秒值设置为零,以仅比较日期.这可以通过以下代码段实现:

someCalendar.set(Calendar.MILLISECOND, 0)
Run Code Online (Sandbox Code Playgroud)

另外,请注意时区变化(例如从冬季到夏季)可能意味着一天中有多于或少于86,400,000毫秒.


Bas*_*que 5

tl; dr

ChronoUnit.DAYS.between( then , now )
Run Code Online (Sandbox Code Playgroud)

天真的计算

您在代码中假设每天正好是二十四小时。不对。诸如夏令时(DST)之类的异常表示天数可能会有所不同,例如23小时长,25小时或其他数字。时区的真正含义是跟踪这些异常的历史记录。

另外,您假设一天从午夜开始。不对。由于异常,某些日子会在其他时间开始,例如01:00

避免使用旧的日期时间类

您正在使用旧的麻烦日期时间类,如java.util.Datejava.util.Calendarjava.text.SimpleTextFormat现在的遗产,由取代java.time类。

时区

指定适当的时区名称,格式continent/region,如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用3-4个字母的缩写,例如EST或,IST因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。

不要扩展java.time

不要扩展(子类)java.time类(它们被标记为final)。

并且不要针对您的业务逻辑对其接口进行泛化;坚持该框架的具体类别。泛化在其他框架(如Java Collections)中是有意义的,而在java.time中则没有。

使用java.time

使用java.time类,这项工作容易得多。

ZonedDateTime代表时间轴上具有指定时区(ZoneId)的时刻。

ZoneId z = ZoneId.of( "America/Montreal" );

// of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond, ZoneId zone)
ZonedDateTime then = ZonedDateTime.of( 2017 , 1 , 23 , 12 , 34 , 56 , 123456789 , z );

ZonedDateTime now = ZonedDateTime.now( z );
Run Code Online (Sandbox Code Playgroud)

ChronoUnit枚举可以计算一对的时刻之间经过的时间。

long days = ChronoUnit.DAYS.between( then , now );
Run Code Online (Sandbox Code Playgroud)

看到此代码在IdeOne.com上实时运行

then.toString():2017-01-23T12:34:56.123456789-05:00 [美国/蒙特利尔]

now.toString():2017-03-01T21:26:04.884-05:00 [美国/蒙特利尔]

天:37

将旧版实例转换为java.time

如果有GregorianCalendar对象,则使用添加到旧类中的新方法转换为java.time。

ZonedDateTime zdt = myGregCal.toZonedDateTime() ;
Run Code Online (Sandbox Code Playgroud)

如果您知道Calendar实例实际上是一个GregorianCalendar,则将其强制转换。

GregorianCalendar myGregCal = (GregorianCalendar) myCal ;
Run Code Online (Sandbox Code Playgroud)

半开

java.time类通过Half-Open方法定义时间范围,其中开始是包含在内的,而结尾是排斥的


关于java.time

java.time框架是建立在Java 8和更高版本。这些类取代麻烦的老传统日期时间类,如java.util.DateCalendar,和SimpleDateFormat

现在处于维护模式Joda-Time项目建议迁移到java.time类。

要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

在哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。你可能在这里找到一些有用的类,比如IntervalYearWeekYearQuarter,和更多