在Java中操作日期和时间戳的最佳方法是什么?

每当我需要使用Java中的日期和/或时间戳时,我总是觉得我做错了什么并花费无数个小时试图找到一种更好的API工作方式,而无需编写我自己的日期和时间实用程序类。 这是我遇到的一些烦人的事情:

  • 基于0的月份。 我意识到最好的做法是使用Calendar.SEPTEMBER而不是8,但令人讨厌的是8代表9月而不是8月。

  • 获取没有时间戳的日期。 我总是需要将日期的时间戳部分归零的实用程序。

  • 我知道我过去还有其他问题,但不记得了。 随意在您的回复中添加更多内容。

所以,我的问题是……你使用什么第三方API来简化Java对日期和时间操作的使用,如果有的话? 有关使用Joda的任何想法? 有人仔细观察JSR-310 Date and Time API吗?

这篇文章对比较Java Date / Time API和JODA进行了很好的讨论。

我个人只需要使用Gregorian Calendar和SimpleDateFormat,我需要在Java中操作日期/时间。 我从来没有在使用Java API时遇到任何问题,并且发现它很容易使用,因此没有真正研究过任何替代方案。

java.time

Java 8及更高版本现在包含java.time框架。 受JSR 310定义的Joda-Time的启发,由ThreeTen-Extra项目扩展。 请参阅教程 。

该框架取代了旧的java.util.Date/.Calendar类。 转换方法允许您来回转换以使用尚未针对java.time类型更新的旧代码。

核心课程是:

  • Instant
    时间轴上的一个时刻,始终是UTC 。
  • ZoneId
    一个时区。 子类ZoneOffset包含UTC的常量 。
  • ZonedDateTime = Instant + ZoneId
    表示调整为特定时区的时间轴上的时刻。

该框架解决了您列出的几个问题。

基于0的月份

java.time中的月号为1-12。

更好的是, EnumMonth )为一年中的每个月提供一个对象实例。 因此,您不必依赖代码中的“魔术”数字,如910

 if ( theMonth.equals ( Month.OCTOBER ) ) { … 

此外,该枚举包括一些方便的实用程序方法,如获取一个月的本地化名称。

如果还不熟悉Java枚举,请阅读教程并进行学习。 他们出奇的方便和强大。

没有时间的约会

LocalDate类表示仅限日期的值,没有时间,没有时区。

 LocalDate localDate = LocalDate.parse( "2015-01-02" ); 

请注意,确定日期需要时区。 巴黎早些时候的新的一天比在蒙特利尔还要早,那时它仍然是“昨天”。 ZoneId类表示时区。

 LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ); 

同样,还有一个LocalTime类,用于尚未与日期或时区绑定的时间。


关于java.time

java.time框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

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

要了解更多信息,请参阅Oracle教程 。 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310 。

从哪里获取java.time类?

  • Java SE 8Java SE 9及更高版本
    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小function和修复。
  • Java SE 6Java SE 7
    • 许多java.timefunction都被反向移植到ThreeTen-Backport中的 Java 6和7。
  • Android的
    • ThreeTenABP项目特别适用于Android的ThreeTen-Backport (如上所述)。
    • 请参见如何使用ThreeTenABP ….

ThreeTen-Extra项目使用其他类扩展了java.time。 该项目是未来可能添加到java.time的试验场。 您可以在这里找到一些有用的课程,如IntervalYearWeekYearQuarter等。

Apache Commons Lang项目有一个DateUtils类,可以执行有用的Date操作。

DateUtils.truncate()使用DateUtils.truncate() ,它会为你“清零”Date的部分(如果你想让你的Date对象代表一个日期并且不包含任何时间信息,则会很有帮助)。 每种方法也适用于DateCalendar对象。

http://commons.apache.org/lang/

我已经独自使用Joda三年了,肯定会推荐它 – 它的整个区域都覆盖了一个“做它所说的”界面。

Joda在你开始时看起来很复杂,例如它有周期,持续时间和间隔的概念,看起来有点类似,但你可以简单地通过替换org.joda.time.DateTime (或org.joda.time.DateMidnight )开始对于代码java.util.Date ,并在了解其他区域之前坚持使用这些类包含的许多有用方法。

我正在使用GregorianCalendar – 随时随地。 简单的java.util.Date太复杂了,是的。

所以,我的建议是 – 使用GC,它很简单

它在javascript中是一样的。 当他们认为让2008年意味着2008年,31意味着本月的第31天,并且 – 这是最好的部分 – 11意味着第12个月时,有人必须吸烟。

另一方面,他们在三分之二的时候做对了。

总是让我使用Java的是日期时间库。 我从来没有使用Joda,只是简单地看一下它,看起来它是一个非常好的实现,如果我正确理解JSR-130它从Joda获取知识并最终将它包含在JavaSE中。

对于过去的项目,我经常包装Java日期时间对象,这本身就是一项非常重要的任务。 然后使用包装器进行日期操作。

日期API很难设计,特别是如果他们必须处理本地化。 尝试自己动手看看,至少值得做一次。 Joda能够做得这么好的事实对其开发者来说是一个真正的功劳。 为了回答你的问题,我没有听到关于那个图书馆的好消息,尽管我自己从未玩过它。

许多程序员首先使用Date,它有许多已弃用的重载构造函数(使其难以使用),但是一旦你弄清楚GregorianCalendar它就会变得更容易管理。 这里的例子非常有用:

http://java.sun.com/j2se/1.4.2/docs/api/java/util/GregorianCalendar.html

编写自己的日期API非常简单,它位于原始Java类,日期和日历之上。 基本上,日期和日历都受到以下事实的影响:他们试图将两个概念塞入一个类:

  1. 日期(即年 – 月 – 日)
  2. 即时(即currentTimeMillis)

当您理解这一点时,它将彻底改变您在代码中处理类似日期的概念的方式。 事情会更简单,更清晰,更好。 从各方面来说!

对我来说,Joda过于复杂,至少在绝大多数用途中都是如此,我特别不喜欢他们违反标准Java表单的事实,例如他们如何解析和格式化日期。 JODA背后的人物斯蒂芬·科勒伯恩(Stephen Colebourne)是JSR-310的规范领导者,这也遭遇了同样的问题(我跟随并为过去几年的讨论做出了贡献)。

自己做; 这很简单。 只需填写以下类:MyDate(包装年 – 月 – 日),月(枚举),TimeOfDay(小时 – 分 – 秒 – 毫秒),DayOfWeek(枚举),Instant(包装长)。 在Instants和Dates之间转换时始终考虑时区。

如果这看起来令人生畏,您可以使用Calendar和SimpleDateFormat。 你会在一天内完成这件事而不会后悔。