Javadate与日历

有人可以build议围绕DateCalendartypes目前的“最佳做法”。

在编写新代码时,是否最好始终支持Calendar ,还是在某些情况下, Date是更合适的数据types?

date是一个更简单的类,主要是出于向下兼容性的原因。 如果您需要设置特定date或进行date算术,请使用日历。 日历还处理本地化。 Date的前一个date操作函数已经被弃用了。

就个人而言,我倾向于使用毫秒为单位的时间(或适当的时间长)或日历(如果有select的话)。

date和日历都是可变的,这在使用API​​时往往会出现问题。

新代码(如果您的政策允许第三方代码)的最佳方式是使用乔达时间库 。

date和日历都有这么多的devise问题,对于新代码来说都不是很好的解决scheme。

  • DateCalendar实际上是相同的基本概念(都代表瞬间的时间 ,是一个基本的long价值的包装)。

  • 人们可以争辩说, Calendar实际上比Date更为破碎 ,因为它似乎提供了有关诸如星期几和时间之类的事情的具体事实,而如果您更改其时timeZone属性,那么具体变成了牛奶冻! 由于这个原因,这两个对象都不是真正有用的年,月 时间存储。

  • 只能使用Calendar作为计算器,当给定DateTimeZone对象时,将为您做计算。 避免将其用于在应用程序中input属性。

  • 使用SimpleDateFormatTimeZoneDate一起生成显示string。

  • 如果你觉得冒险使用Joda-Time,虽然它是不必要的复杂的恕我直言,并很快被JSR-310dateAPI取代在任何情况下。

  • 我之前已经回答说,推出自己的YearMonthDay类并不困难,该类使用Calendar来进行date计算。 我被这个build议压低了,但是我仍然相信这是一个有效的build议,因为Joda-Time (和JSR-310 )对于大多数使用情况来说确实太复杂了。

date最适合存储date对象。 这是一个持续的,序列化的…

日历最适合操作date。

注意:我们有时也赞成java.lang.Long over Date,因为Date是可变的,因此不是线程安全的。 在Date对象上,使用setTime()和getTime()在两者之间切换。 例如,应用程序中的常量Date(例如:1970年1月1日的零,或者设置为2099年12月31日的应用程序END_OF_TIME;将空值replace为开始时间和结束时间非常有用,尤其是当你坚持他们在数据库中,因为SQL是特殊的空值)。

Date应作为不可改变的时间点使用; Calendar是可变的,如果您需要与其他课程协作来提供最终date,可以传递和修改日历。 把它们看作类似于StringStringBuilder ,你会明白我应该如何使用它们。

(是的,我知道date实际上不是技术上不可变的,但意图是它不应该是可变的,如果没有人调用已废弃的方法,那么它是这样的)。

如果可能,我通常使用Date。 虽然它是可变的,但实际上已经不赞成了。 最后,它基本上会包含一个很长的代表date/时间。 相反,如果我必须操纵这些值,我会使用日历。

你可以这样想:只有在需要使用StringBuffer的时候,你才可以轻松地操纵它们,然后使用toString()方法将它们转换成string。 以同样的方式,如果我需要操作时态数据,我只使用日历。

为了最佳实践,我倾向于尽可能在域模型之外使用不可变对象。 它显着减less了任何副作用的机会,而且这是由编译器完成的,而不是JUnittesting。 您可以通过在课堂中创build私人最终字段来使用此技巧。

并回到StringBuffer的比喻。 以下是一些代码,显示如何在日历和date之间进行转换

 String s = "someString"; // immutable string StringBuffer buf = new StringBuffer(s); // mutable "string" via StringBuffer buf.append("x"); assertEquals("someStringx", buf.toString()); // convert to immutable String // immutable date with hard coded format. If you are hard // coding the format, best practice is to hard code the locale // of the format string, otherwise people in some parts of Europe // are going to be mad at you. Date date = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2001-01-02"); // Convert Date to a Calendar Calendar cal = Calendar.getInstance(); cal.setTime(date); // mutate the value cal.add(Calendar.YEAR, 1); // convert back to Date Date newDate = cal.getTime(); // assertEquals(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2002-01-02"), newDate); 

对于Java 8,应该使用新的java.time包 。

对象是不可变的,时区和日光节约考虑在内。

你可以像这样从一个旧的java.util.Date对象创build一个ZonedDateTime对象:

  Date date = new Date(); ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault()); 

我总是提倡乔达时间 。 这是为什么。

  1. 该API是一致的和直观的。 与java.util.Date/Calendar API不同
  2. 它不会遇到线程问题,而不像java.text.SimpleDateFormat等(我已经看到许多客户端问题与没有意识到标准的date/时间格式不是线程安全的)
  3. 它是新的Javadate/时间API( JSR310 ,计划用于Java 8)的基础。因此,您将使用将成为核心Java API的API。

晚会有点晚,但Java在JDK 8中有一个新的Date Time API。您可能需要升级您的JDK版本并拥抱该标准。 没有更多杂乱的date/日历,没有更多的第三方jar子。

TL;博士

build议DateCalendar周围的当前“最佳做法”

是最好总是赞成Calendar

完全避免这些遗留类 。 改用java.time类。

  • 在UTC一会儿,使用Instant
    (相当于Date的现代)
  • 在特定时间段内 ,使用ZonedDateTime
    (现代相当于GregorianCalendar
  • 在UTC的特定偏移量中 ,使用OffsetDateTime
    (在传统课程中没有相应的)
  • 对于具有未知时区或偏移量的date时间(不是片刻),请使用LocalDateTime
    (在传统课程中没有相应的)

细节

回答Ortomala Lokni是正确的build议使用现代java.time类而不是麻烦的旧的遗留date时间类( DateCalendar等)。 但是那个答案提出了错误的类作为等价物(参见我对这个答案的评论)。

使用java.time

java.time类相对于传统的date时间类,夜晚的差异有了很大的改进。 旧的class级devise不好,令人困惑,麻烦。 只要有可能,你应该避免旧的类。 但是当你需要转换/从旧/新,你可以通过调用新的方法添加到旧的类。

有关转换的更多信息,请参阅我的答案和漂亮的图到另一个问题, 将java.util.Date转换为什么“java.time”types? 。

search堆栈溢出给出了使用java.time的数百个示例问题和解答。 但是这是一个快速的简介。

Instant

立即获取当前时刻。 Instant类表示UTC时间轴上的一个时刻,分辨率为纳秒 (最多九(9)位小数)。

 Instant instant = Instant.now(); 

ZonedDateTime

要通过某个特定区域的挂钟时间的镜头查看同一时刻 ,请应用时区( ZoneId )以获取ZonedDateTime

时区

America/MontrealAfrica/CasablancaPacific/Aucklandcontinent/region的格式指定适当的时区名称 。 切勿使用3-4字母缩写(如ESTIST因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

 ZoneId z = ZoneId.of( "America/Montreal" ); ZonedDateTime zdt = instant.atZone(); 

抵消

时区是一个区域的与UTC的偏移量变化的历史logging。 但是有时候只有在没有完整区域的情况下才会给出偏移量。 在这种情况下,使用OffsetDateTime类。

 ZoneOffset offset = ZoneOffset.parse( "+05:30" ); OffsetDateTime odt = instant.atOffset( offset ); 

使用时区比使用单纯的偏移更可取。

LocalDateTime

地方上的“地方”类是指任何地方,不是特定的地方。 所以这个名字可能是反直觉的。

LocalDateTimeLocalDateLocalTime故意缺less关于偏移或时区的任何信息。 所以他们不代表实际的时刻,他们不是时间线上的要点。 如有疑问或疑惑,请使用ZonedDateTime而不是LocalDateTime 。 search堆栈溢出了更多的讨论。

string

不要将date – 时间对象与表示其值的string混合在一起。 您可以parsing一个string来获取date时间对象,并且可以从date时间对象中生成一个string。 但是string从来不是date时间本身。

了解标准的ISO 8601格式,在java.time类中默认使用。

date应该重新开发。 它不应该是一个长整数,而应该把年,月,日,时,分,秒作为单独的字段。 存储此date所关联的日历和时区可能甚至是不错的。

在我们的自然对话中,如果在2013年11月1日纽约时间下午1点设置约会,这是一个DateTime。 这不是一个日历。 所以我们也应该可以在Java中像这样交谈。

当Date被存储为一个长整数(1970年1月1日之后的毫秒),计算它的当前date取决于日历。 不同的日历会给出不同的date。 这是从给予绝对时间的预期(例如Big Bang之后1万亿秒)。 但是我们通常也需要一个方便的对话方式,比如一年一个月的对象等。

我想知道Java是否有新的进展来协调这两个目标。 也许我的Java知识太旧了。

顺便说一句“date”通常被标记为“过时/弃用”(我不知道到底是为什么) – 关于它的东西写在那里Java:为什么不build议使用Date构造函数,而是我用什么?

它看起来像只是构造函数的问题,通过新的date(INT年,INT月,INT天) ,推荐的方式是通过日历和分别设置PARAMS ..( 日历CAL = Calendar.getInstance();