java.time
Java 8 及更高版本中的 java.time 框架取代了旧的 java.util.Date/.Calendar 类。旧的课程已被证明是麻烦的、令人困惑的和有缺陷的。避开他们。
java.time 框架受到高度成功的 Joda-Time 库的启发,该库由 JSR 310 定义,由 ThreeTen-Extra 项目扩展,并在 Tutorial 中进行了解释。
Instant
Instant 类代表UTC 中时间轴上的一个时刻。
java.time 框架的分辨率为纳秒,或小数秒的 9 位数字。毫秒只是小数秒的 3 位数字。因为millisecond resolution 很常见,所以java.time 包含了一个方便的工厂方法。
long millisecondsSinceEpoch = 1446959825213L;
Instant instant = Instant.ofEpochMilli ( millisecondsSinceEpoch );
millisecondsSinceEpoch: 1446959825213 是即时的: 2015-11-08T05:17:05.213Z
ZonedDateTime
要考虑当前周和当前月,我们需要应用特定的时区。
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant , zoneId );
在 zoneId: America/Montreal 即:2015-11-08T00:17:05.213-05:00[America/Montreal]
半开
在日期时间工作中,我们通常使用半开方法来定义时间跨度。开头是inclusive,而结尾是exclusive。我们没有尝试确定一周(或月)结束的最后一瞬间,而是获得下一周周(或月)的第一时刻。因此,一周从星期一的第一刻开始一直到但不包括下一个星期一的第一刻。
让我们在一周的第一天,也是最后一天。 java.time 框架包括一个工具,with 方法和ChronoField 枚举。
默认情况下,java.time 使用ISO 8601 标准。所以周一是一周的第一天 (1),周日是最后一天 (7)。
ZonedDateTime firstOfWeek = zdt.with ( ChronoField.DAY_OF_WEEK , 1 ); // ISO 8601, Monday is first day of week.
ZonedDateTime firstOfNextWeek = firstOfWeek.plusWeeks ( 1 );
那一周从:2015-11-02T00:17:05.213-05:00[America/Montreal] 到 2015-11-09T00:17:05.213-05:00[America/Montreal]
哎呀!查看这些值的时间。我们想要一天的第一刻。由于夏令时 (DST) 或其他异常情况,一天中的第一时刻并不总是 00:00:00.000。所以我们应该让 java.time 代表我们进行调整。为此,我们必须通过 LocalDate 类。
ZonedDateTime firstOfWeek = zdt.with ( ChronoField.DAY_OF_WEEK , 1 ); // ISO 8601, Monday is first day of week.
firstOfWeek = firstOfWeek.toLocalDate ().atStartOfDay ( zoneId );
ZonedDateTime firstOfNextWeek = firstOfWeek.plusWeeks ( 1 );
该周从:2015-11-02T00:00-05:00[America/Montreal] 到 2015-11-09T00:00-05:00[America/Montreal]
这个月也一样。
ZonedDateTime firstOfMonth = zdt.with ( ChronoField.DAY_OF_MONTH , 1 );
firstOfMonth = firstOfMonth.toLocalDate ().atStartOfDay ( zoneId );
ZonedDateTime firstOfNextMonth = firstOfMonth.plusMonths ( 1 );
该月从:2015-11-01T00:00-04:00[America/Montreal] 到 2015-12-01T00:00-05:00[America/Montreal]
YearMonth
查看一对时刻是否在同一月份的另一种方法是检查相同的YearMonth 值。
例如,假设thisZdt 和thatZdt 都是ZonedDateTime 对象:
boolean inSameMonth = YearMonth.from( thisZdt ).equals( YearMonth.from( thatZdt ) ) ;
毫秒
我强烈建议不要以毫秒为单位进行日期时间工作。这确实是日期时间类倾向于在内部工作的方式,但我们有这些类是有原因的。处理从纪元开始的计数很笨拙,因为人类无法理解这些值,因此调试和记录很困难并且容易出错。而且,正如我们已经看到的,不同的解决方案可能正在发挥作用。旧的 Java 类和 Joda-Time 库使用毫秒,而 Postgres 等数据库使用微秒,现在 java.time 使用纳秒。
您会将文本作为位处理,还是让String、StringBuffer 和StringBuilder 等类处理此类细节?
但如果你坚持,从ZonedDateTime 得到一个Instant,然后从那个得到一个毫秒数。但请记住此调用可能意味着数据丢失。 ZonedDateTime/Instant 中可能包含的任何微秒或纳秒都将被截断(丢失)。
long millis = firstOfWeek.toInstant().toEpochMilli(); // Possible data loss.
关于java.time
java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。
Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。
您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。
从哪里获得 java.time 类?