Javaの日付とカレンダー


364

誰かが現在の「ベストプラクティス」DateCalendarタイプについてアドバイスしてくれませんか。

新しいコードを書くとき、それは常に優先するのが最善であるCalendar以上Date、または事情があるDate、より適切なデータ型ですが?



2
FYI、といった面倒な古い日付時刻クラスjava.util.Datejava.util.Calendarjava.text.SimpleDateFormat取って代わら今あるレガシー、java.timeのクラス。java.time機能の多くは、ThreeTen -BackportプロジェクトのJava 6およびJava 7にバックポートされています。ThreeTenABPプロジェクトの初期のAndroidにさらに適合。ThreeTenABPの使用方法…を参照してください。
バジルブルク2018

2
FYI、ジョダタイム(別のコメントで述べた)プロジェクトは、今でメンテナンスモードへの移行を助言チームと、java.timeのクラス。Oracleによるチュートリアルを参照してください。
バジルブルク2018

回答:


377

日付はより単純なクラスであり、主に下位互換性のためにあります。特定の日付を設定したり、日付の計算を行う必要がある場合は、カレンダーを使用してください。カレンダーはローカリゼーションも処理します。以前のDateの日付操作関数は廃止されました。

個人的には、ミリ秒単位の長い時間(または必要に応じて長い時間)またはカレンダーを使用する傾向があります。

日付とカレンダーはどちらも変更可能であり、APIで使用すると問題が発生する傾向があります。


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

67

新しいコードの最善の方法(ポリシーでサードパーティのコードが許可されている場合)は、Joda Timeライブラリを使用することです。

日付カレンダーの両方に非常に多くの設計上の問題があるため、どちらも新しいコードの適切な解決策ではありません。


7
私はjoda時間を使用するという提案の2番目です。使いやすく、理解しやすく、さらに多くの機能を使用できます。
Jeroen van Bergen

30
Joda

3
それが反対投票に値するかどうかはわかりませんが、質問には答えません。コメントとしてはもっと良いかもしれません。
IcedD​​ante 2012

7
問題は、プロジェクトに単一のベンダー依存のリスクを追加するサードパーティのライブラリを使用せずに、日付とカレンダーを使用することでした。
アルキメデストラハノ2013年

3
これは、java.timeパッケージがJava 8で利用可能になるまで「最善の方法」でした
DaBlick

58
  • DateCalendar実際には同じ基本的な概念です(どちらも瞬間を表し、基になるlong値のラッパーです)。

  • 曜日や時間などの具体的な事実を提供しているように見えるので、Calendar実際よりもさらに壊れてDateいると主張することできますが、timeZoneプロパティを変更すると、コンクリートはブランマンジュになります!このため、どちらのオブジェクトも年月日または時刻のストアとしては実際には役立ちません。

  • 使用Calendarのみ与えられ、電卓などDateTimeZoneのオブジェクトは、あなたのための計算を行います。アプリケーションでのプロパティの入力には使用しないでください。

  • およびとSimpleDateFormat一緒に使用してTimeZoneDate表示文字列を生成します。

  • Joda-Timeを冒険的に使用する場合は、必要以上に複雑なIMHOであり、いずれのイベントでもすぐにJSR-310日付APIに取って代わられます。

  • YearMonthDayこれCalendarまでに、日付の計算に内部で使用する独自のクラスをロールすることは難しくないと答えました。私は提案に反対票を投じましたが、Joda -Time(およびJSR-310)はほとんどのユースケースで本当に非常に複雑であるため、それは有効なものであると私はまだ信じています。


1
JSR310の時間枠はありますか?それはJava 7で行われる予定でしたが、今はそうではないと思います。
Brian Agnew

@ブライアン-それは確かにそのメーリングリストで非常に静かになっています!
oxbow_lakes 2009

チェックするだけで非アクティブになりました。つまり、18か月でマイルストーンドラフトを公開していません:-(
Brian Agnew

メーリングリストに関する最新のコメントは7月からで、Stephenによるものなので、プロジェクトはおそらくまだ刻々と
過ぎ

同意した。Dateを不変オブジェクトとして安全に使用する方法、およびCalendarを使用してDateを操作する方法を知っている場合、ほとんどの人は安全です。マルチスレッドコードでSimpleDateFormatを使用するときは注意してください。
cwash、2010年

25

日付は日付オブジェクトを格納するのに最適です。それは永続化されたものであり、シリアライズされたものです...

カレンダーは日付の操作に最適です。

注:Dateは可変であるため、スレッドセーフではないため、Dateよりもjava.lang.Longを優先することもあります。Dateオブジェクトでは、setTime()とgetTime()を使用して2つを切り替えます。たとえば、アプリケーションでの一定の日付(例:ゼロの1970/01/01、または2099/12/31に設定したアプリケーションのEND_OF_TIME)。これらは、特に開始時刻と終了時刻としてnull値を置き換えるのに非常に役立ちます。 SQLはnullが非常に特殊であるため、データベースに永続化した場合)。


私はあなたが不変について取っていると思いますjava.lang.Long
pjp

17

私は通常、可能であれば日付を使用します。変更可能ですが、ミューテーターは実際には非推奨です。最後に、基本的には日付/時刻を表すlongをラップします。逆に、値を操作する必要がある場合は、カレンダーを使用します。

このように考えることができます。StringBufferを使用するのは、toString()メソッドを使用して簡単に操作し、それを文字列に変換できる文字列が必要な場合のみです。同様に、時間データを操作する必要がある場合にのみ、カレンダーを使用します。

ベストプラクティスとして、ドメインモデルの外ではできるだけ不変のオブジェクトを使用する傾向があります。副作用の可能性を大幅に低減し、JUnitテストではなく、コンパイラーによって行われます。この手法を使用するには、クラスにプライベート最終フィールドを作成します。

StringBufferのアナロジーに戻ります。これは、カレンダーと日付の間の変換方法を示すコードです。

String s = "someString"; // immutable string
StringBuffer buf = new StringBuffer(s); // mutable "string" via StringBuffer
buf.append("x");
assertEquals("someStringx", buf.toString()); // convert to immutable String

// immutable date with hard coded format.  If you are hard
// coding the format, best practice is to hard code the locale
// of the format string, otherwise people in some parts of Europe
// are going to be mad at you.
Date date =     new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2001-01-02");

// Convert Date to a Calendar
Calendar cal = Calendar.getInstance();
cal.setTime(date);

// mutate the value
cal.add(Calendar.YEAR, 1);

// convert back to Date
Date newDate = cal.getTime();

// 
assertEquals(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2002-01-02"), newDate);

はい、不変オブジェクトは日時の作業に意味があります。java.timeの取って代わらクラスはDate/ Calendar不変オブジェクトパターンを使用します。
バジルブルク


はい。しかし、現在このページを読んでいる人は何千人もいます。これまでに15万人を超えています。私のコメントはあなたへの批評ではなく、彼らへのメモです。
バジルブルク2018年

私が知っている、それが私が他の答えに賛成した理由です。ただし、上記の答えが必要な古いJDKに苦しむ必要がある人々もまだいます。
アルキメデストラハノ2018年

1
実際、Java 6&7にはThreeTen-Backportプロジェクトがあります。これにより、ほとんど同じjava.time機能が実質的に同じAPIで実現されます。そのため、これらのひどいレガシー日時クラスを使用する必要はありません。
バジルブルク

15

Datesは不変の時点として使用する必要があります。Calendarsは変更可能であり、他のクラスと協力して最終的な日付を決める必要がある場合は、渡したり変更したりできます。それらを類似のものStringと考えればStringBuilder、私はそれらがどのように使用されるべきであると私が考えるかを理解するでしょう。

(そして、はい、Dateは実際には技術的に不変ではないことを知っていますが、意図はそれが変更可能であってはならないことであり、非推奨のメソッドを呼び出すものがない場合はそうです。)


はい、不変オブジェクトは日時の作業に意味があります。java.timeの取って代わらクラスはDate/ Calendar不変オブジェクトパターンを使用します。具体的にInstantjava.util.Date、をZonedDateTime置き換え、Calendar/ を置き換えGregorianCalendarます。
バジルブルク

15

tl; dr

周りの現在の「ベストプラクティス」を助言Dateし、Calendar

それは常に優先するのが最善であるCalendar以上Date

これらのレガシークラスは完全に避けてください。代わりにjava.timeクラスを使用してください。

  • しばらくの間、UTCを使用します(最新のと同等)Instant
    Date
  • 一瞬、特定のタイムゾーンで使用するには、(現代のと同等)ZonedDateTime
    GregorianCalendar
  • しばらくの間、特定のUTCからのオフセットを使用します(レガシークラスには同等のものはありません)。OffsetDateTime
  • タイムゾーンまたはオフセットが不明な日時(瞬間ではない)の場合は、(従来のクラスでは同等のものはありません)LocalDateTime

モダンとレガシーの両方のJavaのすべての日時タイプの表

細部

Ortomalaによって回答 Lokniは、近代的な使用することをお勧めするのは正しいですjava.timeのクラスではなく、面倒な古いレガシー日付時刻クラス(DateCalendarなど)。しかし、その回答は、間違ったクラスを同等のものとして示唆しています(その回答に関する私のコメントを参照してください)。

java.timeの使用

java.timeクラスがある広大なレガシー日時クラス、夜と日の差に比べて改善。古いクラスは設計が不十分で、混乱し、面倒です。可能な限り、古いクラスは避けてください。ただし、古い/新しいとの間で変換を行う必要がある場合は、古いクラスに追加する新しいメソッドを呼び出すことで変換できます。

変換の詳細については別の質問への回答と気の利いた図を参照しください。java.util.Dateを「java.time」タイプに変換しますか?

Stack Overflowを検索すると、java.timeの使用に関する何百ものサンプルの質問と回答が得られます。しかし、ここに簡単な概要があります。

Instant

で現在の瞬間を取得しInstantます。このInstantクラスは、ナノ秒の分解能(小数点以下9桁まで)でUTCのタイムライン上の瞬間を表します。

Instant instant = Instant.now();

ZonedDateTime

特定の地域の実時間のレンズを通して同じ瞬間を確認するには、タイムゾーン()を適用してを取得します。ZoneIdZonedDateTime

タイムゾーン

指定適切なタイムゾーン名をの形式でcontinent/region、のようなAmerica/MontrealAfrica/CasablancaまたはPacific/Auckland。決してなど3-4文字の略称を使用していないESTか、ISTそのままではない真の時間帯ではなく、標準化、さらには一意ではありません(!)。

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone();

オフセット

タイムゾーンは、UTCからのオフセットにおける地域の変更履歴です。ただし、フルゾーンなしでオフセットのみが与えられる場合があります。その場合は、OffsetDateTimeクラスを使用してください。

ZoneOffset offset = ZoneOffset.parse( "+05:30" );
OffsetDateTime odt = instant.atOffset( offset );

時間帯の使用は、単なるオフセットの使用よりも望ましいです。

LocalDateTime

Local…クラスの「ローカル」とは、特定の場所ではなく、任意の場所を意味します。そのため、名前は直観に反する場合があります。

LocalDateTimeLocalDate、およびLocalTime意図的オフセットまたはタイムゾーンに関する情報が不足しています。だから彼らは、ないではない、実際の瞬間を表し、それらはないタイムライン上の点。疑問がある場合や混乱している場合は、ではZonedDateTimeなくを使用してくださいLocalDateTime。詳細については、スタックオーバーフローを検索してください。

文字列

日時オブジェクトをその値を表す文字列と混同しないでください。文字列を解析して日時オブジェクトを取得したり、日時オブジェクトから文字列を生成したりできます。ただし、文字列は日時そのものではありません。

java.timeクラスでデフォルトで使用される標準ISO 8601形式について学びます。


java.timeについて

java.timeのフレームワークは、Java 8に組み込まれており、後にされています。これらのクラスは面倒古い取って代わるレガシーのような日付時刻クラスをjava.util.DateCalendar、& SimpleDateFormat

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

詳細については、Oracleチュートリアルを参照してください。スタックオーバーフローで多くの例と説明を検索してください。仕様はJSR 310です。

JDBC 4.2以降に準拠したJDBCドライバーを使用すると、java.timeオブジェクトをデータベースと直接交換できます。文字列もjava.sql。*クラスも必要ありません。

java.timeクラスはどこで入手できますか?

  • Java SE 8 Java SE 9以降
    • ビルトイン。
    • 実装がバンドルされた標準Java APIの一部。
    • Java 9では、いくつかのマイナーな機能と修正が追加されています。
  • Java SE 6および Java SE 7
    • java.time機能の多くは、ThreeTen-BackportでJava 6および7にバックポートされています。
  • アンドロイド
    • それ以降のバージョンのAndroidには、java.timeクラスの実装がバンドルされています。
    • 以前のAndroidでは、ThreeTenABPプロジェクトはThreeTen-Backport(上記)を採用しています。ThreeTenABPの使用方法…を参照してください。

JavaまたはAndroidのどのバージョンで使用するjava.timeライブラリの表

ThreeTen-エクストラプロジェクトでは、追加のクラスでjava.timeを拡張します。このプロジェクトは、java.timeに将来追加される可能性があることを証明する場です。あなたはここにいくつかの有用なクラスのような見つけることがIntervalYearWeekYearQuarter、および多くを


10

Java 8では、新しいjava.timeパッケージを使用する必要があります。

オブジェクトは不変であり、タイムゾーンと夏時間を考慮します。

次のようにZonedDateTime古いjava.util.Dateオブジェクトからオブジェクトを作成できます。

    Date date = new Date();
    ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());

java.timeクラスを提案するのは良いことです。しかし、お勧めできませんLocalDateTime。そのクラスは、UTCからのオフセットとタイムゾーンに関する情報を意図的に失います。そのため、このクラスはUTCの場合と同等ではなく、割り当てられたタイムゾーンがあります。私の回答と気の利いた図を別の質問に参照しください。java.util.Dateを「java.time」タイプに変換しますか?DateCalendar
バジルブルク2017

9

私はいつもジョーダタイムを提唱してます。これが理由です。

  1. APIは一貫しており、直感的です。java.util.Date/Calendar APIとは異なり
  2. java.text.SimpleDateFormatなどとは異なり、スレッド化の問題は発生しません(標準の日付/時刻のフォーマットがスレッドセーフではないことに気付かないことに関連するクライアントの問題を数多く目にしました)。
  3. これは、新しいJava日付/時刻API(JSR310、Java 8で予定されている)の基礎です。したがって、コアJava APIになるAPIを使用します。

編集:Java 8に移行できる場合、Java 8で導入されたJava日付/時刻クラスが現在推奨されるソリューションです。


3
前回私が見たとき、JODAとJSR-310 は両方ともStephen Colebourneによって書かれたものであっても、非常に異なって見えました。そうは言っても、JODAはJSR-310が解決する日時の問題の複雑さを紹介します
oxbow_lakes

2
問題は、プロジェクトに単一のベンダー依存のリスクを追加するサードパーティのライブラリを使用せずに、日付とカレンダーを使用することでした。
アルキメデストラハノ2013年

2
私はベストプラクティスを維持することは、単にこれらのクラスを使用しないことです
Brian Agnew '11

3
java.util.DateおよびCalendarクラスに関する既知の問題を考えると、Joda-Time(またはJSR 310)を提案することが適切であり、私にとって責任があると思われます。私たちは味や美的スタイルの問題について話しているのではありません。赤い車とシルバーの車のどちらを使うべきかと尋ねられ、赤い車がタイヤがパンクし、シルバーの車がバスト式ラジエーターを持っていることがわかった場合、車を選ぶべきですか、それともタクシーを呼ぶことを勧めるべきですか?その質問への答えは、Sun / Oracleでさえそれらのジャンカーを置き去りにして新しい車を購入することを決めたので、今日明らかになるはずです:JSR 310:Date and Time API。
バジルブルク2014年

1
FYI、ジョダタイムプロジェクトは、今でメンテナンスモードへの移行を専門家の意見、java.timeのクラス。Oracleによるチュートリアルを参照してください。
バジルブルク

8

パーティーには少し遅れますが、JavaのJDK 8には新しいDate Time APIがあります。JDKのバージョンをアップグレードして、標準を採用することもできます。厄介な日付やカレンダー、サードパーティのjarファイルはもうありません。


1

日付を再開発する必要があります。長い整数ではなく、年、月、日、時、分、秒を別々のフィールドとして保持する必要があります。この日付が関連付けられているカレンダーとタイムゾーンを保存することもできます。

私たちの自然な会話では、2013年11月1日午後1時(ニューヨーク時間)に予定を設定すると、これはDateTimeになります。カレンダーではありません。したがって、Javaでもこのように会話できるはずです。

Dateが(1970年1月1日以降のミリ秒の)長整数として格納されている場合、現在の日付の計算はカレンダーに依存します。カレンダーによって日付が異なります。これは、絶対時間(ビッグバンから1兆秒後)を与えるという見通しからのものです。しかし、年、月などをカプセル化するオブジェクトのような便利な会話方法も必要になることがよくあります。

これら2つの目的を両立させるJavaの新しい進歩があるのだろうか。多分私のJavaの知識は古すぎるかもしれません。


同じ瞬間を保存できるが、異なるカレンダーシステムに基づいて異なる時間/分/日/週/年/ fooをレポートできるという事実は、長所であり短所ではありません。(複雑な)現実を反映しています。
ThrawnCA、2015年

確かに、Date再開発されました。java.time.Instantクラスに置き換えられました。そしてCalendar/ GregorianCalendarjava.time.ZonedDateTimeクラスに置き換えられました。
バジルブルク

0

Btw "date"は通常、 "obsolete / deprecated"とタグ付けされています(理由は正確にはわかりません)。そこに何かが書いてあり ます。

それはコンストラクタの問題のようです-new Date(int year、int month、int day)経由で、カレンダー経由でパラメータを個別に設定することをお勧めします..(Calendar cal = Calendar.getInstance();


0

時間を移動するなど、日付に対して特定の操作が必要な場合はカレンダーを使用しますが、日付ニーズに合わせて日付をフォーマットする必要がある場合に役立ちます。最近、ロケールには便利な操作とメソッドがたくさんあることがわかりました。私は現在ロケールを使用しています!


FYI、面倒CalendarDateクラスがで年前に取って代わられたjava.timeのクラス。Dateまたはを使用する必要はありませんCalendar。またLocale、日時オブジェクトの意味とは何の関係もありません。A Localeは、日時オブジェクトの値を表すテキストを生成する際のローカライズで使用される人間の言語と文化的規範を指定するためにのみ使用されます。
バジルブルク
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.