Java:なぜDateコンストラクターが非推奨になり、代わりに何を使用するのですか?


211

私はC#の世界出身なので、Javaの経験はあまりありません。Date廃止予定であるとEclipseから言われたばかりです:

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

どうして?そして、代わりに何を(特に上記のような場合に)使用する必要がありますか?


37
私も同様の学習曲線を経験しており、C#からJavaへと移行しています。もう1つ私を悩ませているのは、年の月は0ベースのシステム(0〜11、Jan。= 0およびDec. = 11)ですが、月の日は1ベース(1〜31)です。その1つに向かいます!
Paul Sasik、2011

2
@Paul Sasik、はい、しかし例えばCalendar.JANUARY定数があり、毎月1つあります
Diogo

5
@PaulSasik笑 うん、愚かなJava。C#からJavaおよびOMGに切り替える必要がありました。
cbmeeks 2013年


8
.Netが優れたJavaライブラリーJoda-Timeの移植版から適切な日時ライブラリー(Noda Time)を入手したため、C#の人々からのJavaについてのぎくしゃくした「笑」の発言は私を笑わせました。
バジルブルク14

回答:


97

特定のDateコンストラクターは非推奨であり、Calendar代わりに使用する必要があります。JavaDoc以下のための日付は、コンストラクタは廃止されると、使用してそれらを交換する方法について説明しますCalendar


25
Calendarは追加のオブジェクトを必要とし、8行のように、同じことを行うためにコードを追加できます。タイムゾーン調整済みの変数ではなく日付のみが必要な場合、混乱を招き、不必要に思えます。
G_V 2017年

5
以下のようなFYI、ひどく面倒な古い日付時刻クラスjava.util.Datejava.util.Calendarjava.text.SimpleDateFormat今のレガシーに取って代わられ、java.timeの Javaの8に、後に内蔵されたクラス。Oracleによるチュートリアル参照してください。
バジルブルク

250

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


2
これが最良の答えです。ありがとう。
jordaniac89

「国際化ではうまく機能しない」とは、DateにTimeZoneを割り当てることができないということですか?ありがとう
DiveInto

どの日付が文字列を解析したので、代わりに年、月、日を含む文字列を部分文字列化する必要がありますか?ほとんどの場合、そのような複雑なロジックやメソッドを追加する必要がないものには、多くの余分な手間がかかるようです。
G_V 2017年

1
追加するだけで、デフォルトのタイムゾーンが考慮されます。私たちは、他のタイムゾーンを指定したい場合は、我々は使用することができますCalendar cal = Calendar.getInstance(TimeZone.getTimeZone(<timezone id>));
ヴィカスプラサド

1
「代わりにCalendarクラスを使用する必要があります」 -Java 8以降のjava.time.*場合、コードを変更する場合はクラスがより適切なオプションです。
スティーブンC

73

tl; dr

LocalDate.of( 1985 , 1 , 1 )

…または…

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

細部

java.util.Datejava.util.Calendar、およびjava.text.SimpleDateFormatJavaが最初に起動して進化したときにクラスがあまりにも早く駆けつけました。クラスは適切に設計または実装されていませんでした。改善が試みられたため、見つかった非推奨事項。残念ながら、改善の試みはほとんど失敗しました。これらのクラスは完全に避ける必要があります。Java 8では、新しいクラスに取って代わられました。

コードの問題

java.util.Dateには、日付と時刻の両方の部分があります。コードの時間部分を無視しました。そのため、Dateクラスは、JVMのデフォルトのタイムゾーンで定義された日の初めを取り、その時間をDateオブジェクトに適用します。したがって、コードの結果は、コードが実行されるマシンまたは設定されるタイムゾーンによって異なります。おそらくあなたが望むものではありません。

誕生日だけのように、時刻部分を除いて日付だけが必要な場合は、Dateオブジェクトを使用したくない場合があります。日付の文字列のみをISO 8601形式で保存したい場合がありYYYY-MM-DDます。またはLocalDate、Joda-Timeのオブジェクトを使用します(以下を参照)。

ジョーダタイム

Javaで最初に学ぶこと:Javaにバンドルされている悪名高い厄介なjava.util.Dateおよびjava.util.Calendarクラスを避けてください

で正しく注記されているように user3277382によって答え、使用のいずれかジョダタイムや新しいjava.time。*パッケージのJava 8インチ

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のコードは、 -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.DateCalendar、& SimpleDateFormat

ジョダタイムプロジェクトは、今でメンテナンスモードへの移行をアドバイスjava.timeのクラス。

詳細については、Oracleチュートリアルを参照してください。また、スタックオーバーフローで多くの例と説明を検索してください。仕様は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-エクストラプロジェクトでは、追加のクラスでjava.timeを拡張します。このプロジェクトは、java.timeに将来追加される可能性があることを証明する場です。あなたはここにいくつかの有用なクラスのような見つけることがIntervalYearWeekYearQuarter、および多くを


5
根本的な原因を実際に言及し、利用可能なすべての代替策を網羅するための小道具。
mabi

これが正解です。Calendarクラスは避けてください。ThreeTenが最良の選択肢です
ant2009 '11

11

コンストラクタが廃止された理由の1つは、yearパラメータの意味が期待したものではないことです。javadocは言う:

JDKバージョン1.1以降は、に置き換えられましたCalendar.set(year + 1900, month, date)

年フィールドはそれ以降の年数であることに注意してください 1900ため、サンプルコードは期待どおりに動作しない可能性があります。そして、それがポイントです。

一般に、DateAPIはモダンウエスタンカレンダーのみをサポートし、特異的に指定されたコンポーネントを持ち、フィールドを設定すると一貫性のない動作をします。

CalendarそしてGregorianCalendarAPIはよりも優れているDate、とサードパーティジョダ時間のAPIは、一般的に最高であると考えられていました。Java 8ではjava.timeパッケージが導入されましたが、これらは現在推奨される代替手段です。


このソリューションは、新しい日付(年、月、日)のように時間、分、秒、ミリ秒のゼロ時間を使用しないことを除いて、うまく機能します。したがって、次のようなものが必要です。Calendar cal = Calendar.getInstance(); cal.clear(); cal.set(年+ 1900、月、日付); 日付dateRepresentation = cal.getTime();
Joel Richard Koett

11

私はこの質問に出くわしましたが、特定の年、月、日で非推奨ではない方法を取得するための新しい質問の複製ですDate

これまでの答えは、Calendarクラスを使用することでしたが、Java 8が登場するまではそうでした。しかし、Java 8以降、これを行う標準的な方法は次のとおりです。

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

そして本当に本当に必要な場合はjava.util.Dateこの質問の提案を使用できます

詳細については、Java 8のAPIまたはチュートリアルをご覧ください。


7

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で上記でテスト済み)




2

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

1
これらの恐ろしいのクラスは今レガシーで年前に取って代わられたあるjava.timeの勧めるJSR 310で定義されたクラスDateCalendar2019年が悪いアドバイスです。
バジルブルク

@BasilBourque提案に感謝します。すぐに更新するのを楽しみにしています。
Divyanshu Kumar


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


1
これらのひどく厄介なクラスは、数年前に最近のjava.timeクラス、特にInstantおよびに取って代わられましたZonedDateTime
バジルブルク2018

上記の解決策では、年に1900を追加し、月から1を減算しないでください。また、Calendar.getInstance()行の後にcal.clear()を実行して、時間/分/秒/ミリ秒がゼロになるようにする必要があります(それらはDateコンストラクタで行います)。
ジョエルリチャードコエット

1

Dateコンストラクターは、1900年からの年の形式、0から始まる月、1から始まる日を期待し、時間/分/秒/ミリ秒をゼロに設定します。

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

したがって、廃止予定のDateコンストラクターにCalendarの置き換え(ゼロベースの年、ゼロベースの月、1ベースの日)を使用するには、次のようなものが必要です。

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(ゼロベースの年と1ベースの月と日があります)を使用します。

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

1
これらの恐ろしいクラスの両方がで年前に取って代わられたjava.timeの JSR 310で定義されたクラス
バジルボーク

日付、カレンダー、Java 1.8のバージョンを表示するように回答を更新しました。
Joel Richard Koett

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.