有人能建议当前的“最佳实践”围绕日期和日历类型。

在编写新代码时,最好总是使用Calendar而不是Date,还是在某些情况下Date是更合适的数据类型?


当前回答

Date最适合存储日期对象。它是持久化的,序列化的…

日历是操作日期的最佳工具。

注意:我们有时也更喜欢java.lang.Long而不是Date,因为Date是可变的,因此不是线程安全的。在Date对象上,使用setTime()和getTime()在两者之间切换。例如,应用程序中的一个常量Date(例如:0 1970/01/01,或应用程序的END_OF_TIME,您设置为2099/12/31;这些对于替换null值作为开始时间和结束时间非常有用,特别是当您在数据库中持久化它们时,因为SQL对null非常特殊)。

其他回答

对于新代码(如果您的策略允许第三方代码),最好的方法是使用Joda Time库。

日期和日历都有很多设计问题,它们都不是新代码的好解决方案。

Date是一个更简单的类,主要是为了向后兼容。如果需要设置特定的日期或进行日期计算,请使用Calendar。日历也处理本地化。date之前的日期操作函数已弃用。

就我个人而言,如果有选择的话,我倾向于使用以毫秒为单位的时间作为long(或long,视情况而定)或Calendar。

Date和Calendar都是可变的,这在API中使用时往往会出现问题。

日期应该用作不可变的时间点;日历是可变的,如果您需要与其他类协作以得出最终日期,则可以传递和修改日历。把它们看作类似于String和StringBuilder,您就会理解我认为应该如何使用它们。

(是的,我知道Date实际上在技术上不是不可变的,但目的是它不应该是不可变的,如果没有调用已弃用的方法,那么它就是不可变的。)

顺便说一句,“日期”通常被标记为“过时/弃用”(我不知道确切的原因)-关于它的一些东西写在那里 Java:为什么日期构造函数弃用,我用什么代替?

看起来这是一个构造函数的问题-方法通过新日期(int年,int月,int日),推荐的方法是通过日历和设置参数分开。(Calendar cal = Calendar. getinstance (); )

博士tl;

建议当前的“最佳实践”围绕日期和日历 日历比日期更好吗

完全避免这些遗留类。使用java。而是时间类。

在UTC中,暂时使用Instant(现代版的Date) 在特定的时区,使用ZonedDateTime(现代版的GregorianCalendar) 在特定的offset-from-UTC中,使用OffsetDateTime(在遗留类中没有等效内容) 对于时区或偏移量未知的date-time(不是moment),使用LocalDateTime(在遗留类中没有等效内容)

细节

Ortomala Lokni的回答是正确的,建议使用现代java。时间类,而不是麻烦的旧遗留日期-时间类(日期、日历等)。但这个答案暗示了一个错误的等价类(见我对那个答案的评论)。

使用java.time

java。时间类是对传统日期-时间类的巨大改进。旧的类设计很差,令人困惑,而且很麻烦。您应该尽可能避免使用旧的类。但是,当您需要从旧类/新类转换或从旧类/新类转换时,可以通过调用添加到旧类的新方法来实现。

有关转换的更多信息,请参阅我的回答和另一个问题的漂亮图表,将java.util. date转换为什么“java. util. date”。时间”类型?。

搜索Stack Overflow提供了数百个关于使用java.time的示例问题和答案。但这里有一个快速的概要。

即时

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

Instant instant = Instant.now();

分区日期时间

要通过某些特定地区的挂钟时间来查看同一时刻,可以应用一个时区(ZoneId)来获得一个zoneeddatetime。

时区

请指定合适的时区名称,如“America/Montreal”、“Africa/Casablanca”或“Pacific/Auckland”。不要使用3-4个字母的缩写,如EST或IST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

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

抵消

时区是一个区域相对于utc偏移量的变化历史。但有时你只得到一个偏移量而没有完整的区域。在这种情况下,使用OffsetDateTime类。

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

使用时区比仅仅使用偏移量更可取。

LocalDateTime

Local…类中的“Local”表示任何位置,而不是特定的位置。所以这个名字可能是反直觉的。

LocalDateTime、LocalDate和LocalTime故意缺乏任何关于偏移量或时区的信息。所以它们不代表实际的时刻,它们不是时间轴上的点。当有疑问或困惑时,使用zoneeddatetime而不是LocalDateTime。更多讨论请搜索Stack Overflow。

字符串

不要将日期-时间对象与表示其值的字符串合并。可以解析字符串以获得日期-时间对象,也可以从日期-时间对象生成字符串。但是字符串从来不是日期-时间本身。

了解在java中默认使用的标准ISO 8601格式。时间类。


关于java.time

java。时间框架内置于Java 8及更高版本中。这些类取代了麻烦的旧遗留日期-时间类,如java.util。日期,日历和简单日期格式。

Joda-Time项目现在处于维护模式,建议迁移到java。时间类。

要了解更多,请参阅Oracle教程。搜索Stack Overflow可以找到很多例子和解释。规范是JSR 310。

使用与JDBC 4.2或更高版本兼容的JDBC驱动程序,您可以交换java。Time对象直接使用数据库。不需要字符串或java.sql。*类。

从哪里获取java。时间类?

Java SE 8、Java SE 9以及更高版本 内置的。 带有捆绑实现的标准Java API的一部分。 Java 9增加了一些小特性并进行了修复。 Java SE 6和Java SE 7 大部分的java。时间功能在ThreeTen-Backport中向后移植到Java 6和7。 安卓 后续版本的Android捆绑实现的java。时间类。 对于早期的Android, ThreeTenABP项目适应了ThreeTen-Backport(如上所述)。参见如何使用ThreeTenABP....

ThreeTen-Extra项目扩展了java。额外的课程时间。这个项目是未来可能添加到java.time的一个试验场。你可以在这里找到一些有用的类,比如Interval、YearWeek、YearQuarter等等。