Java 日期 - 应该使用哪个类?

18

所以整个Java Date / Calendar / GregorianCalendar这一套显然是一个笑话。那么,使用什么样的Date类才是正确的呢?

编辑:在Android上构建面向第三方SDK的应用程序,其中应用程序需要提供日期。

更多编辑:使这种情况显然是一个笑话的原因:

  • 99%的Date已被弃用
  • Date的年份偏移自1900年
  • Date的月份从零开始索引,而日期从1开始索引
  • 日期是可变的
  • 你应该使用Calendar来创建日期......
  • ......除非你真的必须使用GregorianCalendar
    • 有相当比例的开发人员想使用不同的日历吗?
  • Calendar.getTime()返回Date
  • 没有日期计算(例如两个日期之间相差多少年)
    • 毫秒级别的计算不算
  • 无法将部分链接在一起以获取表达式(例如一年前的今天的日期)
  • 可能还有其他的问题

2
我点赞是因为我同意(可悲的是)整个日历混乱是一堆垃圾。我最终经常只使用日期,甚至是System.currentTimeMillis()。 - user949300
这不是笑话!这只是 Java 中日期 API 悲惨现状的真实写照... - maerics
1
@BasilBourque 我不确定重新提出这样一个老问题是否值得努力。 - Dave Newton
@DaveNewton,您所说的“复活”是指我链接到相关问题还是回答这个问题?无论哪种方式,“忽略旧问题”都必须成为Stack Overflow的新政策,因此请指引我查看相关文档。此前,该网站会为旧问题上的新活动颁发奖励。 - Basil Bourque
1
@BasilBourque,仅仅因为你回答了一些老问题就获得了荣誉并不意味着这是一个好主意,或者说没有更近期的问题更加相关。你可以随便抱怨和发牢骚——但我认为在有更多近期、更相关的问题需要关注时,去回答七年前的问题并没有什么意义。 - Dave Newton
3个回答

17

Joda-Time可以在Android上使用。

如果你想使用Java SE类,那就要看你要做什么了。

编辑:你不停地更改问题。 DateCalendar


2
当你将jar文件添加到项目中时,它在Android上运行得非常完美。而且它是迄今为止最好的日期框架。+1 - Guillaume
我认为Joda-Time是Java中最好的日期处理解决方案,但作为API设计者,不强制用户依赖不必要的库更为重要(如果他们的应用程序依赖于与您的SDK不同的Joda-Time版本怎么办?)。尽管如此,如果Joda-Time提供了对您的API至关重要的功能,则可以选择使用它并显式依赖它。 - maerics
@Hounshell Java标准版。Java。 - Dave Newton
啊,没看到“Joda time”的部分。不幸的是,我需要坚持使用Android附带的核心jar包,不能使用第三方jar包(主要是因为@maerics指出的缺点)。 - Hounshell
1
Joda-Time 项目现已进入维护模式,团队建议迁移到 java.time 类。请参阅 Oracle 的教程 - Basil Bourque
显示剩余4条评论

4

避免使用旧版日期时间类

所以整个Java Date/Calendar/GregorianCalendar的东西显然是个笑话。

是的,早期版本的Java捆绑了旧版日期时间类,这些类非常混乱。设计不良,笨拙尝试改进,许多hack。

但是公平地说,这些类是在应对整个信息行业数十年忽视的一个令人惊讶的棘手主题时做出的勇敢努力。基于TaligentIBM的先前工作,这些类的作者至少做出了一种尝试,在几乎所有其他编程语言、平台和工具只提供最基本的日期时间处理支持的情况下。

幸运的是,我们现在有行业领先的java.time类(JSR 310)内置于Java 8及更高版本中。这些类受到了Joda-Time项目成功的启发。事实上,这两个努力都由同一个人Stephen Colebourne领导。

java.time

使用java.time,您的所有投诉问题都可以得到纠正。

  • 99%的Date已弃用
    Instant取代了java.util.Date。据我所知,Java 8和Java 9中的java.time没有任何废弃的内容。
  • Date的年份偏移自1900年
    在java.time中,年份有一个合理的编号,2018是2018年。
  • Date的月份从零开始计数,而日期从一开始计数
    在java.time中,月份有一个合理的编号,1-12表示1月到12月。更好的是,Month enum提供了表示每个月份的对象,而不仅仅是一个整数。因此,您可以获得有效的值、类型安全和自我记录的代码。
  • 日期可变
    几乎所有的java.time都是不可变的。对java.time对象的任何更改调用都会返回一个新的、独立的对象。甚至构造函数也被隐藏起来,而是使用静态工厂方法。
  • 你应该使用Calendar来创建日期……
    ZonedDateTime替换了java.util.Calendar
  • ……除非你真的必须使用GregorianCalendar
    ZonedDateTime也替换了java.util.GregorianCalendar。java.time框架主要使用接口供内部使用,鼓励应用程序仅使用具体类。这是java.time作为框架特定需求的设计决策,并不意味着您在应用程序中也应该这样做。
  • Calendar.getTime()返回一个Date
    在java.time中,只需使用Instant作为基本构建块类,始终表示UTC的一个时刻,分辨率为纳秒。其他类型如OffsetDateTimeZ

    另一个问题领域是与数据库交换日期时间值。请注意,如果使用符合JDBC 4.2或更高版本(JSR 221)的JDBC驱动程序,则可以避免与日期时间相关的java.sql类,例如java.sql.Timestamp类。那些旧类与麻烦的旧遗留类有关,现在已不再需要。

    myPreparedStatement.setObject( … , instant ) ;
    

    …和…

    Instant instant = myResultSet.getObject( … , Instant.class ) ;
    

    关于java.time

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

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

    要了解更多信息,请参阅Oracle教程。在Stack Overflow上搜索许多示例和解释。规范是JSR 310
    如何获取java.time类?

1

“正确”的日期类型完全取决于您的应用程序;然而,java.util.Calendar通常被认为是java.util.Date的替代品,因为它提供了更多的功能(特别是关于提取单个日期元素如年、月等)。实际上,在某些情况下,Date可以更容易使用(并且是Java自己的DateFormat类所使用的),因此这是一个判断性的选择。

在两者之间进行转换并不困难,因此我会选择其中一个并始终保持一致地使用它来编写API。如果我要选择一个,我会使用Date,因为它是最简单的,以我个人的看法。


请注意,旧的日期时间类(如java.util.Datejava.util.Calendarjava.text.SimpleDateFormat)现在已经成为遗留系统,被内置于Java 8和Java 9中的java.time类所取代。请参阅Oracle的教程 - Basil Bourque

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接