Java:为什么不赞成使用Date构造函数,我该使用什么呢?

| 我来自C#领域,因此对Java不太熟悉。 Eclipse告诉我,不赞成
Date
Person p = new Person();
p.setDateOfBirth(new Date(1985, 1, 1));
为什么?并且应该改用什么(尤其是在上述情况下)?     
已邀请:
不赞成使用特定的“ 0”构造函数,而应改用“ 3”。 Date的
JavaDoc
描述不赞成使用哪些构造函数,以及如何使用
Calendar
替换它们。     
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     
tl; dr
LocalDate.of( 1985 , 1 , 1 )
…要么…
LocalDate.of( 1985 , Month.JANUARY , 1 )
细节 Java首次启动和发展时,
java.util.Date
java.util.Calendar
java.text.SimpleDateFormat
类赶得太快。这些类的设计或实施不正确。已尝试进行改进,因此发现了不推荐使用的地方。不幸的是,改进的尝试在很大程度上失败了。您应该完全避免这些类。在Java 8中,新类取代了它们。 代码中的问题 java.util.Date同时具有日期和时间部分。您忽略了代码中的时间部分。因此,Date类将采用JVM的默认时区定义的一天的开始,并将该时间应用于Date对象。因此,代码的结果将根据它运行的计算机或设置的时区而有所不同。可能不是您想要的。 如果只需要日期,而没有时间部分,例如出生日期,则可能不希望使用“ 0”对象。您可能只想存储日期的字符串,格式为
YYYY-MM-DD
的ISO 8601。或使用Joda-Time提供的
LocalDate
对象(请参见下文)。 乔达时代 在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 );
转储到控制台...
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
)的日期时间对象。然后使用“不可变对象”模式,我们根据旧对象的同一瞬间(自纪元以来的纳秒数)创建了新的日期时间,但分配了其他时区。最后,我们得到一个
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();
关于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类? Java SE 8,Java SE 9,Java SE 10和更高版本 内置的 标准Java API的一部分,具有捆绑的实现。 Java 9添加了一些次要功能和修复。 Java SE 6和Java SE 7 很多java.time功能都在ThreeTen-Backport中反向移植到Java 6和7。 安卓系统 更高版本的Android捆绑了java.time类的实现。 对于早期的Android(<26),ThreeTenABP项目改编了ThreeTen-Backport(如上所述)。请参阅如何使用ThreeTenABP…。 ThreeTen-Extra项目使用其他类扩展了java.time。该项目是将来可能向java.time添加内容的试验场。您可能会在这里找到一些有用的类,例如
Interval
YearWeek
YearQuarter
等。     
构造函数被弃用的原因之一是year参数的含义与您期望的不一样。 Javadoc说:   从JDK 1.1版开始,由ѭ31代替。 请注意,year字段是自
1900
以来的年数,因此您的示例代码很可能不会执行您期望的操作。这就是重点。 通常,“ 0” API仅支持现代西方日历,具有特殊指定的组件,并且如果您设置字段,则行为会不一致。
Calendar
GregorianCalendar
API比
Date
好,并且通常认为第三方Joda-time API是最好的。在Java 8中,他们引入了
java.time
软件包,现在推荐使用这些软件包。     
我遇到了这个问题,它是一个较新问题的重复,该问题询问在特定的年,月和日获得ѭ0的非弃用方式是什么。 到目前为止,这里的答案都说要使用
Calendar
类,直到Java 8出来之前都是如此。但是从Java 8开始,执行此操作的标准方法是:
LocalDate localDate = LocalDate.of(1985, 1, 1);
然后,如果您确实确实需要
java.util.Date
,则可以使用此问题中的建议。 有关更多信息,请查看API或Java 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进行了测试)     
Date
本身不被弃用。这只是它的很多方法。有关详细信息,请参见此处。 改用
java.util.Calendar
。     
当前,大多数Java开发人员都使用第三方程序包Joda-Time。人们普遍认为它是一种更好的实现。 但是,Java 8将具有新的java.time。*包。请参阅本文,介绍JDK 8的新日期和时间API。     
与binnyb建议的类似,您可以考虑使用更新的Calendar> GregorianCalendar方法。请参阅以下最新文档: http://download.oracle.com/javase/6/docs/api/java/util/GregorianCalendar.html     
通过使用
Calendar
类,可以在代码中创建类似于
new Date(year,month,date)
的方法。
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
弃用的构造函数一样工作     
由于不推荐使用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
    
new GregorianCalendar(1985, Calendar.JANUARY, 1).getTime();
(Java-8之前的方式)     
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));
    

要回复问题请先登录注册