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

时间:2011-04-15 13:25:15

标签: java date deprecated

我来自C#世界,所以对Java还没有太多经验。刚刚被Eclipse告知Date已被弃用。

Person p = new Person();
p.setDateOfBirth(new Date(1985, 1, 1));

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

14 个答案:

答案 0 :(得分:227)

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();

看看日期Javadoc:

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

答案 1 :(得分:91)

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

答案 2 :(得分:62)

TL;博士

LocalDate.of( 1985 , 1 , 1 )

...或...

LocalDate.of( 1985 , Month.JANUARY , 1 )

详细

当Java首次启动和发展时,java.util.Datejava.util.Calendarjava.text.SimpleDateFormat类的速度过快。这些课程没有很好地设计或实施。尝试了改进,因此您发现了弃用。不幸的是,改进的尝试基本上失败了你应该完全避免这些类。它们在Java 8中被新类取代。

您的代码中的问题

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

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

约达时间

用Java学习的第一件事:避免臭名昭着的java.util.Date& Java捆绑的java.util.Calendar类

正如the answer by user3277382中正确指出的那样,在Java 8中使用Joda-Time或新的java.time.* package

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

转储到控制台...

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

跑步时......

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

java.time

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

我们获得一个时区(ZoneId),并构建一个分配给该时区的日期时间对象(ZonedDateTime)。然后使用Immutable Objects模式,我们根据旧对象的同一时刻(自epoch以来的纳秒数)创建新的日期时间,但指定了其他时区。最后,我们得到一个LocalDate,它没有时间或时区,但是在确定该日期时注意到时区适用(Oslo中的新日期早于New York中的新日期例子)。

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();

关于 java.time

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

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

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

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 3 :(得分:11)

我将此问题视为a newer question的副本,其中询问了在特定年份,月份和日期获取Date的未弃用方法是什么。

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

LocalDate localDate = LocalDate.of(1985, 1, 1);

然后,如果您确实需要java.util.Date,则可以使用this question中的建议。

有关详细信息,请查看{8}的the APIthe tutorials

答案 4 :(得分:10)

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

  

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

请注意,年份字段是自1900以来的年数,因此您的示例代码很可能无法按照您的预期执行操作。这就是重点。

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

CalendarGregorianCalendar API优于Date,第三方Joda-time API通常被认为是最好的。在Java 8中,他们引入了java.time包,现在推荐这些包。

答案 5 :(得分:8)

请注意Calendar.getTime()日期部分默认为当前时间的意义上是不确定的。

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

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

输出例如:

Sun Mar 07 10:46:21 CET 2010

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

Sun Mar 07 10:57:51 CET 2010

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

答案 6 :(得分:6)

Date本身并未弃用。这只是它的很多方法。 See here for details

改为使用java.util.Calendar

答案 7 :(得分:5)

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

Java 8但是会​​有一个新的java.time.* package。请参阅此文Introducing the New Date and Time API for JDK 8

答案 8 :(得分:2)

我从Secure Code Guideline for Java那里得到了

本节中的示例按原样广泛使用java.util.Date 可变API类的示例。在一个应用程序中,它将是 最好使用新的Java日期和时间API(java.time。*),该API 被设计为不可变的。

答案 9 :(得分:1)

与binnyb建议的类似,您可以考虑使用较新的日历> GregorianCalendar方法。请参阅这些最近的文档:

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

答案 10 :(得分:1)

通过使用new Date(year,month,date)类,可以在代码中创建类似于Calendar的方法。

private Date getDate(int year,int month,int date){
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.YEAR, year);
    cal.set(Calendar.MONTH, month-1);
    cal.set(Calendar.DAY_OF_MONTH, day);
    return cal.getTime();
}

它将像已弃用的Date

一样工作

答案 11 :(得分:1)

不建议使用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

答案 12 :(得分:0)

new GregorianCalendar(1985, Calendar.JANUARY, 1).getTime();

(Java-8之前的方式)

答案 13 :(得分:0)

Date构造函数期望以1900年以来的年份格式,从零开始的月份,并将小时/分钟/秒/毫秒设置为零。

Date result = new Date(year, month, day);

因此,对于已过时的Date构造函数使用Calendar替换(从零开始的年份,从零开始的月份,从一个开始的日子),我们需要类似以下内容:

Calendar calendar = Calendar.getInstance();
calendar.clear(); // Sets hours/minutes/seconds/milliseconds to zero
calendar.set(year + 1900, month, day);
Date result = calendar.getTime();

或使用Java 1.8(年份从零开始,月份和日期从一开始):

Date result = Date.from(LocalDate.of(year + 1900, month + 1, day).atStartOfDay(ZoneId.systemDefault()).toInstant());

以下是日期,日历和Java 1.8的相同版本:

int year = 1985; // 1985
int month = 1; // January
int day = 1; // 1st

// Original, 1900-based year, zero-based month, one-based day
Date date1 = new Date(year - 1900, month - 1, day);

// Calendar, zero-based year, zero-based month, one-based day
Calendar calendar = Calendar.getInstance();
calendar.clear(); // Sets hours/minutes/seconds/milliseconds to zero
calendar.set(year, month - 1, day);
Date date2 = calendar.getTime();

// Java-time back to Date, zero-based year, one-based month, one-based day
Date date3 = Date.from(LocalDate.of(year, month, day).atStartOfDay(ZoneId.systemDefault()).toInstant());

SimpleDateFormat format = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss.SSS");

// All 3 print "1985-Jan-01 00:00:00.000"
System.out.println(format.format(date1));
System.out.println(format.format(date2));
System.out.println(format.format(date3));