JavaRush /Java Blog /Random-JA /時間を迷わないようにする方法 - DateTime と Calendar

時間を迷わないようにする方法 - DateTime と Calendar

Random-JA グループに公開済み
こんにちは!今日は、これまでに見たことのない新しいデータ型、つまり日付の取り扱いを開始します。 時間を迷わない方法 - 日時とカレンダー - 1日付が何であるかを説明する必要はないと思います :) 原理的には、Java で現在の日付と時刻を通常の文字列で書き込むことはかなり可能です。

public class Main { 
   public static void main(String[] args) { 

       String date = "June 11, 2018"; 
       System.out.println(date); 
   } 
}
しかし、このアプローチには多くの欠点があります。このクラスはStringテキストを操作するために作成されており、適切なメソッドがあります。何らかの方法で日付を管理する必要がある場合 (たとえば、日付に 2 時間を追加する)、Stringここでは機能しません。または、たとえば、プログラムがコンソールにコンパイルされた時点の現在の日付と時刻を表示します。ここStringでも役に立ちません。コードを書いて実行している間に時間が変わり、無関係なものがコンソールに表示されます。したがって、Java では、その作成者は日付と時刻を操作するためのいくつかのクラスを提供しました。一つ目はクラスですjava.util.Date

Java 日付クラス

Java の別のパッケージにもクラスがあるため、完全な名前を付けましたjava.sql.Date。混乱しないでください!これについて最初に知っておく必要があるのは、1970 年 1 月 1 日から経過した日付をミリ秒単位で保存するということです。この日付には「Unix 時間」という別の名前もあります。非常に興味深い方法だと思いませんか? :) 2 番目に覚えておくべきことは、空のコンストラクターを使用してオブジェクトを作成した場合、結果はオブジェクトが作成された時点の現在の日付と時刻Dateになります。このようなタスクは日付形式では問題があると私たちがどのように書いたか覚えていますか? クラスはそれを簡単に解決します。 StringDate

public class Main { 
   public static void main(String[] args) { 

       Date date = new Date(); 
       System.out.println(date); 
   } 
}
このコードを数回実行すると、毎回時間がどのように変化するかがわかります :) これが可能になるのは、ミリ秒単位で保存されているためです。ミリ秒は時間の最小単位であり、それが結果が非常に正確である理由です。には別のコンストラクターがありますDate。1970 年 1 月 1 日 00:00 から必要な日付までの正確な経過ミリ秒数を指定すると、コンストラクターが作成されます。

public class Main { 
   public static void main(String[] args) { 
 
       Date date = new Date(1212121212121L); 
       System.out.println(date); 
   }
}
コンソール出力:

Fri May 30 08:20:12 MSD 2008
2008 年 5 月 30 日に入手しました。「Fri」は曜日 - 「Friday」(金曜日)、MSD - 「Moscow Daylight Saving」(モスクワ夏時間)を意味します。longミリ秒は、多くの場合、数値が に適合しないため、の形式で送信されますint。では、仕事ではどのような日付操作が必要になるでしょうか? もちろん、最も明白なことは比較です。ある日付が別の日付より遅いか早いかを判断します。これはさまざまな方法で実行できます。たとえば、 . メソッドを呼び出すとDate.getTime()、1970 年 1 月 1 日の午前 0 時から経過したミリ秒数が返されます。2 つの Date オブジェクトに対してこれを呼び出して、相互に比較してみましょう。

public class Main { 
   public static void main(String[] args) { 

       Date date1 = new Date(); 

       Date date2 = new Date(); 

       System.out.println((date1.getTime() > date2.getTime())? 
               "date1 is later than date2" : "date1 is earlier than date2"); 
   } 
}
結論:

date1 раньше date2
しかし、もっと便利な方法があります。それは、クラスDate:before()およびafter()の特別なメソッドを使用することですequals()。これらはすべて で結果を返しますboolean。このメソッドは、before()日付が引数として渡した日付よりも古いかどうかをチェックします。

public class Main { 
   public static void main(String[] args) throws InterruptedException { 

       Date date1 = new Date(); 

       Thread.sleep(2000);//приостановим работу программы на 2 секунды 
       Date date2 = new Date(); 

       System.out.println(date1.before(date2)); 
   } 
}
コンソール出力:

true
このメソッドは同様の方法で動作しafter()、日付が引数として渡した日付よりも遅いかどうかをチェックします。

public class Main { 
   public static void main(String[] args) throws InterruptedException { 

       Date date1 = new Date(); 

       Thread.sleep(2000);//приостановим работу программы на 2 секунды 
       Date date2 = new Date(); 

       System.out.println(date1.after(date2)); 
   }
}
コンソール出力:

false
この例では、2 つの日付が異なることが保証されるように、プログラムを 2 秒間スリープさせます。date1高速なコンピュータでは、と の作成間の時間がdate21 ミリ秒未満になる場合があり、その場合は と の両方がbefore()after()返しますfalseequals()しかし、そのような状況でのメソッドは戻りますtrue。結局のところ、各日付の 1970 年 1 月 1 日 00:00 から経過したミリ秒数を正確に比較します。オブジェクトは、ミリ秒単位で一致する場合にのみ等しいとみなされます。

public static void main(String[] args) { 

   Date date1 = new Date(); 
   Date date2 = new Date(); 

   System.out.println(date1.getTime()); 
   System.out.println(date2.getTime()); 

   System.out.println(date1.equals(date2)); 
}
他に注意する必要があることがあります。Oracle の Web サイトでこのクラスのドキュメントを開くと、そのメソッドとコンストラクターの多くが(「非推奨」)Dateに指定されていることがわかります。Class Date Java の作成者自身が、非推奨になったクラスの部分について次のように述べています。 「@Deprecated の注釈が付けられたプログラム要素はDeprecated通常、危険であるか、もっと良い代替手段があります。」 これは、これらの方法がまったく使用できないという意味ではありません。さらに、IDEA でそれらを使用してコードを実行しようとすると、おそらく機能するでしょう。たとえば、オブジェクトから時間数を返す非推奨のメソッドを考えてみましょう。 Date.getHours()Date

public static void main(String[] args) { 

   Date date1 = new Date(); 

   System.out.println(date1.getHours()); 

}
たとえば、コードを実行した時点の時刻が 14:21 の場合、数字の 14 が表示されます。ご覧のとおり、非推奨のメソッドには取り消し線が引かれていますが、このメソッドは非常にうまく機能します。これらのメソッドを使用して既に記述されたコードの束が壊れないように、これらのメソッドは完全には削除されませんでした。つまり、これらのメソッドは「壊れた」または「削除された」のではなく、より便利な代替手段が利用できるため、使用が推奨されないだけです。ちなみに、これについてはドキュメントに詳しく書かれています。 時間を迷わない方法 - 日時とカレンダー - 2Date クラスのほとんどのメソッドは、その改良された拡張バージョンである class に移動されましたCalendar。私たちは彼をさらに知ることになります:)

Javaカレンダー

Java 1.1 では、新しいクラス が導入されましたCalendar。彼は Java での日付の操作を以前よりも少し簡単にしました。Calendar私たちが使用するクラスの唯一の実装は、クラスですGregorianCalendar(このクラスは、世界のほとんどの国が使用するグレゴリオ暦を実装します)。その主な便利な点は、より便利な形式で日付を操作できることです。たとえば、次のことができます。
  • 現在の日付に月または日を追加します
  • その年がうるう年かどうかを確認します。
  • 個々の日付コンポーネントを取得します (たとえば、日付全体から月番号を取得します)。
  • また、その内部では非常に便利な定数システムが開発されています (その多くは以下で説明します)。
このクラスのもう 1 つの重要な違いCalendarは、定数を実装していることですCalendar.Era。日付を紀元前(「キリスト以前」 - キリストの誕生前、つまり「私たちの時代の前」) またはAC (「キリストの後」 - 「」)に設定できます。私たちの時代」)。これらすべてを例を挙げて見てみましょう。2017 年 1 月 25 日の日付のカレンダーを作成してみましょう。

public static void main(String[] args) { 

  Calendar calendar = new GregorianCalendar(2017, 0 , 25); 
}
クラス内の月Calendar(ちなみに のようなDate) は 0 から始まるため、2 番目の引数として数値 0 を渡しました。クラスを扱うときに重要なことは、これが別の日付ではなく、 カレンダーCalendarであることを理解することです。日付は、特定の期間を表す一連の数字にすぎません。そして、カレンダーは、日付を使ってさまざまなことができるデバイス全体です :) これは、Calendar オブジェクトをコンソールに出力してみると非常によくわかります。 出力: 時間を迷わない方法 - 日時とカレンダー - 3

java.util.GregorianCalendar[time=?,areFieldsSet=false,areAllFieldsSet=false,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=10800000,dstSavings=0,useDaylight=false,transitions=79,lastRule=null],firstDayOfWeek=2,minimalDaysInFirstWeek=1,ERA=?,YEAR=2017,MONTH=0,WEEK_OF_YEAR=?,WEEK_OF_MONTH=?,DAY_OF_MONTH=25,DAY_OF_YEAR=?,DAY_OF_WEEK=?,DAY_OF_WEEK_IN_MONTH=?,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=?,ZONE_OFFSET=?,DST_OFFSET=?]
どれだけの情報があるのか​​見てみましょう!カレンダーには通常の日付にはない多数のプロパティがあり、それらはすべてコンソールに出力されます (これがtoString()クラスのメソッドの動作方法ですCalendar)。仕事中に、カレンダーから単純な日付を取得する必要がある場合、つまり object Date- これはメソッドを使用して行われますCalendar.getTime()(名前は最も論理的ではありませんが、何も実行できません)。

public static void main(String[] args) { 

   Calendar calendar = new GregorianCalendar(2017, 0 , 25); 
   Date date = calendar.getTime(); 
   System.out.println(date); 
}
結論:

Wed Jan 25 00:00:00 MSK 2017
これで、カレンダーが通常の日付に「単純化」されました。次へ移りましょう。月を表す数値記号に加えて、Calendar定数も教室で使用できます。Calendar定数は、変更できない値がすでに設定されているクラスの静的フィールドです。コードの可読性が向上するため、このオプションの方が実際には優れています。

public static void main(String[] args) { 
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25); 
}
Calendar.JANUARY— 月を示す定数の 1 つ。この命名オプションを使用すると、たとえば、数字の「3」は、私たちが慣れ親しんでいる 3 番目の月である 3 月ではなく、4 月を意味することを誰も忘れることはありません。書くだけですCalendar.APRIL- それで終わりです :) すべてのカレンダー フィールド (日、月、分、秒など) は、メソッドを使用して個別に設定できますset()Calendarクラス内に各フィールドに独自の定数があり、最終的なコードが可能な限り単純になるため、これは非常に便利です。たとえば、前の例では日付を作成しましたが、現在時刻を設定しませんでした。時間を19:42:12に設定しましょう

public static void main(String[] args) { 
   Calendar calendar = new GregorianCalendar(); 
   calendar.set(Calendar.YEAR, 2017); 
   calendar.set(Calendar.MONTH, 0); 
   calendar.set(Calendar.DAY_OF_MONTH, 25); 
   calendar.set(Calendar.HOUR_OF_DAY, 19); 
   calendar.set(Calendar.MINUTE, 42); 
   calendar.set(Calendar.SECOND, 12); 

   System.out.println(calendar.getTime()); 
}
結論:

Wed Jan 25 19:42:12 MSK 2017
メソッドを呼び出しset()、定数 (変更するフィールドに応じて) とこのフィールドの新しい値を渡します。set()このメソッドは、1 つのフィールドではなく、多くのフィールドに値を設定できる一種の「スーパーセッター」であることがわかります:) クラス内の値の加算と減算は、をCalendar使用して実行されますadd()。変更したいフィールドと、現在の値から正確に加算/減算する数値を渡す必要があります。たとえば、作成した日付を 2 か月前に戻してみましょう。

public static void main(String[] args) { 
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25); 
   calendar.set(Calendar.HOUR, 19); 
   calendar.set(Calendar.MINUTE, 42); 
   calendar.set(Calendar.SECOND, 12); 

   calendar.add(Calendar.MONTH, -2);//чтобы отнять meaning - в метод нужно передать отрицательное число 
   System.out.println(calendar.getTime()); 
}
結論:

Fri Nov 25 19:42:12 MSK 2016
素晴らしい!日付を2か月前に戻しました。その結果、月だけでなく年も2017年から2016年に変わりました。日付を移動する際の現在の年の計算は、もちろん自動的に行われ、手動で制御する必要はありません。ただし、何らかの目的でこの動作を無効にする必要がある場合は、無効にすることができます。特別なメソッドを使用すると、roll()他の値に影響を与えることなく値を加算および減算できます。たとえば、次のようになります。

public static void main(String[] args) { 
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25); 
   calendar.set(Calendar.HOUR, 10); 
   calendar.set(Calendar.MINUTE, 42); 
   calendar.set(Calendar.SECOND, 12); 

   calendar.roll(Calendar.MONTH, -2); 
   System.out.println(calendar.getTime()); 
}
前の例とまったく同じことを行い、現在の日付から 2 か月を減算しました。しかし、今度はコードの動作が異なります。月は 1 月から 11 月に変わりましたが、年は 2017 年のままです。結論:

Sat Nov 25 10:42:12 MSK 2017
さらに遠く。上で述べたように、オブジェクトのすべてのフィールドはCalendar個別に取得できます。このメソッドはこれを担当しますget()

public static void main(String[] args) { 
   GregorianCalendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25); 
   calendar.set(Calendar.HOUR, 10); 
   calendar.set(Calendar.MINUTE, 42); 
   calendar.set(Calendar.SECOND, 12); 
 
   System.out.println("Year: " + calendar.get(Calendar.YEAR)); 
   System.out.println("Month: " + calendar.get(Calendar.MONTH)); 
   System.out.println("Number of the week in the month: " + calendar.get(Calendar.WEEK_OF_MONTH));// serial number of the week in the month

   System.out.println("Number: " + calendar.get(Calendar.DAY_OF_MONTH)); 

   System.out.println("Watch: " + calendar.get(Calendar.HOUR)); 
   System.out.println("Minutes: " + calendar.get(Calendar.MINUTE)); 
   System.out.println("Seconds: " + calendar.get(Calendar.SECOND)); 
   System.out.println("Milliseconds: " + calendar.get(Calendar.MILLISECOND)); 

}
結論:

Год: 2017 
Месяц: 0 
Порядковый номер недели в месяце: 4 
Число: 25 
Часы: 10 
Минуты: 42 
Секунды: 12 
Миллисекунды: 0
つまり、クラスには「スーパーセッター」に加えて、Calendar「スーパーゲッター」も存在します:) もう 1 つの興味深い点は、もちろん時代を扱うことです。日付「BC」を作成するには、フィールドを使用する必要がありますCalendar.Era 。たとえば、ハンニバルがローマ軍を破ったカンナエの戦いを示す日付を作成してみましょう。これは紀元前 216 年 8 月 2 日に起こりました。e.:

public static void main(String[] args) { 
   GregorianCalendar cannes = new GregorianCalendar(216, Calendar.AUGUST, 2); 
   cannes.set(Calendar.ERA, GregorianCalendar.BC); 

   DateFormat df = new SimpleDateFormat("dd MMM yyy GG"); 
   System.out.println(df.format(cannes.getTime())); 
}
ここでは、クラスを使用してSimpleDateFormat、よりわかりやすい形式で日付を表示しました (「GG」という文字は時代の表示を担当します)。結論:

02 авг 216 до н.э.
クラスにはCalendarさらに多くのメソッドと定数があります 。ドキュメントでそれらについて読んでください。

現在までの改行

文字列を日付に変換するには、Java ヘルパー クラスSimpleDateFormatを使用できます。これは、日付を定義した形式に変換するために必要なクラスです。 時間を迷わない方法 - 日時とカレンダー - 5つまり、これはDateFormatに非常に似ています。2 つの唯一の注目すべき違いは、SimpleDateFormat は書式設定 (日付を文字列に変換) し、文字列をロケール対応の日付に解析するために使用できるのに対し、DateFormat はロケールをサポートしていないことです。さらに、DateFormat は日付の書式設定と解析の基本サポートを提供する抽象クラスですが、SimpleDateFormat は DateFormat クラスを拡張する具象クラスです。SimpleDateFormat オブジェクトを作成し、Date をフォーマットする例は次のようになります。

SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(1212121212121L);

System.out.println(formatter.format(date));
上の例では、「yyyy-MM-dd HH:mm:ss」というパターンを使用しました。これは次のことを意味します。
  • 年は 4 桁 (yyyy)。
  • 月 (MM) は 2 桁。
  • 日 (dd) を表す 2 桁。
  • 時間を 24 時間形式 (HH) で表す 2 桁。
  • 分 (mm) を表す 2 桁。
  • 秒 (ss) を 2 桁で表します。
分離マークとパターン シンボルの順序は保持されます。コンソール出力:

2008-05-30 08:20:12
SimpleDateFormatクラス には非常に多くのテンプレート文字があります。混乱しないように、それらを表にまとめました。
シンボル 説明
G 時代 (英語ローカライズ - AD および BC) 広告
y 年(4桁の数字) 2020年
やあ 年(下2桁) 20
yyyy 年(4桁の数字) 2020年
M 月番号 (先頭のゼロなし) 8
んん 月番号 (月番号が 10 未満の場合は先頭にゼロが付きます) 04
うーん 3 文字の月の略称 (ローカライズによる) 1月
んー 完全な月名 六月
w 年間の週 (先頭のゼロなし) 4
ww 年間の週 (先頭にゼロが付きます) 04
W 月内の週 (先頭のゼロなし) 3
WW 月内の週 (先頭にゼロが付きます) 03
D 一年のうちの日 67
d 月の日 (先頭のゼロなし) 9
DD 月の日 (先頭にゼロが付きます) 09
F 月の曜日 (先頭のゼロなし) 9
FF 月の曜日 (先頭にゼロが付きます) 09
E 曜日(略称) W
ええい 曜日(フル) 金曜日
あなた 曜日番号 (先頭のゼロなし) 5
うーん 曜日の番号 (先頭にゼロが付きます) 05
ある 午前/午後マーカー 午前。
H 先行ゼロのない 24 時間形式の時間 6
HH 先頭にゼロが付いた 24 時間形式の時計 06
k 24 時間形式の時間数 18
K 12 時間形式の時間数 6
h 先頭のゼロを除いた 12 時間形式の時刻 6
ふーん 先頭にゼロを付けた 12 時間形式の時刻 06
メートル 先頭ゼロなしの分 32
んん 先頭にゼロが付いた分 32
s 先行ゼロなしの秒 十一
ss 先行ゼロ付きの秒 十一
S ミリ秒 297
z タイムゾーン EET
Z RFC 822 形式のタイムゾーン 300
パターン文字の組み合わせの例:
サンプル
dd-MM-yyyy 2020 年 1 月 11 日
yyyy-MM-dd 2019-10-01
HH:mm:ss.SSS 23:59.59.999
yyyy-MM-dd HH:mm:ss 2018-11-30 03:09:02
yyyy-MM-dd HH:mm:ss.SSS 2016-03-01 01:20:47.999
yyyy-MM-dd HH:mm:ss.SSS Z 2013-13-13 23:59:59.999 +0100
形式を少し間違えると、java.text.ParseException の所有者になる可能性があり、これはあまり楽しいことではありません。さて、 SimpleDateFormatへの短い小旅行は終わりました。Java文字列の date への変換に戻りましょう。 SimpleDateFormat はそのような機能を提供します。このプロセスを段階的に説明します。
  1. 日付を設定する必要がある行を作成します。

    
    String strDate = "Sat, April 4, 2020";
  2. 文字列内の内容と一致するテンプレートを使用して、新しいSimpleDateFormatオブジェクトを作成します(そうしないと解析できません)。

    
    SimpleDateFormat formatter = new SimpleDateFormat("EEE, MMMM d, yyyy", Locale.ENGLISH);

    ご覧のとおり、ここには Locale 引数があります。これを省略すると、デフォルトのロケールが使用されますが、必ずしも英語であるとは限りません。

    ロケールが入力文字列と一致しない場合、言語にバインドされた文字列データ ( MonAprilなど) は認識されず、たとえパターンが一致したとしても java.text.ParseException がスローされます。

    ただし、言語固有ではないテンプレートを使用している場合は、形式を指定する必要はありません。例として - yyyy-MM-dd HH:mm:ss

  3. フォーマッタを使用して日付を作成し、入力文字列から日付を解析します。

    
    try {
      Date date = formatter.parse(strDate);
      System.out.println(date);
    }
    catch (ParseException e) {
      e.printStackTrace();
    }

    コンソール出力:

    
    Sat Apr 04 00:00:00 EEST 2020

    うーん...しかし、フォーマットはもう同じではありません!

    同じフォーマットを作成するには、フォーマッタを再度使用します。

    
    System.out.println(formatter.format(date));

    コンソール出力:

    
    Sat, April 4, 2020

SimpleDateFormat とカレンダー

SimpleDateFormat を使用すると、作成したすべての Date オブジェクトと Calendar オブジェクトを後で使用できるように書式設定できます。時代を扱うという興味深い点を考えてみましょう。「BC」日付を作成するには、Calendar.Era フィールドを使用する必要があります。たとえば、ハンニバルがローマ軍を破ったカンナエの戦いを示す日付を作成してみましょう。これは紀元前 216 年 8 月 2 日に起こりました。e.:

public static void main(String[] args) {
   GregorianCalendar cannes = new GregorianCalendar(216, Calendar.AUGUST, 2);
   cannes.set(Calendar.ERA, GregorianCalendar.BC);

   DateFormat df = new SimpleDateFormat("dd MMM yyy GG");
   System.out.println(df.format(cannes.getTime()));
}
ここでは、SimpleDateFormat クラスを使用して、よりわかりやすい形式で日付を表示しました (上で示したように、文字「GG」は元号の表示を担当します)。結論:

02 авг 216 до н.э.

Java の日付形式

ここで別のケースを紹介します。この日付形式が適さないと仮定しましょう。

Sat Nov 25 10:42:12 MSK 2017
それで、ここにあります。Java 日付形式の機能を使用すると、それほど難しくなく独自の日付形式に変更できます。

public static void main(String[] args) {

   SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, d MMMM yyyy");
   Calendar calendar = new GregorianCalendar(2017, Calendar.JANUARY , 25);
   calendar.set(Calendar.HOUR, 10);
   calendar.set(Calendar.MINUTE, 42);
   calendar.set(Calendar.SECOND, 12);

   calendar.roll(Calendar.MONTH, -2);
   System.out.println(dateFormat.format(calendar.getTime()));
}
結論:

суббота, 25 Ноябрь 2017
ずっと良いですよね?:)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION