Javadate和时间API有什么问题?

我经常遇到Java Date和其他与date时间相关的类的负面反馈。 作为一名.NET开发人员,我不能完全(没有使用过它们)理解它们究竟有什么问题。

任何人都可以对此有所了解吗?

啊,Java Date类。 也许是最好的例子之一,如何不用任何语言在任何地方做任何事情。 我从哪开始呢?

阅读JavaDoc可能导致人们认为开发者实际上已经有了一些好的想法。 尽pipe事实上两者之间的差异基本上是闰秒(这种情况很less发生),但UTC和GMT之间的区别仍在继续。

然而,devise决策真的是浪费任何devise良好的API的想法。 这里有一些最喜欢的错误:

  • 尽pipe是在千年的最后十年devise,它自1900年以来的年数是两位数字。由于这个平凡的决定,在Java世界中有1900多万(或1900年)的数百万的变通办法。
  • 几个月是零索引,以迎合一个非常罕见的情况有一个数组的月份,而不是与十三个元素数组,其中第一个包含一个null 。 因此,我们有0..11(今天是109年的第11个月)。 为了转换成string,在几个月有相似数量的++和 – 。
  • 他们是可变的 。 因此,任何时候你想给一个约会(比如说,作为一个实例结构),你需要返回一个克隆的date,而不是date对象本身(否则,人们可以改变你的结构)。
  • Calendar ,旨在“修复”,实际上犯了同样的错误。 他们仍然是可变的。
  • Date表示DateTime ,但为了顺应SQL land中的date时间,还有另一个java.sql.Date子类,它表示一天(尽pipe没有与其关联的时区)。
  • 没有与Date关联的时TimeZone ,所以范围(例如“整天”)通常表示为午夜 – 午夜(通常在某个任意时区)

最后,值得注意的是,闰秒通常会在一个小时之内对ntp更新的好的系统时钟进行校正(参见下面的链接)。 在引入两个闰秒(实际上每隔六个月至less每几年)内系统仍然运行的可能性相当小,特别是考虑到您必须不时重新部署代码的新版本。 即使使用dynamic语言来重新生成类或类似WAR引擎的东西,也会污染类空间并最终耗尽permgen。

JSR 310在Java 8中用java.time取代了旧的date – 时间类,在原始的JSR中certificate了自身的正确性 ,如下所示:

2.5build议的规范将解决Java社区的哪些需求?

目前Java SE有两个独立的date和时间API – java.util.Date和java.util.Calendar。 Java开发人员在博客和论坛上都一致地描述了这两种API。 值得注意的是,两个月都使用零指数,这是许多错误的原因。 日历也经历了多年来的许多错误和性能问题,主要是由于在内部以两种不同的方式存储其状态。

一个经典的错误(4639407)阻止在日历对象中创build某些date。 可以编写一段代码,可以在某些年份创build一个date,但不能在其他date创builddate,从而阻止某些用户input正确的出生date。 这是由于日历课程只允许夏令时夏令时增加1小时,而历史上这是在第二次世界大战时加上2小时。 虽然现在这个bug已经修复,但是如果将来某个国家在夏天select夏令时增加三个小时,那么Calendar课程将再次被打破。

目前的Java SE API也在multithreading环境中受到影响。 不可变的类被认为是固有的线程安全的,因为它们的状态不能改变。 但是,date和日历都是可变的,这要求程序员明确考虑克隆和线程。 另外,DateTimeFormat中缺less线程安全性的知识并不广泛,并且一直是导致很多难以跟踪线程问题的原因。

除了Java SE针对datetime的类所存在的问题外,还没有其他概念build模的类。 在Java SE中,非时区date或时间,持续时间,时间段和时间间隔没有类别表示。 因此,开发人员经常使用int来表示持续时间,javadoc指定单位。

缺乏全面的date和时间模型也导致许多常见操作比应该更复杂。 例如,计算两个date之间的天数是目前特别困难的问题。

这JSR将解决完整的date和时间模型的问题,包括date和时间(有和没有时区),持续时间和时间段,时间间隔,格式和parsing。

  • date实例是可变的 ,这几乎总是不方便的。
  • 他们有双重性质。 它们代表时间戳和日历date。 事实certificate,在计算date时,这是有问题的。
  • 日历数据的数字表示在许多情况下是违反直觉的。 例如: getMonth()是基于零的, getYear()是基于1900的(即,2009年被表示为109)。
  • 他们错过了Date类中的许多function。

我感觉对你来说…作为一名前.NET程序员,我问了同样的问题,.NET中的时间API(时间跨度,运算符重载)非常方便。

首先,要创build特定的date,您可以使用已弃用的API或:

 Calendar c = Calendar.getInstance(); c.set(2000, 31, 12) 

要减去一天,你做邪恶的事情

 Date firstDate = ... Calendar c = Calendar.getInstance(); c.setTime(fistDate); c.add(Calendar.DATE,-1); Date dayAgo = c.getTime(); 

或更糟

 Date d = new Date(); Date d2 = new Date(d.getTime() - 1000*60*60*24); 

要了解两个date之间有多less时间(以天/周/月为单位),情况会变得更糟

然而,从Apache( org.apache.commons.lang.time.DateUtilsDateUtils提供了一些方便的方法,我发现自己最近只使用它们

正如Brabster所写,Joda Time也是一个很好的外部库,但是apache似乎比其他任何东西都更“普遍”。

我发现Java的Date API可用,说实话。 我所见过和所听到的大多数问题都涉及到详细程度,涉及多个类来执行任何有用的操作( CalendarDateDateFormat / SimpleDateFormat )的需求,以及像getDayOfWeek()这样的简单访问器的缺乏。

Joda Time是Java中一个备受推崇的替代API,在Why Joda Time部分,它给出了更多的理由,为什么它是一个可行的替代scheme,可能是有趣的。