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

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


当前回答

Java 8,新的Java。应该使用时间包。

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

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

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

其他回答

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

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

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

如果可能的话,我通常使用Date。虽然它是可变的,但实际上不推荐使用突变器。最后,它基本上包装了一个表示日期/时间的long。相反,如果我必须操作这些值,我会使用calendar。

您可以这样想:只在需要可以轻松操作的字符串时使用StringBuffer,然后使用toString()方法将它们转换为字符串。同样,我只在需要操作时态数据时使用Calendar。

为了实现最佳实践,我倾向于在域模型之外尽可能多地使用不可变对象。它极大地降低了任何副作用的可能性,并且它是由编译器代替JUnit测试完成的。可以通过在类中创建私有final字段来使用这种技术。

回到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);

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

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

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

日期应该重新开发。它不应该是一个长整数,而应该包含年、月、日、小时、分钟、秒作为单独的字段。甚至还可以存储这个日期所关联的日历和时区。

在我们平常的谈话中,如果你安排的约会时间是纽约时间2013年11月1日下午1点,这就是“约会时间”。它不是日历。所以我们在Java中也应该能够像这样交谈。

当Date存储为一个长整数(自1970年1月1日以来的毫秒数)时,计算其当前日期取决于日历。不同的日历会给出不同的日期。这是从给出绝对时间(如大爆炸后1万亿秒)的角度出发的。但通常我们也需要一种方便的对话方式,比如一个对象可以封装年、月等。

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

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

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