Java: Why is the Date constructor deprecated, and

2019-01-03 12:51发布

I come from the C# world, so not too experienced with Java yet. Was just told by Eclipse that the Date was deprecated.

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

Why? And what (especially in cases like above) should be used instead?

11条回答
走好不送
2楼-- · 2019-01-03 13:25

tl;dr

LocalDate.of( 1985 , 1 , 1 )

…or…

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

Details

The java.util.Date, java.util.Calendar, and java.text.SimpleDateFormat classes were rushed too quickly when Java first launched and evolved. The classes were not well designed or implemented. Improvements were attempted, thus the deprecations you’ve found. Unfortunately the attempts at improvement largely failed. You should avoid these classes altogether. They are supplanted in Java 8 by new classes.

Problems In Your Code

A java.util.Date has both a date and a time portion. You ignored the time portion in your code. So the Date class will take the beginning of the day as defined by your JVM’s default time zone and apply that time to the Date object. So the results of your code will vary depending on which machine it runs or which time zone is set. Probably not what you want.

If you want just the date, without the time portion, such as for a birth date, you may not want to use a Date object. You may want to store just a string of the date, in ISO 8601 format of YYYY-MM-DD. Or use a LocalDate object from Joda-Time (see below).

Joda-Time

First thing to learn in Java: Avoid the notoriously troublesome java.util.Date & java.util.Calendar classes bundled with Java.

As correctly noted in the answer by user3277382, use either Joda-Time or the new java.time.* package in Java 8.

Example Code in 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 );

Dump to console…

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

When run…

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

In this case the code for java.time is nearly identical to that of Joda-Time.

We get a time zone (ZoneId), and construct a date-time object assigned to that time zone (ZonedDateTime). Then using the Immutable Objects pattern, we create new date-times based on the old object’s same instant (count of nanoseconds since epoch) but assigned other time zone. Lastly we get a LocalDate which has no time-of-day nor time zone though notice the time zone applies when determining that date (a new day dawns earlier in Oslo than in New York for example).

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

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

查看更多
Bombasti
3楼-- · 2019-01-03 13:28

One reason that the constructor is deprecated is that the meaning of the year parameter is not what you would expect. The javadoc says:

As of JDK version 1.1, replaced by Calendar.set(year + 1900, month, date).

Notice that the year field is the number of years since 1900, so your sample code most likely won't do what you expect it to do. And that's the point.

In general, the Date API only supports the modern western calendar, has idiosyncratically specified components, and behaves inconsistently if you set fields.

The Calendar and GregorianCalendar APIs are better than Date, and the 3rd-party Joda-time APIs were generally thought to be the best. In Java 8, they introduced the java.time packages, and these are now the recommended alternative.

查看更多
▲ chillily
4楼-- · 2019-01-03 13:29

Most Java developers currently use the third party package Joda-Time. It is widely regarded to be a much better implementation.

Java 8 however will have a new java.time.* package. See this article, Introducing the New Date and Time API for JDK 8.

查看更多
Root(大扎)
5楼-- · 2019-01-03 13:34

You can make a method just like new Date(year,month,date) in your code by using Calendar class.

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

It will work just like the deprecated constructor of Date

查看更多
甜甜的少女心
6楼-- · 2019-01-03 13:35

The specific Date constructor is deprecated, and a Calendar should be used instead. The JavaDoc for Date describes which constructors are deprecated and how to replace them using a Calendar.

查看更多
登录 后发表回答