web-dev-qa-db-ja.com

カレンダーが間違った月を返します

Calendar rightNow = Calendar.getInstance();
String month = String.valueOf(rightNow.get(Calendar.MONTH));

上記のスニペットの実行後、月の値は11ではなく10になります。どうしてですか?

94
Hant

月は1ではなく0からインデックス化されるため、10は11月、11は12月になります。

126

彼らは0から始まります-チェック ドキュメント

28
Bozho

多くの答えから明らかなように、月は0で始まります。

ヒントを次に示します。SimpleDateFormatを使用して、月の文字列表現を取得する必要があります。

Calendar rightNow = Calendar.getInstance();
Java.text.SimpleDateFormat df1 = new Java.text.SimpleDateFormat("MM");
Java.text.SimpleDateFormat df2 = new Java.text.SimpleDateFormat("MMM");
Java.text.SimpleDateFormat df3 = new Java.text.SimpleDateFormat("MMMM");
System.out.println(df1.format(rightNow.getTime()));
System.out.println(df2.format(rightNow.getTime()));
System.out.println(df3.format(rightNow.getTime()));

出力:

11
Nov
November

注:出力は異なる場合があり、ロケール固有です。

22
Bart Kiers

数人が指摘したように、Javaの-​​ Calendar および Date クラスによって返される月は、1ではなく0からインデックス付けされます。したがって、0は1月、そして今月の11月は10です。

なぜそうなのか疑問に思うかもしれません。起源は、POSIX標準関数ctimegmtime、およびlocaltimeにあります。これらは、次のフィールドを持つtime_t構造体を受け入れるか、返します(from man 3 ctime ):

int tm_mday;    /* day of month (1 - 31) */
int tm_mon;     /* month of year (0 - 11) */
int tm_year;    /* year - 1900 */

このAPIは、Java 1.0のJava Dateクラスにほぼ正確にコピーされ、そこからJava 1.1のCalendarクラスにほぼそのままコピーされました。 Sunは、Calendarを導入したときに最も目立った問題を修正しました。これは、グレゴリオ暦の2001年がDateクラスの値101で表されていたという事実です。しかし、日と月の値を少なくとも0から1のいずれかでインデックス付けの一貫性を保つように変更しなかった理由はわかりません。この矛盾と関連する混乱は、今日までJava(およびC)に残っています。

18
Matt Ryall

リストのインデックスのように、月はゼロから始まります。

したがって、1月= 0、2月= 1などです。

10
Federer

APIから:

年の最初の月は1月で、0です。最後は1年の月数に依存します。

http://Java.Sun.com/j2se/1.5.0/docs/api/Java/util/Calendar.html

8
b.roth

tl; dr

LocalDate.now()            // Returns a date-only `LocalDate` object for the current month of the JVM’s current default time zone.
         .getMonthValue()  // Returns 1-12 for January-December.

詳細

他の答えは正しいですが、時代遅れです。

面倒な古い日時クラスには、多くの貧弱な設計選択と欠陥がありました。 1つは、明らかな1〜12ではなく、0〜11の月番号のカウントです。

Java.time

Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、Java.util.Date.CalendarJava.text.SimpleDateFormatなどの古い厄介な日時クラスに取って代わります。

メンテナンスモード で、 Joda-Time プロジェクトもJava.timeへの移行を推奨しています。

詳細については、 Oracleチュートリアル を参照してください。また、Stack Overflowで多くの例と説明を検索してください。

Java.time機能の多くは、 ThreeTen-Backport のJava 6および7にバックポートされ、 ThreeTenABP のAndroidにさらに適合します。

ThreeTen-Extra プロジェクトは、クラスを追加してJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。

1〜12か月

Java.timeでは、月の数は実際には1月から12月に予想される1〜12です。

LocalDate クラスは、時刻とタイムゾーンのない日付のみの値を表します。

タイムゾーン

タイムゾーンは、日付を決定する際に重要です。どのような場合でも、日付はゾーンごとに世界中で異なります。たとえば、 Paris France の真夜中から数分後の新しい日は、 MontréalQuébec の「昨日」のままです。

continent/regionAmerica/Montreal 、またはAfrica/Casablancaなど、 適切なタイムゾーン名Pacific/Aucklandの形式で指定します。 ESTISTなどの3〜4文字の略語をnotとして使用しないでください。真のタイムゾーンであり、標準化されておらず、一意(!)でもありません。

LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) );
int month = today.getMonthValue();  // Returns 1-12 as values.

タイムゾーンの日付時刻が必要な場合は、ZonedDateTimeオブジェクトを同じ方法で使用します。

ZonedDateTime now = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );
int month = now.getMonthValue();  // Returns 1-12 as values.

レガシークラスを変換する

GregorianCalendar オブジェクトを手に持っている場合、古いクラスに追加された新しい ZonedDateTime メソッドを使用してtoZonedDateTimeに変換します。変換情報の詳細については、 Java.util.Dateを「Java.time」型に変換しますか? を参照してください。

ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime();
int month = zdt.getMonthValue();  // Returns 1-12 as values.

Month enum

ちなみに、Java.timeクラスには便利な Monthenum が含まれています。単なる整数ではなくコードでこのクラスのインスタンスを使用して、コードをより自己文書化し、 type-safety を提供し、有効な値を確保します。

Month month = today.getMonth();  // Returns an instant of `Month` rather than integer.

Month enumは、月のローカライズ名 を使用してStringを生成するなどの便利なメソッドを提供します


Java.timeについて

Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、 Java.util.DateCalendar 、および SimpleDateFormat などの厄介な古い legacy 日時クラスに取って代わります。

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

詳細については、 Oracleチュートリアル を参照してください。また、Stack Overflowで多くの例と説明を検索してください。仕様は JSR 31 です。

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

  • Java SE 8Java SE 9 、およびそれ以降
    • ビルトイン。
    • バンドル実装を備えた標準Java APIの一部。
    • Java 9は、いくつかのマイナーな機能と修正を追加します。
  • Java SE 6 and Java SE 7
    • Java.time機能の多くは、 ThreeTen-Backport のJava 6および7にバックポートされています。
  • Android

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

7
Basil Bourque
_cal.get(Calendar.MONTH) + 1;
_

上記のステートメントは、月の正確な数を示します。 get(Calendar.Month)は0から始まる月を返すため、結果に1を追加すると正しい出力が得られます。また、月を設定するときは1を引くことに注意してください。

_cal.set(Calendar.MONTH, (8 - 1));
_

または、提供されている定数変数を使用します。

_cal.set(Calendar.MONTH, Calendar.AUGUST);
_
3
krishnadhar

使用する方が良いでしょう

Calendar.JANUARY

これはゼロです...

0
Maher Abuthraa