有人可以就Date
和Calendar
类型的当前“最佳做法”提供建议。
在编写新代码时,最好是始终支持Calendar
而不是Date
,还是有Date
更适合数据类型的情况?
答案 0 :(得分:368)
日期是一个更简单的类,主要是出于向后兼容的原因。如果您需要设置特定日期或进行日期算术,请使用日历。日历还处理本地化。之前的Date日期操作函数已被弃用。
就个人而言,我倾向于使用任何时间(以毫秒为单位)作为长(或适当的长)或日历。
日期和日历都是可变的,在API中使用时往往会出现问题。
答案 1 :(得分:66)
新代码的最佳方式(如果您的政策允许使用第三方代码)是使用Joda Time library。
答案 2 :(得分:53)
Date
和Calendar
实际上是相同的基本概念(两者都代表即时并且是基础long
值的包装器) 。
有人可能认为 Calendar
实际上比Date
更加破碎,因为它似乎提供了关于诸如星期几等事情的具体事实。一天中的时间,而如果你改变它的timeZone
属性,混凝土会变成白痴!由于这个原因,这两个对象都不能用作年月日或时间的存储。
仅将Calendar
用作计算器,当给定Date
和TimeZone
个对象时,它将为您进行计算。避免将其用于应用程序中的属性输入。
与SimpleDateFormat
和TimeZone
一起使用Date
生成显示字符串。
如果你喜欢冒险使用Joda-Time,虽然它是不必要的复杂恕我直言,并且很快就会被JSR-310 date API取代。
我之前已经回答过,推出自己的YearMonthDay
课程并不困难,该课程使用Calendar
进行日期计算。我对该建议进行了投票,但我仍然认为它是有效的,因为Joda-Time(和JSR-310)对于大多数用例而言实际上过于复杂。
答案 3 :(得分:25)
日期最适合存储日期对象。它是持久的,序列化的......
日历最适合操纵日期。
注意:我们有时也喜欢java.lang.Long而不是Date,因为Date是可变的,因此不是线程安全的。在Date对象上,使用setTime()和getTime()在两者之间切换。例如,应用程序中的常量日期(示例:零1970/01/01,或者您设置为2099/12/31的应用END_OF_TIME;那些将空值替换为开始时间和结束时间非常有用,尤其是当你将它们保存在数据库中时,因为SQL对于空值非常特殊。)
答案 4 :(得分:17)
如果可能,我通常会使用日期。尽管它是可变的,但实际上不推荐使用mutators。最后它基本上包裹了一个代表日期/时间的长。相反,如果我必须操纵值,我会使用Calendars。
你可以这样想:只有当你需要拥有可以轻松操作的字符串然后使用toString()方法将它们转换为字符串时,才使用StringBuffer。同样,如果我需要操作时态数据,我只使用日历。
对于最佳实践,我倾向于在域模型之外尽可能多地使用不可变对象。它显着降低了任何副作用的机会,它由编译器为您完成,而不是JUnit测试。您可以通过在班级中创建私人最终字段来使用此技术。
回到StringBuffer比喻。以下是一些代码,向您展示如何在日历和日期之间进行转换
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);
答案 5 :(得分:15)
Date
应该用作不可变时间点; Calendar
是可变的,如果您需要与其他类协作以提出最终日期,则可以传递并修改。考虑它们类似于String
和StringBuilder
,您将理解我认为应该如何使用它们。
(是的,我知道Date实际上并不是技术上不可变的,但意图是它不应该是可变的,如果没有调用已弃用的方法那么它就是这样。)
答案 6 :(得分:11)
建议围绕
的当前“最佳做法”Date
和Calendar
最好始终支持
Calendar
而不是Date
完全避免使用这些遗留类。请改用java.time类。
Instant
Date
)ZonedDateTime
GregorianCalendar
)OffsetDateTime
LocalDateTime
Answer by Ortomala Lokni建议使用现代java.time课程,而不是麻烦的旧遗留日期时间课程(Date
,Calendar
等)。但是那个答案表明错误的等级是等同的(参见我对该答案的评论)。
java.time类是对遗留日期时间类,日夜差异的浩大改进。旧课程设计糟糕,令人困惑,麻烦。你应该尽可能避免使用旧课程。但是当您需要转换为旧/新转换时,可以通过调用添加到旧类的新方法来实现。
有关转化的更多信息,请参阅my Answer and nifty diagram至另一个问题Convert java.util.Date to what “java.time” type?。
使用java.time搜索Stack Overflow提供了数百个示例问题和解答。但这是一个快速概要。
Instant
使用Instant
获取当前时刻。 Instant
类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。
Instant instant = Instant.now();
ZonedDateTime
要通过特定区域wall-clock time的镜头看到相同的同时片刻,请应用时区(ZoneId
)以获得ZonedDateTime
。< / p>
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用诸如EST
或IST
之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone();
时区是其offset-from-UTC区域变化的历史记录。但有时你只给出一个没有完整区域的偏移量。在这种情况下,请使用OffsetDateTime
类。
ZoneOffset offset = ZoneOffset.parse( "+05:30" );
OffsetDateTime odt = instant.atOffset( offset );
使用时区优于仅使用偏移量。
LocalDateTime
Local…
类中的“本地”表示任何位置,而不是特定的位置。所以这个名字可能违反直觉。
LocalDateTime
,LocalDate
和LocalTime
故意缺少有关偏移或时区的任何信息。所以他们不代表实际时刻,他们在时间轴上不点。如有疑问或混淆,请使用ZonedDateTime
而不是LocalDateTime
。搜索Stack Overflow以进行更多讨论。
不要将日期时间对象与表示其值的字符串混淆。您可以解析字符串以获取日期时间对象,并且可以从日期时间对象生成字符串。但字符串永远不是日期时间本身。
了解标准ISO 8601格式,默认情况下在java.time类中使用。
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和&amp; SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
使用符合JDBC driver或更高版本的JDBC 4.2,您可以直接与数据库交换 java.time 对象。不需要字符串也不需要java.sql。* classes。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 7 :(得分:10)
With Java 8, the new java.time package should be used.
Objects are immutable, time zones and day light saving are taken into account.
You can create a ZonedDateTime
object from an old java.util.Date
object like this:
Date date = new Date();
ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());
答案 8 :(得分:9)
我总是提倡Joda-time。这就是原因。
编辑:如果可以迁移到Java 8,Java 8引入的Java日期/时间类现在是首选解决方案
答案 9 :(得分:8)
派对上有点晚了,但是Java在JDK 8中有一个新的Date Time API。您可能希望升级JDK版本并接受标准。没有更多凌乱的日期/日历,没有更多的第三方罐子。
答案 10 :(得分:1)
应重新制定日期。它应该将年,月,日,小时,分钟,秒作为单独的字段,而不是长整数。存储与此日期相关联的日历和时区可能更加出色。
在我们的自然对话中,如果在2013年11月1日纽约时间下午1点设置预约,这是一个DateTime。它不是日历。所以我们也应该能够在Java中以这样的方式进行交谈。
当日期存储为长整数(自1970年1月1日以来的mili秒或其他内容)时,计算其当前日期取决于日历。不同的日历会给出不同的日期。这是出于绝对时间(例如大爆炸后1万亿秒)的前景。但通常我们也需要一种方便的对话方式,比如封装年,月等的对象。
我想知道Java是否有新的进展来协调这两个目标。也许我的java知识太旧了。
答案 11 :(得分:0)
顺便说一句“日期”通常被标记为“过时/弃用”(我不确切知道为什么) - 关于它的一些东西写在那里 Java: Why is the Date constructor deprecated, and what do I use instead?
通过 新日期(int year,int month,int day) 看起来只是构造函数的问题,推荐的方法是通过Calendar和set params分开..( 日历cal = Calendar.getInstance(); )
答案 12 :(得分:0)
当需要在日期上进行一些特定的操作(例如时间推移)时,我会使用“日历”,但是“日期”在您需要格式化日期以适应您的需求时会很有帮助,最近我发现“语言环境”有很多有用的操作,方法。所以我现在正在使用语言环境!