Javadate与日历
有人可以build议围绕Date
和Calendar
types目前的“最佳做法”。
在编写新代码时,是否最好始终支持Calendar
,还是在某些情况下, Date
是更合适的数据types?
date是一个更简单的类,主要是出于向下兼容性的原因。 如果您需要设置特定date或进行date算术,请使用日历。 日历还处理本地化。 Date的前一个date操作函数已经被弃用了。
就个人而言,我倾向于使用毫秒为单位的时间(或适当的时间长)或日历(如果有select的话)。
date和日历都是可变的,这在使用API时往往会出现问题。
新代码(如果您的政策允许第三方代码)的最佳方式是使用乔达时间库 。
date和日历都有这么多的devise问题,对于新代码来说都不是很好的解决scheme。
-
Date
和Calendar
实际上是相同的基本概念(都代表瞬间的时间 ,是一个基本的long
价值的包装)。 -
人们可以争辩说,
Calendar
实际上比Date
更为破碎 ,因为它似乎提供了有关诸如星期几和时间之类的事情的具体事实,而如果您更改其时timeZone
属性,那么具体变成了牛奶冻! 由于这个原因,这两个对象都不是真正有用的年,月或日 时间存储。 -
只能使用
Calendar
作为计算器,当给定Date
和TimeZone
对象时,将为您做计算。 避免将其用于在应用程序中input属性。 -
使用
SimpleDateFormat
与TimeZone
和Date
一起生成显示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,可以传递和修改日历。 把它们看作类似于String
和StringBuilder
,你会明白我应该如何使用它们。
(是的,我知道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());
我总是提倡乔达时间 。 这是为什么。
- 该API是一致的和直观的。 与java.util.Date/Calendar API不同
- 它不会遇到线程问题,而不像java.text.SimpleDateFormat等(我已经看到许多客户端问题与没有意识到标准的date/时间格式不是线程安全的)
- 它是新的Javadate/时间API( JSR310 ,计划用于Java 8)的基础。因此,您将使用将成为核心Java API的API。
晚会有点晚,但Java在JDK 8中有一个新的Date Time API。您可能需要升级您的JDK版本并拥抱该标准。 没有更多杂乱的date/日历,没有更多的第三方jar子。
TL;博士
build议
Date
和Calendar
周围的当前“最佳做法”是最好总是赞成
Calendar
完全避免这些遗留类 。 改用java.time类。
- 在UTC一会儿,使用
Instant
(相当于Date
的现代) - 在特定时间段内 ,使用
ZonedDateTime
(现代相当于GregorianCalendar
) - 在UTC的特定偏移量中 ,使用
OffsetDateTime
(在传统课程中没有相应的) - 对于具有未知时区或偏移量的date时间(不是片刻),请使用
LocalDateTime
(在传统课程中没有相应的)
细节
回答Ortomala Lokni是正确的build议使用现代java.time类而不是麻烦的旧的遗留date时间类( Date
, Calendar
等)。 但是那个答案提出了错误的类作为等价物(参见我对这个答案的评论)。
使用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/Montreal
, Africa/Casablanca
, Pacific/Auckland
等continent/region
的格式指定适当的时区名称 。 切勿使用3-4字母缩写(如EST
或IST
因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
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
地方上的“地方”类是指任何地方,不是特定的地方。 所以这个名字可能是反直觉的。
LocalDateTime
, LocalDate
和LocalTime
故意缺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(); )