Java日期和时间API有什么问题?[关闭]


105

很多时候,我遇到有关Java Date和其他与日期时间相关的类的负面反馈。作为.NET开发人员,我无法完全理解(不使用它们)它们到底有什么问题。

有人能对此有所启发吗?


Answers:


142

啊,Java Date类。最好的例子之一就是如何不以任何语言在任何地方做某事。我从哪里开始?

阅读JavaDoc可能会使人们认为开发人员实际上有了一些好主意。它接着约之间的区别UTCGMT在长度,尽管两者之间的差别基本上是闰秒(这发生非常 罕见)。

但是,设计决定实际上是在浪费任何被认为是设计良好的API的想法。以下是一些最喜欢的错误:

  • 尽管在上个世纪的最后十年进行了设计,但自1900年以来,它的年数一直是两位数。由于这个平庸的决定,在Java世界中确实有数百万个变通方法在执行1900+(或1900-)。
  • 月被索引为零,以适应这种异常的情况:月数组,而不是十三个元素数组,其中第一个元素包含null。结果,我们有0..11(今天是109年的第11个月)。为了转换为字符串,在月份中有类似数量的++和-。
  • 他们是可变的。结果,任何时候您想要返回一个日期(例如,作为实例结构),都需要返回该日期的副本而不是日期对象本身(否则,人们可以更改您的结构)。
  • Calendar,旨在“修复”这一点,实际上使同样的错误。他们仍然是可变的。
  • Date代表DateTime,但是为了顺应SQL领域的需求,还有另一个子类java.sql.Date,代表了一天(尽管没有与之关联的时区)。
  • 没有TimeZone与关联的Date,因此范围(例如“全天”)通常表示为午夜至午夜(通常在任意时区)

最后,值得注意的是,leap秒通常会在一个小时内用ntp更新的良好系统时钟进行自我校正(请参见下面的链接)。在引入两个leap跃秒(最少每六个月,实际上每隔几年)的情况下,系统仍无法正常运行的可能性,尤其是考虑到必须不时重新部署新版本的代码这一事实。即使使用重新生成类或诸如WAR引擎之类的动态语言,也会污染类空间并最终耗尽permgen。


43

JSR 310在Java 8 中用java.time替换了旧的日期时间类,原始JSR中证明了自己的理由,如下所示:

2.5建议的规范将满足Java社区的哪些需求?

当前,Java SE具有两个单独的日期和时间API-java.util.Date和java.util.Calendar。Java开发人员在Weblog和论坛上一致认为这两个API难以使用。值得注意的是,两个月都使用零索引,这是许多错误的原因。多年来,Calendar还遭受了许多错误和性能问题,这主要是由于内部以两种不同方式存储了其状态。

一个经典错误(4639407)阻止了在Calendar对象中创建某些日期。可以编写一系列代码,这些代码可以在几年内创建日期,而不能在其他年份内创建日期,从而导致某些用户无法输入正确的出生日期。这是由Calendar类引起的,夏季仅允许夏令时增加一小时,而从历史上看,第二次世界大战前后的夏令时增加了两小时。尽管此错误已得到修复,但如果将来某个时候某个国家/地区选择在夏季增加三小时的夏令时,那么Calendar类将再次被破坏。

当前的Java SE API在多线程环境中也受到影响。不可变类由于其状态无法更改而具有固有的线程安全性。但是,日期和日历都是可变的,这要求程序员明确考虑克隆和线程化。此外,DateTimeFormat中缺乏线程安全性尚未广为人知,并且已成为导致许多难以追踪线程问题的原因。

除了Java SE在日期时间上存在的类问题之外,它还没有用于建模其他概念的类。非时区日期或时间,持续时间,期间和间隔在Java SE中没有类表示形式。结果,开发人员经常使用int表示持续时间,而javadoc指定了单位。

缺乏全面的日期和时间模型也导致许多常见的操作比应有的操作更为棘手。例如,计算两个日期之间的天数是当前特别困难的问题。

该JSR将解决完整的日期和时间模型的问题,包括日期和时间(带和不带时区),持续时间和时间段,间隔,格式和解析。


28
  • 日期实例是可变的,几乎总是很不方便。
  • 它们具有双重性质。它们既代表时间戳又代表日历日期。事实证明,在对日期进行计算时这是有问题的。
  • 日历数据的数字表示在许多情况下是违反直觉的。例如:getMonth()从零开始,getYear()从1900开始(即2009年表示为109)。
  • 他们缺少了您期望从Date课堂上获得的许多功能。

13

我为您感到...作为前.NET程序员,我问了同样的问题,.NET中的时间API(时间跨度,运算符重载)非常方便。

首先,要创建特定日期,请使用已弃用的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);

要找出两个日期之间相隔的时间(以天/周/月为单位),情况会变得更糟

但是,来自apache()的DateUtilsorg.apache.commons.lang.time.DateUtils提供了一些便捷的方法,最近我发现自己仅使用它们

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


请请告诉我们如何操作(“找出两个日期之间经过了多少时间”)!
安东·戈戈列夫

我希望我知道一个简单的方法...包括leap年,jump月和虚弱的日子...
Eran Medan 2009年

1
另请参见org.apache.commons.lang.time:commons.apache.org/lang//api/org/apache/commons/lang/time/…–
垃圾桶

@AntonGogolev在java.time中,使用PeriodDuration类分别以年-月-日-天和小时-分钟-秒的比例来计算和表示经过的时间。
罗勒·布尔克

4

老实说,我发现Java的Date API可用。大多数我见过和听说过的问题涉及到冗长,需要涉及多个类做任何有用的(CalendarDateDateFormat/ SimpleDateFormat),以及缺乏简单的存取等getDayOfWeek()

Joda Time是Java中备受推崇的替代API,在“为什么Joda Time”部分中,它提供了更多有关为什么它是一种可能令人感兴趣的替代方案的论据。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.