tl;博士
ChronoUnit.DAYS.between( then , now )
简单计算
您在代码中假设每天正好是二十四小时。不对。 Daylight Saving Time (DST) 等异常表示天数可能会有所不同,例如 23 小时、25 小时或其他数字。时区的真正含义是跟踪这些异常的历史。
此外,您假设这一天从午夜开始。不对。由于异常,有些日子从其他时间开始,例如01:00。
避免使用旧的日期时间类
您正在使用麻烦的旧日期时间类,例如 java.util.Date、java.util.Calendar 和 java.text.SimpleTextFormat,现在是 legacy,被 java.time 类所取代。
时区
以continent/region 的格式指定proper time zone name,例如America/Montreal、Africa/Casablanca 或Pacific/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 );
ChronoUnit 枚举可以计算一对时刻之间经过的时间。
long days = ChronoUnit.DAYS.between( then , now );
见this code run live at 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() ;
如果您知道 Calendar 实例实际上是 GregorianCalendar,请强制转换它。
GregorianCalendar myGregCal = (GregorianCalendar) myCal ;
半开
java.time 类通过半开方法定义时间跨度,其中开始是包含,而结束是独占。
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
从哪里获得 java.time 类?
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。