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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1969442/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 01:55:48  来源:igfitidea点击:

What's wrong with Java Date & Time API?

javadatetime

提问by Anton Gogolev

Very often I come across negative feedback on Java Dateand other date-time-related classes. Being a .NET developer, I cannot fully (without having used them) understand, what's actually wrong with them.

我经常遇到关于 JavaDate和其他与日期时间相关的类的负面反馈。作为 .NET 开发人员,我无法完全(没有使用过它们)理解它们究竟有什么问题。

Can anybody shed some light on this?

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

采纳答案by AlBlue

Ah, the Java Dateclass. Perhaps one of the best examples of how not to do something in any language, anywhere. Where do I begin?

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

Reading the JavaDoc might lead one to think that the developers have actually got some good ideas. It goes on about the difference between UTCand GMTat length, despite the fact that the difference between the two is basically leap seconds (which happen prettyrarely).

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

However, the design decisions really lay to waste any thought of being a well designed API. Here are some of the favourite mistakes:

然而,设计决策实际上是在浪费任何设计良好的 API 的想法。以下是一些最喜欢的错误:

  • Despite being designed in the last decade of the millennium, it rates years as two digits since 1900. There are literally millions of workarounds doing 1900+ (or 1900-) in the Java world as a result of this banal decision.
  • Months are zero indexed, to cater for the spectacularly unusual case of having an array-of-months and not living with a thirteen element array, the first of which containing a null. As a result, we have 0..11 (and today being month 11 of the year 109). There are a similar number of ++ and -- on the months in order to convert to a string.
  • They're mutable. As a result, any time you want to give a date back (say, as an instance structure) you need to return a clone of that date instead of the date object itself (since otherwise, people can mutate your structure).
  • The Calendar, designed to 'fix' this, actually makes the same mistakes. They're still mutable.
  • Daterepresents a DateTime, but in order to defer to those in SQL land, there's another subclass java.sql.Date, which represents a single day (though without a timezone associated with it).
  • There are no TimeZones associated with a Date, and so ranges (such as a 'whole day') are often represented as a midnight-midnight (often in some arbitrary timezone)
  • 尽管是在千禧年的最后十年设计的,但自 1900 年以来的年数为两位数。由于这个平庸的决定,Java 世界中有数百万种解决方法在执行 1900+(或 1900-)。
  • 月份是零索引的,以适应具有月份数组而不是包含 13 个元素数组的非常不寻常的情况,其中第一个包含null. 结果,我们有 0..11(今天是 109 年的第 11 个月)。有类似数量的 ++ 和 -- 以转换为字符串。
  • 它们是可变的。因此,任何时候您想要返回日期(例如,作为实例结构),您都需要返回该日期的副本而不是日期对象本身(否则,人们可以改变您的结构)。
  • Calendar,旨在“修复”这一点,实际上使同样的错误。它们仍然是可变的。
  • Date代表 a DateTime,但为了遵循 SQL 领域中的那些,还有另一个子类java.sql.Date,它代表一天(尽管没有与之关联的时区)。
  • 没有TimeZone与 a 相关联的 s Date,因此范围(例如“一整天”)通常表示为午夜午夜(通常在某个任意时区)

Finally, it's worth noting that leap seconds generally correct themselves against a good system clock which is updated with ntp within an hour (see links below). The chance of a system being still up and running in the introduction of two leap seconds (every six months minimum, every few years practically) is pretty unlikely, especially considering the fact that you have to redeploy new versions of your code from time to time. Even using a dynamic language which regenerates classes or something like a WAR engine will pollute the class space and run out of permgen eventually.

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

回答by Eran Medan

I feel for you... as a former .NET programmer, I asked the same questions, the time API in .NET (timespans, operator overloading) is very convenient.

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

First, to create a specific date, you use either a deprecated API, or:

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

or worse

或更糟

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

To find out how much time passed between two dates (in days / weeks / months)... it gets even worse

找出两个日期之间经过了多少时间(以天/周/月为单位)......情况变得更糟

However DateUtilsfrom apache (org.apache.commons.lang.time.DateUtils) offer some convenient methods and I found myself using only them lately

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

As Brabster wrote, Joda Time is also a good external library, but apache seems more "common" than anything else...

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

回答by waxwing

  • Date instances are mutable, which is almost always inconvenient.
  • They have a double nature. They represent both a timestamp and a calendar date. It turns out this is problematic when doing calculations on dates.
  • The numeric representations of calendar data are counter-intuitive in many cases. For example: getMonth()is zero-based, getYear()is 1900-based (i.e., the year 2009 is represented as 109).
  • They are missing a lot of functionality you expect from a Dateclass.
  • 日期实例是可变的,这几乎总是不方便的。
  • 它们具有双重性质。它们代表时间戳和日历日期。事实证明,在对日期进行计算时,这是有问题的。
  • 在许多情况下,日历数据的数字表示是违反直觉的。例如:getMonth()是从零开始,getYear()是从 1900 开始(即 2009 年表示为 109)。
  • 它们缺少您期望从Date类中获得的许多功能。

回答by brabster

I find Java's Date API usable, to be honest. Most of the issues I've seen and heard about relate to the verbosity, the need to involve multiple classes to do anything useful (Calendar, Date, DateFormat/SimpleDateFormat) and the lack of simple accessors like getDayOfWeek().

老实说,我发现 Java 的 Date API 可用。我见过和听说过的大多数问题都与冗长、需要涉及多个类来做任何有用的事情(CalendarDateDateFormat/ SimpleDateFormat)以及缺乏像getDayOfWeek().

Joda Timeis 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.

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

回答by meriton

JSR 310, which supplanted the old date-time classes with java.timein Java 8, justifies itself in the original JSRas follows:

JSR 310在 Java 8中用java.time取代了旧的日期时间类,在原始 JSR 中证明自己如下:

2.5 What need of the Java community will be addressed by the proposed specification?

Currently Java SE has two separate date and time APIs - java.util.Date and java.util.Calendar. Both APIs are consistently described as difficult to use by Java developers on weblogs and forums. Notably, both use a zero-index for months, which is a cause of many bugs. Calendar has also suffered from many bugs and performance issues over the years, primarily due to storing its state in two different ways internally.

One classic bug (4639407) prevented certain dates from being created in a Calendar object. A sequence of code could be written that could create a date in some years but not in others, having the effect of preventing some users from entering their correct birth dates. This was caused by the Calendar class only allowing a daylight savings time gain of one hour in summer, when historically it was plus 2 hours around the time of the second world war. While this bug is now fixed, if at some point in the future a country chose to introduce a daylight savings time gain of plus three hours in summer, then the Calendar class would again be broken.

The current Java SE API also suffers in multi-threaded environments. Immutable classes are known to be inherently thread-safe as their state cannot change. However, both Date and Calendar are mutable, which requires programmers to consider cloning and threading explicitly. In addition, the lack of thread-safety in DateTimeFormat is not widely known, and has been the cause of many hard to track down threading issues.

As well as the problems with the classes that Java SE has for datetime, it has no classes for modelling other concepts. Non-time-zone dates or times, durations, periods and intervals have no class representation in Java SE. As a result, developers frequently use an int to represent a duration of time, with javadoc specifying the unit.

The lack of a comprehensive date and time model also results in many common operations being trickier than they should be. For example, calculating the number of days between two dates is a particularly hard problem at present.

This JSR will tackle the problem of a complete date and time model, including dates and times (with and without time zones), durations and time periods, intervals, formatting and parsing.

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

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

一个经典错误 (4639407) 阻止在 Calendar 对象中创建某些日期。可以编写一系列代码,可以在某些年份创建日期,但不能在其他年份创建,从而防止某些用户输入正确的出生日期。这是由于 Calendar 类只允许在夏季将夏令时增加一小时,而在历史上,它是在第二次世界大战前后增加 2 小时。虽然此错误现已修复,但如果在未来某个时间某个国家/地区选择在夏季引入 3 小时的夏令时增益,那么 Calendar 类将再次被破坏。

当前的 Java SE API 也受到多线程环境的影响。众所周知,不可变类本质上是线程安全的,因为它们的状态不能改变。但是,Date 和 Calendar 都是可变的,这需要程序员明确考虑克隆和线程化。此外,DateTimeFormat 中缺乏线程安全性并不广为人知,并且已成为许多难以追踪的线程问题的原因。

除了 Java SE 的 datetime 类的问题外,它没有用于建模其他概念的类。非时区日期或时间、持续时间、周期和间隔在 Java SE 中没有类表示。因此,开发人员经常使用 int 来表示持续时间,并使用 javadoc 指定单位。

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

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