Java:为什么不推荐使用Date构造函数,而是使用什么呢?

Svi*_*ish 194 java date deprecated

我来自C#世界,所以对Java还没有太多经验.Eclipse刚刚告诉他们Date已经弃用了.

Person p = new Person();
p.setDateOfBirth(new Date(1985, 1, 1));
Run Code Online (Sandbox Code Playgroud)

为什么?应该使用什么(特别是在上面的情况下)呢?

Buf*_*alo 237

java.util.Date班实际上没有过时,只是构造,与其他几个构造函数/方法已过时一起.它被弃用了,因为这种用法不适用于国际化.该Calendar级应使用:

Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1988);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
Date dateRepresentation = cal.getTime();
Run Code Online (Sandbox Code Playgroud)

看一下Javadoc的日期:

http://download.oracle.com/javase/6/docs/api/java/util/Date.html

  • +一个用于提供有效的解决方案 (7认同)
  • *“应该使用 Calendar 类”* - 对于 Java 8 及更高版本,“java.time.*”类是更好的选择...如果您要更改代码。 (3认同)
  • 这应该是最好的答案。谢谢。 (2认同)
  • 只是补充一下,这将考虑默认时区。如果我们想指定任何其他时区,我们可以使用 `Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(<timezone id>));` (2认同)

Rub*_*ben 94

不推荐使用特定的Date构造函数,而应使用Calendar.JavaDoc for Date描述了不推荐使用的构造函数以及如何使用Calendar替换它们.

  • 日历需要一个额外的对象,并且像8行更多的代码来做同样的事情,从我可以告诉我创建一个Date对象.当你只需要一个日期而不是时区调整变量时,这是令人困惑的,似乎是不必要的. (19认同)
  • 仅供参考,非常麻烦的旧日期时间类,例如[`java.util.Date`](https://docs.oracle.com/javase/10/docs/api/java/util/Date.html),[ `java.util.Calendar`](https://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html)和`java.text.SimpleDateFormat`现在[legacy]( https://en.wikipedia.org/wiki/Legacy_system),由[* java.time *](https://docs.oracle.com/javase/10/docs/api/java/time/package- summary.html)Java 8及更高版本中内置的类。请参见[* Oracle的Tutorial *](https://docs.oracle.com/javase/tutorial/datetime/TOC.html)。 (4认同)

Bas*_*que 68

TL;博士

LocalDate.of( 1985 , 1 , 1 )
Run Code Online (Sandbox Code Playgroud)

…要么…

LocalDate.of( 1985 , Month.JANUARY , 1 )
Run Code Online (Sandbox Code Playgroud)

细节

java.util.Date,java.util.Calendarjava.text.SimpleDateFormat班级被送往太快时的Java首次推出和发展.这些课程没有很好地设计或实施.尝试了改进,因此您发现了弃用.不幸的是,改进的尝试基本上失败了 你应该完全避免这些类.它们在Java 8中被新类所取代.

你的代码中的问题

java.util.Date同时具有日期和时间部分.您忽略了代码中的时间部分.因此,Date类将按照JVM的默认时区定义的一天开始,并将该时间应用于Date对象.因此,代码的结果将根据其运行的机器或设置的时区而有所不同.可能不是你想要的.

如果您只想要日期,没有时间部分,例如出生日期,您可能不想使用Date对象.您可能只想以ISO 8601格式存储日期字符串YYYY-MM-DD.或者使用LocalDateJoda-Time中的对象(见下文).

乔达时间

首先要学习Java:避免使用与Java捆绑在一起的臭名昭着的java.util.Date和java.util.Calendar类.

正如user3277382答案中正确指出的那样,在Java 8中使用Joda-Time或新的java.time.*包.

Joda-Time 2.3中的示例代码

DateTimeZone timeZoneNorway = DateTimeZone.forID( "Europe/Oslo" );
DateTime birthDateTime_InNorway = new DateTime( 1985, 1, 1, 3, 2, 1, timeZoneNorway );

DateTimeZone timeZoneNewYork = DateTimeZone.forID( "America/New_York" );
DateTime birthDateTime_InNewYork = birthDateTime_InNorway.toDateTime( timeZoneNewYork ); 

DateTime birthDateTime_UtcGmt = birthDateTime_InNorway.toDateTime( DateTimeZone.UTC );

LocalDate birthDate = new LocalDate( 1985, 1, 1 );
Run Code Online (Sandbox Code Playgroud)

转储到控制台......

System.out.println( "birthDateTime_InNorway: " + birthDateTime_InNorway );
System.out.println( "birthDateTime_InNewYork: " + birthDateTime_InNewYork );
System.out.println( "birthDateTime_UtcGmt: " + birthDateTime_UtcGmt );
System.out.println( "birthDate: " + birthDate );
Run Code Online (Sandbox Code Playgroud)

跑的时候......

birthDateTime_InNorway: 1985-01-01T03:02:01.000+01:00
birthDateTime_InNewYork: 1984-12-31T21:02:01.000-05:00
birthDateTime_UtcGmt: 1985-01-01T02:02:01.000Z
birthDate: 1985-01-01
Run Code Online (Sandbox Code Playgroud)

java.time

在这种情况下,java.time的代码几乎与Joda-Time的代码相同.

我们得到一个时区(ZoneId),并构造一个分配给该时区(ZonedDateTime)的日期时间对象.然后使用不可变对象模式,我们根据旧对象的同一时刻(自纪元以来的纳秒数)创建新的日期时间,但指定了其他时区.最后我们得到一个LocalDate没有时间或时区但是在确定该日期时注意时区适用(例如,在奥斯陆的新日期比在纽约早些时候开始).

ZoneId zoneId_Norway = ZoneId.of( "Europe/Oslo" );
ZonedDateTime zdt_Norway = ZonedDateTime.of( 1985 , 1 , 1 , 3 , 2 , 1 , 0 , zoneId_Norway );

ZoneId zoneId_NewYork = ZonedId.of( "America/New_York" );
ZonedDateTime zdt_NewYork = zdt_Norway.withZoneSameInstant( zoneId_NewYork );

ZonedDateTime zdt_Utc = zdt_Norway.withZoneSameInstant( ZoneOffset.UTC );  // Or, next line is similar.
Instant instant = zdt_Norway.toInstant();  // Instant is always in UTC.

LocalDate localDate_Norway = zdt_Norway.toLocalDate();
Run Code Online (Sandbox Code Playgroud)

关于java.time

java.time框架是建立在Java 8和更高版本.这些类取代麻烦的老传统日期时间类,如java.util.Date,Calendar,和SimpleDateFormat.

现在处于维护模式Joda-Time项目建议迁移到java.time类.

要了解更多信息,请参阅Oracle教程.并搜索Stack Overflow以获取许多示例和解释.规范是JSR 310.

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

从哪里获取java.time类?

ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类Interval,YearWeek,YearQuarter,和更多.

  • 道具实际上提到了根本原因并提供了所有可用替代品的覆盖范围. (5认同)

Ste*_*n C 11

不推荐使用构造函数的一个原因是year参数的含义不是您所期望的.javadoc说:

从JDK 1.1版开始,替换为Calendar.set(year + 1900, month, date).

请注意,年份字段是此后的年数1900,因此您的示例代码很可能无法按预期执行.这就是重点.

通常,DateAPI仅支持现代西方日历,具有特殊指定的组件,并且如果设置字段则行为不一致.

CalendarGregorianCalendarAPI是比好Date,和第三方乔达时间的API被普遍认为是最好的.在Java 8中,他们介绍了java.time这些软件包,现在推荐这些软件包.


Kev*_*man 11

我发现这个问题是一个较新问题的副本,该问题询问了Date在特定年份,月份和日期的非弃用方式.

到目前为止,答案是使用Calendar该类,直到Java 8出现之前都是如此.但是从Java 8开始,执行此操作的标准方法是:

LocalDate localDate = LocalDate.of(1985, 1, 1);
Run Code Online (Sandbox Code Playgroud)

然后,如果你真的需要一个java.util.Date,你可以使用这个问题中的建议.

有关更多信息,请查看API或Java 8 的教程.


Tij*_*ter 8

请注意,Calendar.getTime()白天时间部分默认为当前时间的意义上,这是不确定的.

要重现,请尝试多次运行以下代码:

Calendar c = Calendar.getInstance();
c.set(2010, 2, 7); // NB: 2 means March, not February!
System.err.println(c.getTime());
Run Code Online (Sandbox Code Playgroud)

输出例如:

Sun Mar 07 10:46:21 CET 2010
Run Code Online (Sandbox Code Playgroud)

几分钟后运行完全相同的代码会产生:

Sun Mar 07 10:57:51 CET 2010
Run Code Online (Sandbox Code Playgroud)

因此,虽然set()强制对应字段来更正值,但它会泄漏其他字段的系统时间.(上面用Sun jdk6&jdk7测试过)


Mik*_*sen 6

Date本身并没有被弃用.这只是它的很多方法.详情请见此处.

java.util.Calendar改用.


Div*_*mar 6

由于 Date 构造函数已被弃用,您可以尝试此代码。

import java.util.Calendar;

  Calendar calendar = Calendar.getInstance();
     calendar.set(Calendar.HOUR_OF_DAY, 6);// for 6 hour
     calendar.set(Calendar.MINUTE, 0);// for 0 min
     calendar.set(Calendar.SECOND, 0);// for 0 sec
     calendar.set(1996,0,26);// for Date [year,month(0 to 11), date]

    Date date = new Date(calendar.getTimeInMillis());// calendar gives long value

    String mConvertedDate = date.toString();// Fri Jan 26 06:00:00 GMT+05:30 1996
Run Code Online (Sandbox Code Playgroud)

  • 这些糟糕的类现在已成为遗留问题,多年前已被 JSR 310 中定义的 *java.time* 类取代。在 2019 年建议“日期”和“日历”是个糟糕的建议。 (2认同)

dav*_*ain 5

大多数Java开发人员目前使用第三方软件包Joda-Time.它被广泛认为是一种更好的实施方式.

但是Java 8将有一个新的java.time.*包.请参阅本文,介绍JDK 8的新日期和时间API.