web-dev-qa-db-ja.com

Java日付けとカレンダー

誰かがDateCalendar型に関する現在の「ベストプラクティス」についてアドバイスしてもらえますか。

新しいコードを書くとき、常にCalendarよりDateを優先するのが最善ですか、それともDateがより適切なデータ型である状況がありますか?

348
Marty Pitt

Dateはより単純なクラスであり、主に下位互換性の理由からそこにあります。特定の日付を設定したり日付計算をしたりする必要がある場合は、カレンダーを使用してください。カレンダーはローカライズも扱います。 Dateの以前の日付操作関数はそれ以来推奨されていません。

個人的には、選択肢がある場合は、ミリ秒単位の時間をロング(または適宜、ロング)またはカレンダーとして使用する傾向があります。

DateとCalendarはどちらも変更可能であり、APIで使用すると問題が発生する傾向があります。

368
cletus

新しいコードのための最善の方法は(あなたのポリシーがサードパーティのコードを許可している場合) Joda Time library を使うことです。

DateCalendar のどちらにも、設計上の問題が非常に多いので、どちらも新しいコードに対する良い解決策ではありません。

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

  • Calendarは実際にはDateよりもさらに壊れていると主張する人もいるでしょう。 timeZoneプロパティを変更すると、具象はblancmangeに変わります。このため、どちらのオブジェクトも年月日または時刻の保管場所としては実際には役に立ちません。

  • CalendarDateおよびTimeZoneオブジェクトが与えられたときに計算を行う計算機としてのみ使用してください。アプリケーションでのプロパティの入力には使用しないでください。

  • 表示文字列を生成するには、SimpleDateFormatTimeZoneおよびDateを一緒に使用します。

  • 不必要に複雑な私見であり、いずれにせよJSR-310日付APIに取って代わられることになっていますが、冒険的にJoda-Timeを使っているのであれば。

  • 私は、日付計算のためにYearMonthDayをフードの下で使用する独自のCalendarクラスをロールバックすることは難しくないと以前に答えました。私はその提案に賛成しませんでしたが、 Joda-Time (および JSR-31 )はほとんどのユースケースで非常に複雑すぎるため、有効なものであると私は考えています。 。

54
oxbow_lakes

日付は日付オブジェクトを格納するのに最適です。それは永続化されたもの、直列化されたものです...

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

注:Dateは可変であり、スレッドセーフではないため、DateよりもJava.lang.Longを優先することもあります。 Dateオブジェクトでは、setTime()とgetTime()を使って両者を切り替えます。たとえば、アプリケーション内の定数Date(例:ゼロの1970/01/01、または2099/12/31に設定したアプリケーションのEND_OF_TIME。特に開始時刻と終了時刻としてNULL値を置き換える場合に非常に便利です) SQLはNULLで非常に独特であるため、データベースにそれらを保持する場合。

25
KLE

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

あなたはそれをこのように考えることができます:あなたがあなたが簡単に操作することができてそれからtoString()メソッドを使ってそれらをStringsに変換することができる必要があるときだけStringBufferを使います。同様に、テンポラルデータを操作する必要がある場合にのみカレンダーを使用します。

ベストプラクティスのために、私はドメインモデルの外側でできるだけ不変オブジェクトを使う傾向があります。これは、あらゆる副作用の可能性を大幅に減らし、JUnitテストではなく、コンパイラによって行われます。このテクニックは、クラス内にprivate finalフィールドを作成することによって使用します。

そして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);
17

Datesは、不変の時点として使用する必要があります。 Calendarsは変更可能で、最終日を出すために他のクラスと共同作業する必要がある場合は、受け渡して変更することができます。それらがStringStringBuilderに似ていると考えてください、そして私はそれらがどのように使われるべきであると考えるかを理解するでしょう。

(そして、確かに、Dateは実際には技術的に不変ではないことを知っていますが、意図は変更不可能であるべきではないということです。

15
Andrzej Doyle

tl; dr

DateCalendarに関する現在の「ベストプラクティス」をアドバイスする

常にCalendarよりDateを優先するのが最善です。

これらの従来のクラスを完全に避けてください。代わりに Java.time クラスを使用してください。

  • しばらくの間 UTC には、 Instant を使用してください。
    Dateと現代の同等語)
  • しばらくの間 タイムゾーン の場合は、 ZonedDateTime を使用します。
    GregorianCalendarと現代の同等語)
  • しばらくの間は TCからのオフセット を使用してください。 OffsetDateTime
    (従来のクラスでは同等)
  • タイムゾーンまたはオフセットが不明な日時(瞬間ではない)の場合は、 LocalDateTime を使用します。
    (従来のクラスでは同等)

詳細

Ortomalaによる回答 Lokniは、厄介な古い従来の日時クラス(DateCalendarなど)ではなく、最新の Java.time クラスを使用することをお勧めします。しかし、その答えは、間違ったクラスが同等であると示唆しています(その答えに対する私のコメントを参照してください)。

Java.timeを使う

Java.timeクラスは、従来の日時クラスと比べて、 大幅な の改善、昼と夜の違いがあります。古いクラスは、デザインがよくなく、混乱しやすく、面倒です。可能な限り古いクラスを避けるべきです。しかし、古い/新しいから/に変換する必要があるときは、新しいメソッドadd//を追加して old クラスに変換することで変換できます。

変換に関するより多くの情報については、 私の答えと気の利いた図 を他の質問に、 Java.util.Dateを“ Java.time”型に変換する? を参照してください。

スタックオーバーフローを検索すると、Java.timeの使用に関する質問と回答の例が多数あります。しかし、これは簡単な概要です。

Instant

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

Instant instant = Instant.now();

ZonedDateTime

ある特定の地域のレンズを通して同じ同時モーメント壁時計時間 を見るには、タイムゾーン( ZoneId )を適用します ZonedDateTime を取得してください。

タイムゾーン

continent/regionAmerica/Montreal 、またはAfrica/Casablancaのように、 正しいタイムゾーン名Pacific/Aucklandの形式で指定します。 ESTISTなどの3〜4文字の省略形は、 not trueタイムゾーンであり、標準化されておらず、一意でもありません(!)。

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

オフセット

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

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

単なるオフセットの使用よりもタイムゾーンの使用の方が好ましいです。

LocalDateTime

Local…クラスの“ Local”は any localityを意味し、特定のlocalityを意味しません。そのため、名前は直感的にわかりにくい場合があります。

LocalDateTimeLocalDate、およびLocalTimeには、オフセットまたはタイムゾーンに関する情報が意図的に欠けています。したがって、それらは実際の瞬間を表す not ではなく、タイムライン上の not ポイントです。疑わしい場合や混乱している場合は、ZonedDateTimeではなくLocalDateTimeを使用してください。より多くの議論についてはスタックオーバーフローを検索してください。

文字列

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

Java.timeクラスでデフォルトで使用されている標準の ISO 8601 フォーマットについて学んでください。


Java.time について

Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、 Java.util.DateCalendar 、& SimpleDateFormat のような、面倒な古い レガシー 日時クラスに代わるものです。

Joda-Time プロジェクトは、現在 メンテナンスモード になっており、 Java.time クラスへの移行を推奨しています。

詳細は、 Oracle Tutorial を参照してください。そして多くの例と説明についてはStack Overflowを検索してください。指定は JSR 31 です。

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

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

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

ThreeTen-Extra プロジェクトは、追加クラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性があることを証明するものです。 IntervalYearWeekYearQuartermore などの便利なクラスがあります。

11
Basil Bourque

Java 8では、新しい Java.timeパッケージ を使うべきです。

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

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

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

私はいつも擁護しています Joda-time 。これが理由です。

  1. aPIは一貫性があり直感的です。 Java.util.Date/Calendar APIとは異なり
  2. Java.text.SimpleDateFormat などとは異なり、スレッドの問題に悩まされることはありません(標準の日付/時刻フォーマットがスレッドセーフではないことを認識していないことに関連するクライアントの問題が多数あります)
  3. これは、新しいJava日付/時刻API( JSR31 、Java 8用にスケジュールされたもの)の基礎です。したがって、コアJava APIになるAPIを使用することになります。

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

9
Brian Agnew

ちょっと遅くなりましたが、JavaにはJDK 8の新しいDate Time APIがあります。あなたのJDKバージョンをアップグレードしてその標準を受け入れることをお勧めします。これ以上面倒な日付やカレンダーはなく、サードパーティのjarもありません。

8
Silviu Burcea

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

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

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

これら2つの目的を両立させるために、Javaに新しい進歩があるのではないでしょうか。私のJavaの知識は古すぎるかもしれません。

1
user2835562

私は私が私が私があなたの必要性を合わせるために日付をフォーマットする必要があるとき私が時間を動かすことのようなある特定の操作を必要とする時にカレンダーを使用する。私は今ロケールを使っています!

0
Brian Nelson

ところで、 "date"は通常 "廃止予定/非推奨"とタグ付けされています(正確には理由がわかりません) - それについて何か書かれています Java:Dateコンストラクタが推奨されないのはなぜですか?

new Date(int year、int month、int day)を介してのみコンストラクタの問題であるように見えます。方法はカレンダーを介してであり、別々にパラメータを設定します..(Calendar cal = Calendar.getInstance();

0
xxxvodnikxxx