1. ホーム
  2. java

[解決済み] 1日の開始時刻と終了時刻を取得する方法を教えてください。

2022-04-30 08:17:29

質問

ある日の開始時刻と終了時刻を取得する方法を教えてください。

このようなコードは正確ではありません。

 private Date getStartOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.set(year, month, day, 0, 0, 0);
    return calendar.getTime();
}

private Date getEndOfDay(Date date) {
    Calendar calendar = Calendar.getInstance();
    int year = calendar.get(Calendar.YEAR);
    int month = calendar.get(Calendar.MONTH);
    int day = calendar.get(Calendar.DATE);
    calendar.set(year, month, day, 23, 59, 59);
    return calendar.getTime();
}

ミリ秒単位の精度ではありません。

解決方法は?

tl;dr

LocalDate                       // Represents an entire day, without time-of-day and without time zone.
.now(                           // Capture the current date.
    ZoneId.of( "Asia/Tokyo" )   // Returns a `ZoneId` object.
)                               // Returns a `LocalDate` object.
.atStartOfDay(                  // Determines the first moment of the day as seen on that date in that time zone. Not all days start at 00:00!
    ZoneId.of( "Asia/Tokyo" ) 
)                               // Returns a `ZonedDateTime` object.

一日の始まり

ある時間帯で見た今日の全長を取得します。

半開きの手法で、先頭が 包括的 であり、エンディングは 排他的 . この方法によって、最後の1秒を考慮できていないコードの欠陥が解決されます。

ZoneId zoneId = ZoneId.of( "Africa/Tunis" ) ;
LocalDate today = LocalDate.now( zoneId  ) ;

ZonedDateTime zdtStart = today.atStartOfDay( zoneId ) ;
ZonedDateTime zdtStop = today.plusDays( 1 ).atStartOfDay( zoneId ) ;

zdtStart.toString() = 2020-01-30T00:00+01:00[アフリカ/チュニジア]です。

<ブロッククオート

zdtStop.toString() = 2020-01-31T00:00+01:00[アフリカ/チュニジア]です。

同じ瞬間をUTCでご覧ください。

Instant start = zdtStart.toInstant() ;
Instant stop = zdtStop.toInstant() ;

start.toString() = 2020-01-29T23:00:00Z

<ブロッククオート

stop.toString() = 2020-01-30T23:00:00Z

ある日付をタイムゾーンではなく UTC で見た場合の全日程を知りたい場合は、次のようにします。 OffsetDateTime .

LocalDate today = LocalDate.now( ZoneOffset.UTC  ) ;

OffsetDateTime odtStart = today.atTime( OffsetTime.MIN ) ;
OffsetDateTime odtStop = today.plusDays( 1 ).atTime( OffsetTime.MIN ) ;

odtStart.toString() = 2020-01-30T00:00+18:00

odtStop.toString() = 2020-01-31T00:00+18:00

これらは OffsetDateTime オブジェクトはすでにUTCになっていますが toInstant は、定義上常にUTCであるそのようなオブジェクトが必要な場合。

Instant start = odtStart.toInstant() ;
Instant stop = odtStop.toInstant() ;

start.toString() = 2020-01-29T06:00:00Z

<ブロッククオート

stop.toString() = 2020-01-30T06:00:00Z

ヒント:このメソッドに スリーテンエクストラ をプロジェクトに追加し、その Interval クラスで、このペアの Instant オブジェクトを作成します。このクラスは、以下のような比較のための便利なメソッドを提供します。 abuts , overlaps , contains などなど。

Interval interval = Interval.of( start , stop ) ;

interval.toString() = 2020-01-29T06:00:00Z/2020-01-30T06:00:00Z

半開き

mprivatの回答 が正しいです。この方のポイントは、一日の終わりを求めるのではなく、次の日の始まりの前と比較することです。彼の考えは、ハーフオープン法と呼ばれるもので、時間のスパンに 包括的な始まり 一方 エンディングは排他的 .

  • 現在のJavaの日付時間フレームワーク(java.util.Date/Calendarと Joda-Time(ジョダタイム のミリ秒を使用します。 エポック . しかし、Java 8 では、新しい JSR 310 java.time.* クラスはナノ秒の分解能を使用します。一日の最後の瞬間のミリ秒のカウントを強制することに基づいて書かれたコードは、新しいクラスに切り替えた場合、不正確なものになります。
  • 他のソースからのデータを比較する場合、他の解像度を使用していると不具合が発生します。例えば、Unix ライブラリは通常整数秒を使用し、データベースは ポストグレス は日付-時間をマイクロ秒に解決する。
  • 夏時間の変更は深夜に行われることがあり、さらに混乱する可能性があります。

ジョダタイム 2.3では、まさにこの目的のために、その日の最初の瞬間を取得するメソッドを提供しています。 withTimeAtStartOfDay() . java.timeでも同様に。 LocalDate::atStartOfDay .

StackOverflowでquot;joda half-open"を検索してください。 をクリックすると、より多くの議論と例を見ることができます。

この投稿をご覧ください。 時間間隔などの範囲は半開放にする Bill Schneiderによるものです。

レガシーな日付-時間クラスの回避

java.util.Dateと.Calendarクラスは厄介なことで知られています。避けてください。

使用方法 java.time クラスがあります。は java.time フレームワークは、大きな成功を収めた ジョダタイム ライブラリを使用します。

java.time(ジャバタイム

java.timeフレームワークは、Java 8以降に組み込まれています。でJava 6 & 7にバックポートされています。 スリーテン-バックポート プロジェクトで、さらにAndroidに適応させた スリーテンABP プロジェクトに参加しました。

An Instant は、タイムライン上のある瞬間を UTC の解像度で ナノ秒 .

Instant instant = Instant.now();

タイムゾーンを適用して 壁掛け時計時間 を、あるロケールで表示します。

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

その日の最初の瞬間を得るには、次のようにします。 LocalDate クラスとその atStartOfDay メソッドを使用します。

ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );

ハーフオープンの手法で、翌日の最初の瞬間を取得する。

ZonedDateTime zdtTomorrowStart = zdtStart.plusDays( 1 );

現在、java.time フレームワークには Interval クラスは、Joda-Timeのために以下に説明されるようなものです。しかし スリーテン・エキストラ プロジェクトは、java.time を拡張し、さらにクラスを追加しています。このプロジェクトは、将来java.timeに追加される可能性のあるクラスのための実験場です。そのクラスの中には Interval . を構築します。 Interval のペアを渡すことで Instant オブジェクトを作成します。を取り出すことができます。 Instant から ZonedDateTime オブジェクトを作成します。

Interval today = Interval.of( zdtStart.toInstant() , zdtTomorrowStart.toInstant() );


について java.time(ジャバタイム

java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、面倒な古い レガシー のような日付時間クラスがあります。 java.util.Date , Calendar , & SimpleDateFormat .

さらに詳しく知りたい方は オラクルチュートリアル . また、Stack Overflowで検索すると、多くの例や解説が見つかります。仕様書は JSR 310 .

ジョダタイム プロジェクトは、現在 メンテナンスモード への移行を推奨しています。 Java.time クラスがあります。

を交換することができます。 java.time オブジェクトを直接データベースとやり取りすることができます。データベースと直接接続するには JDBCドライバ に準拠した JDBC 4.2 またはそれ以降であること。文字列は必要ありません。 java.sql.* クラスがあります。Hibernate 5 & JPA 2.2サポート java.time .

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


ジョダイム

UPDATE: Joda-Timeプロジェクトは現在メンテナンスモードにあり、Joda-Timeへの移行を推奨しています。 java.time クラスがあります。このセクションは履歴のためにそのまま残しています。

Joda-Timeには、様々な方法で時間のスパンを表現するための3つのクラスがあります。 Interval , Period および Duration . また Interval は、宇宙のタイムライン上で特定の始まりと終わりを持っています。これは、「1日」を表現するのに適しています。

メソッドを呼び出します。 withTimeAtStartOfDay は、時刻をゼロにするのではありません。サマータイムやその他の異常により、一日の最初の瞬間が 00:00:00 .

Joda-Time 2.3を使用したサンプルコードです。

DateTimeZone timeZone = DateTimeZone.forID( "America/Montreal" );
DateTime now = DateTime.now( timeZone );
DateTime todayStart = now.withTimeAtStartOfDay();
DateTime tomorrowStart = now.plusDays( 1 ).withTimeAtStartOfDay();
Interval today = new Interval( todayStart, tomorrowStart );

どうしても必要な場合は、java.util.Dateに変換することができます。

java.util.Date date = todayStart.toDate();