Java日期与日历

时间:2009-09-10 09:10:00

标签: java date calendar

有人可以就DateCalendar类型的当前“最佳做法”提供建议。

在编写新代码时,最好是始终支持Calendar而不是Date,还是有Date更适合数据类型的情况?

13 个答案:

答案 0 :(得分:368)

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

就个人而言,我倾向于使用任何时间(以毫秒为单位)作为长(或适当的长)或日历。

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

答案 1 :(得分:66)

新代码的最佳方式(如果您的政策允许使用第三方代码)是使用Joda Time library

DateCalendar都有很多设计问题,既不是新代码的好解决方案。

答案 2 :(得分:53)

  • DateCalendar实际上是相同的基本概念(两者都代表即时并且是基础long值的包装器) 。

  • 有人可能认为 Calendar实际上比Date 更加破碎,因为它似乎提供了关于诸如星期几等事情的具体事实。一天中的时间,而如果你改变它的timeZone属性,混凝土会变成白痴!由于这个原因,这两个对象都不能用作年月日时间的存储。

  • 仅将Calendar用作计算器,当给定DateTimeZone个对象时,它将为您进行计算。避免将其用于应用程序中的属性输入。

  • SimpleDateFormatTimeZone一起使用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是可变的,如果您需要与其他类协作以提出最终日期,则可以传递并修改。考虑它们类似于StringStringBuilder,您将理解我认为应该如何使用它们。

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

答案 6 :(得分:11)

TL;博士

  

建议围绕DateCalendar

的当前“最佳做法”      

最好始终支持Calendar而不是Date

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

  • UTC中暂时使用Instant
    (现代等效于Date
  • 在特定time zone中暂时使用ZonedDateTime
    (现代相当于GregorianCalendar
  • 在特定offset-from-UTC中暂时使用OffsetDateTime
    (旧版课程中没有相应内容)
  • 对于具有未知时区或偏移量的日期时间(不是片刻),请使用LocalDateTime
    (旧版课程中没有相应内容)

详细

Answer by Ortomala Lokni建议使用现代java.time课程,而不是麻烦的旧遗留日期时间课程(DateCalendar等)。但是那个答案表明错误的等级是等同的(参见我对该答案的评论)。

使用java.time

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/MontrealAfrica/CasablancaPacific/Auckland。切勿使用诸如ESTIST之类的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…类中的“本地”表示任何位置,而不是特定的位置。所以这个名字可能违反直觉。

LocalDateTimeLocalDateLocalTime故意缺少有关偏移或时区的任何信息。所以他们代表实际时刻,他们在时间轴上点。如有疑问或混淆,请使用ZonedDateTime而不是LocalDateTime。搜索Stack Overflow以进行更多讨论。

字符串

不要将日期时间对象与表示其值的字符串混淆。您可以解析字符串以获取日期时间对象,并且可以从日期时间对象生成字符串。但字符串永远不是日期时间本身。

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

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和&amp; SimpleDateFormat

现在位于Joda-Timemaintenance 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的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 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。这就是原因。

  1. API一致且直观。与java.util.Date/Calendar API
  2. 不同
  3. 它不会遇到线程问题,不像java.text.SimpleDateFormat等。(我看到很多客户端问题与未意识到标准日期/时间格式不是线程安全的)
  4. 它是为Java 8安排的新Java日期/时间API(JSR310的基础。因此,您将使用将成为核心Java API的API。
  5. 编辑:如果可以迁移到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)

当需要在日期上进行一些特定的操作(例如时间推移)时,我会使用“日历”,但是“日期”在您需要格式化日期以适应您的需求时会很有帮助,最近我发现“语言环境”有很多有用的操作,方法。所以我现在正在使用语言环境!