Java 日期和时间 API 有什么问题?

我经常遇到关于 JavaDate和其他与日期时间相关的类的负面反馈。成为一个。NET 开发人员,我不能完全(没有使用过他们)理解,他们实际上是错误的。

有人能解释一下吗?

33171 次浏览

我同情你,作为一个前任。NET 程序员,我问了同样的问题,时间 API 在。NET (时间跨度,运算符重载)非常方便。

首先,要创建一个特定的日期,您可以使用一个不推荐的 API,或者:

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

To subtract a day you do evil things like

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 (org.apache.commons.lang.time.DateUtils)的 DateUtils提供了一些方便的方法,我发现自己最近只使用它们

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

  • 日期实例是 易变的,这几乎总是不方便。
  • 他们有双重性格。它们表示时间戳和日历日期。事实证明,在进行日期计算时,这是有问题的。
  • 日历数据的数字表示在许多情况下是违反直觉的。例如: getMonth()是从零开始的,getYear()是从1900开始的(也就是说,2009年表示为109)。
  • 它们缺少了许多您期望从 Date类中获得的功能。

老实说,我觉得 Java 的 Date API 是可用的。我所看到和听到的大多数问题都与冗长有关,需要涉及多个类来做任何有用的事情(CalendarDateDateFormat/SimpleDateFormat) ,缺少像 getDayOfWeek()这样的简单访问器。

Joda Time is a well-respected alternative API in Java, and in the Why Joda Time section it gives some more arguments as to why it is a viable alternative that might be of interest.

JSR 310 用 Java 8中的 爪哇时间取代了旧的日期时间类,它在 原版的 JSR中证明了自己的合理性:

2.5 What need of the Java community will be addressed by the proposed 说明书?

目前,JavaSE 有两个独立的 Date and time API-java.util. Date 和 java.util.Calendar 一直被描述为难以 Java 开发人员在 weblog 和 值得注意的是,两者都使用零索引 几个月了,这是许多 日历也受到 许多错误和性能问题 年份,主要是由于储存 它的状态有两种不同的方式 在内部。

防止了一个典型的错误(4639407) 中创建的某些日期 日历对象,代码序列 could be written that could create a 在某些年份约会,但在其他年份不约会, 有阻止某些事情发生的效果 用户输入正确的 birth dates. This was caused by the 日历类只允许 日光节约时间增加一小时 in summer, when historically it was 加上2小时左右的时间 第二次世界大战,而这只虫子 现在固定,如果在某一点在 future a country chose to introduce a 日光节约时间增益 three hours in summer, then the 日历类将再次中断。

当前的 JavaSEAPI 也受到了影响 在多线程环境中。 已知不可变类是 本质上线程安全的状态 不能更改。但是,日期和 日历是可变的,这需要 程序员考虑克隆和 threading explicitly. In addition, the lack of thread-safety in DateTimeFormat 并不广为人知, 也是许多人难以 跟踪线程问题。

As well as the problems with the Java SE 用于日期时间的类, 它没有模特课程 concepts. Non-time-zone dates or times, durations, periods and 间隔没有类表示 因此,开发人员 经常使用 int 来表示 持续时间,使用 javadoc 指定单位。

缺乏一个全面的日期和 time model also results in many common 行动比他们更棘手 应该是。例如,计算 两次约会之间的天数 是一个特别困难的问题 现在。

这个 JSR 将解决 complete date and time model, 包括日期和时间 (不设时区)、持续时间及 时间周期、间隔、格式 和解析。

Java Date类。也许这是最好的例子之一,告诉我们如何不用任何语言,在任何地方做任何事情。从何说起呢?

Reading the JavaDoc might lead one to think that the developers have actually got some good ideas. It goes on about the difference between 协调世界时 and 格林威治时间 at length, despite the fact that the difference between the two is basically leap seconds (which happen 漂亮 很少).

然而,设计决策实际上浪费了作为一个设计良好的 API 的任何想法。以下是一些最常犯的错误:

  • 尽管设计于本世纪的最后十年,但自1900年以来,年份排名仅为两位数。由于这个平庸的决定,在 Java 世界中有数百万个工作区正在执行1900 + (或1900 -)。
  • 月是零索引的,以满足特殊情况下有一个月的数组,而不是生活在13个元素数组,其中第一个包含 null。结果,我们得到0。. 11(今天是109年的第11个月)。为了转换成字符串,在月份上有相似数量的 + + 和——。
  • mutable。因此,无论何时您想返回一个日期(比如说,作为一个实例结构) ,您都需要返回该日期的一个克隆,而不是 date 对象本身(因为否则,人们可能会改变您的结构)。
  • Calendar被设计用来“修复”这个问题,实际上它也犯了同样的错误,它们仍然是可变的。
  • Date代表一个 DateTime,但是为了遵从 SQL 的规则,还有另一个子类 java.sql.Date,它代表一天(尽管没有与之相关的时区)。
  • 没有与 Date相关联的 TimeZone,因此范围(例如“整天”)通常表示为午夜至午夜(通常在某个任意时区)

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