Java Dateカットオフ時間情報


120

日付と時刻の情報を含むJava Dateオブジェクトがあります。時間情報を切り捨て、時間、分、秒を切り捨てるメソッドを記述したいので、日付だけを残します。

入力例:

2008-01-01 13:15:00

期待される出力:

2008-01-01 00:00:00

ヒントはありますか?私はこのようなことをやってみました:

(timestamp / (24 * 60 * 60 * 1000)) * (24 * 60 * 60 * 1000)

しかし、タイムゾーンに問題が発生しました。

回答:


178

日付/時刻操作を行うための推奨される方法は、Calendarオブジェクトを使用することです。

Calendar cal = Calendar.getInstance(); // locale-specific
cal.setTime(dateObject);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
long time = cal.getTimeInMillis();

2
@ cletus、Dateオブジェクトから時間を削除することは可能ですか?私は2008-01-01のような純粋な日付を時間部分なしで欲しい。
2012年

2
java.util.Calendarが推奨されているとは言えません。Sun / Oracleは、Java 8のそのクラスを新しいjava.timeパッケージで置き換えました。それかJoda-Timeのどちらかを使用してください。
バジルブルク

3
カレンダーは推奨されなくなりました。参照stackoverflow.com/a/28868089/40064をあなたは、Java 8を使用している場合
ヴィムDeblauwe

2
参考までに、java.timeクラスに取って代わった、java.util.Calendar今ではレガシーなどの厄介な古い日時クラス。Oracleによるチュートリアルを参照してください。
バジルブルク2017

147

Apache Commons LangのDateUtils truncateメソッドを見たことはありますか?

Date truncatedDate = DateUtils.truncate(new Date(), Calendar.DATE);

時間要素を削除します。


9
リンクを再度更新しました(Apacheにアクセスしてください!ドキュメントを
動かさないで

6
切り捨て操作が実行されるタイムゾーンは常にローカルPCタイムゾーンであるというこのアプローチのマイナスです。そのため、UTCタイムゾーンまたはローカルタイムゾーン以外のタイムゾーンでカレンダーと日付を操作する場合、意図したとおりに日付が切り捨てられる可能性があります。
クラウド

@Cloudが指摘したように、ここにCalendarインスタンスが表示されない(それを制御できない)ため、少し緊張します:)
JaroslavZáruba17年

その方法は驚くほど長く、少なくとも2つのバグ修正がありました。
ピノ

42

ジョーダを見た?それはだ非常に日付と時刻との仕事へのより簡単かつ直感的な方法。たとえば、あなたは、(例えば)との間で変換することができ自明のLocalDateTimeLOCALDATEオブジェクト。

例(APIを説明するため)

LocalDate date = new LocalDateTime(milliseconds).toLocalDate()

さらに、日付/時刻フォーマッタのいくつかのスレッド安全性の問題を解決し、Javaで日付/時刻の問題を処理する場合に強くお勧めします。


12
そうだと思います。壊れたjava.utilクラスとの戦いではなく、より優れたライブラリを使用することをお勧めします(質問からもわかるように)
Brian Agnew

10
もちろん、JodaはJavaで日付、時刻、カレンダーを操作するためのライブラリです。それを勧めないのは義務の怠慢だろう。
Joel、

1
スレッドセーフの問題は非常に興味深いものです。この投稿は、Oracle / Hibernateエラー「IllegalArgumentException、sun.util.calendar.ZoneInfo.getOffset(ZoneInfo)、oracle.jdbc.driver.DateCommonBinder.zoneOffset(OraclePreparedStatement)」を調査していることを発見しました。これは、負荷の高いフォーラムのみで発生する別のOracleの問題について説明しています。私にとっては、Oracleに疑わしい可能性のある非jodaのものを使用させるのではなく、Jodaを使用して自分のスレッドでダウンキャストすると思います。
Mark Bennett

4
これに賛成票を投じたすべての人に反対票を投じたいと思います。質問に答えようとしない返信を+1する人は誰ですか?Jodaを使用した答えは歓迎すべき以上のものですが、これはそうではありません...
Ryan

1
@ライアンこの回答はどうして関係ないのですか?質問は、時刻なしの日付を尋ねました。この回答は、時刻なしの日付を表すことを唯一の目的とするクラスを示しています。
バジルブルク

35

現在、Java 8以降に組み込まれているjava.timeクラスに照らして簡単に更新します。

LocalDateTime持っているtruncatedToあなたはおよそここで話しているものを効果的にアドレスする方法を:

LocalDateTime.now().truncatedTo(ChronoUnit.MINUTES)

これにより、現在の時刻が分単位まで表示されます。

2015-03-05T11:47

DAYSより小さいChronoUnit(またはTemporalUnit)を使用して切り捨てを実行できます(切り捨てはLocalDateTimeの時刻部分にのみ適用され、日付部分には適用されません)。


3
ChronoUnitsはDAYSまでしか使用できません。上位のユニットは例外をスローします。
アッシリア2015年

26
Date date = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
date = cal.getTime();

22

Jodaを使用すると、簡単に予定日を取得できます。

バージョン2.7(おそらく2.2よりも前のいくつかのバージョン以降)では、コメントとして、toDateMidnight非推奨になり、適切に名前が付けられたwithTimeAtStartOfDay()ため、

DateTime.now().withTimeAtStartOfDay()

可能。

より良いAPIの利点が追加されました。

古いバージョンでは、次のことができます

new DateTime(new Date()).toDateMidnight().toDate()

6
Joda-Timeの深夜0時関連のメソッドとクラスは現在非推奨です。開発者はそれらを使用しないことを推奨します。代わりにメソッドを使用してくださいwithTimeAtStartOfDay
バジルブルク

ご指摘ありがとうございます。これを検討するために回答を更新しました。
h7r 2015

を使用toLocalDateして、時間コンポーネントさえ持たないオブジェクトを取得することもできます。
Charles Wood

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

8

新しいjava8 APIで切り捨てを行いました。私は奇妙なことに直面しましたが、一般的にそれは切り捨てられています...

Instant instant = date.toInstant();
instant = instant.truncatedTo(ChronoUnit.DAYS);
date = Date.from(instant);

キーワード:java.time、Java 8、LocalDateTime.truncatedTo()
Alexander Taylor

1
この回答は、UTCタイムゾーンのコンテキストの日付のみを生成します。
バジルブルク2016年


6

タイムスタンプの場合:

timestamp -= timestamp % (24 * 60 * 60 * 1000)

3
このコードに小さなエラーがあります-左角括弧が正しく配置されていません。タイムスタンプ-=タイムスタンプ%(24 * 60 * 60 * 1000)でなければなりません。これは時間部分を切り捨てます。そして、この方法はCaledarオブジェクトを作成してそのメソッドで遊んだり、他のサードパーティのライブラリを使用したりするよりも十分です
Stan

2
いいえ、これは正しい解決策ではありません。注意してください。これは、日付値を切り捨ててフロアに丸めることと同じです。つまり、(ロケールでは)3月29日のタイムスタンプで3月28日を取得できます。したがって、カレンダーベースのソリューション(ApacheのDateUtilsもカレンダーを使用する)が唯一の方法です
Drew

これは、夏時間のために時間が変更された場合にも機能しません。
Alexandru Severin 2017年

5

java.util.Date JavaDocsから:

クラスDateは、特定の瞬間をミリ秒の精度で表します

そして、java.sql.Date JavaDocsから:

SQL DATEの定義に準拠するには、インスタンスが関連付けられている特定のタイムゾーンで時間、分、秒、ミリ秒をゼロに設定して、java.sql.Dateインスタンスでラップされたミリ秒の値を「正規化」する必要があります。 。

したがって、時間部分が必要ない場合は、java.sql.Dateを使用するのが最善の方法です。

java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(System.currentTimeMillis());

そして出力は:

java.util.Date : Thu Apr 26 16:22:53 PST 2012
java.sql.Date  : 2012-04-26

4

tl; dr

LocalDateTime.parse(                            // Lacking an offset or time zone, parse as a `LocalDateTime`. *Not* a specific moment in time.
    "2008-01-01 13:15:00".replace( " " , "T" )  // Alter input string to comply with ISO 8601 standard format.
)
.toLocalDate()                                  // Extract a date-only value.
.atStartOfDay(                                  // Do not assume the day starts at 00:00:00. Let class determine start-of-day.
    ZoneId.of( "Europe/Paris" )                 // Determining a specific start-of-day requires a time zone.
)                                               // Result is a `ZonedDateTime` object. At this point we have a specific moment in time, a point on the timeline.
.toString()                                     // Generate a String in standard ISO 8601 format, wisely extended to append the name of the time zone in square brackets.

2008-01-01T00:00 + 01:00 [ヨーロッパ/パリ]

目的の形式で文字列を生成するには、を渡しますDateTimeFormatter

LocalDateTime.parse(                            // Lacking an offset or time zone, parse as a `LocalDateTime`. *Not* a specific moment in time.
    "2008-01-01 13:15:00".replace( " " , "T" )  // Alter input string to comply with ISO 8601 standard format.
)
.toLocalDate()                                  // Extract a date-only value.
.atStartOfDay(                                  // Do not assume the day starts at 00:00:00. Let class determine start-of-day.
    ZoneId.of( "Europe/Paris" )                 // Determining a specific start-of-day requires a time zone.
)                                               // Result is a `ZonedDateTime` object. At this point we have a specific moment in time, a point on the timeline.
.format(                                        // Generate a String representing the object’s value.
    DateTimeFormatter.ISO_LOCAL_DATE_TIME       // Built-in predefined formatter close to what you want. 
)
.replace( "T" , " " )                           // Replace the standard’s use of a 'T' in the middle with your desired SPACE character.

2008-01-01 00:00:00

細部

他の答えは正しいですが、java.timeフレームワークでは時代遅れになった古い日時クラスを使用してください。

java.time

java.timeフレームワークは、Java 8以降に組み込まれています。java.time機能の多くは、Java 6および7(ThreeTen-Backport)にバックポートされ、さらにAndroid(ThreeTenABP)に適合しています。

最初に、ISO 8601形式の正規バージョンに準拠するように入力文字列を変更します。標準のISO 8601形式は、java.timeクラスのデフォルトで、日時値を表す文字列の解析/生成に使用されます。途中のSPACEをに置き換える必要がありTます。

String input = "2008-01-01 13:15:00".replace( " " , "T" );  // → 2008-01-01T13:15:00

これをとして解析できますLocalDateTime。「ローカル」は特定の場所を意味しません。入力には、UTCからのオフセットまたはタイムゾーン情報がありません。

LocalDateTime ldt = LocalDateTime.parse( input );

ldt.toString()…2008-01-01T13:15:00

時刻やタイムゾーンを気にしない場合は、に変換してくださいLocalDate

LocalDate ld = ldt.toLocalDate();

ld.toString()…2008-01-01

日の最初の瞬間

代わりに、時刻をその日の最初の瞬間に設定する場合は、ZonedDateTimeクラスを使用してから、LocalDateオブジェクトに変換してそのatStartOfDayメソッドを呼び出します。00:00:00夏時間またはその他の異常のため、最初の瞬間が時間ではない可能性があることに注意してください。

特定の瞬間に日付が世界中でゾーンによって異なるため、タイムゾーンは重要です。たとえば、真夜中のパリは、パリジャンにとって新しい日ですが、モントリオールではカナダ人にとってまだ「昨日」です。

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ldt.atZone( zoneId );
LocalDate ldFromZdt = zdt.toLocalDate();
ZonedDateTime zdtStartOfDay = ldFromZdt.atStartOfDay( zoneId );

zdtStartOfDay.toString()…2008-01-01T00:00:00-05:00 [アメリカ/モントリオール]

UTC

UTCタイムゾーンのレンズを通してその瞬間を確認するには、Instantオブジェクトを抽出します。どちらZonedDateTimeInstantタイムライン上の同じ瞬間を表すが、2つの異なるとして表示されます壁時計の時間

アンはInstant常にUTCで定義することにより、java.timeにおける基本的なビルディング・ブロックのクラスです。通常はビジネスロジック、データストレージ、およびデータ交換をUTCで行う必要があるため、このクラスを頻繁に使用します。

Instant instant = zdtStartOfDay.toInstant();

instant.toString()…2008-01-01T05:00:00Z

真夜中のストロークではなく、午前5時が表示されます。標準形式ではZ、末尾のはZulu「UTC」の略で、「UTC」を意味します。


java.timeについて

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

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

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

java.timeオブジェクトをデータベースと直接交換することができます。JDBC 4.2以降に準拠したJDBCドライバーを使用します。文字列もクラスも必要ありません。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(<26)では、ThreeTenABPプロジェクトはThreeTen-Backport(上記)を採用しています。ThreeTenABPの使用方法…を参照してください。

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



2

質問は矛盾しています。時刻なしの日付を要求しますが、時刻がの例を表示します00:00:00

ジョーダタイム

UPDATE:ジョダタイムプロジェクトは、今でメンテナンスモードへの移行を助言チームと、java.timeのクラス。java.timeソリューションに関する他の回答を参照しください。

代わりに、時刻をその日の最初の瞬間に設定したい場合DateTimeは、Joda-Timeライブラリーのオブジェクトを使用して、そのwithTimeAtStartOfDayメソッドを呼び出します。00:00:00夏時間またはその他の異常のため、最初の瞬間が時間ではない可能性があることに注意してください。


これが決定的な答えです(Joda Timeを使用でき、使用したい場合)
Clint Eastwood '19

2

ただ、clear()冗長フィールド。

Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.clear(Calendar.MINUTE);
calendar.clear(Calendar.SECOND);
calendar.clear(Calendar.MILLISECOND);
Date truncatedDate = calendar.getTime();

Java 8以降でtruncatedToLocalDateTime、のメソッドを使用することをお勧めします。例:

LocalDateTime.now().truncatedTo(ChronoUnit.DAYS)

calendar.clear(Calendar.HOUR_OF_DAY);時間をクリアしないため、これは機能しません。@cletusのソリューションは問題なく動作します。
Arcao 2013年

申し訳ありませんが、正解です。修正しました。何時間も値を設定する必要があります。一般的には、日付を切り捨てる方法とほぼ同じです...
m190

1

新しい「改善された」カレンダーコンストラクターは、「ひどい」古い日付のように、ミリ秒の間intを取りません。それから私は本当にクロスしてこれを書きました:

long stuffYou = startTime.getTimeInMillis() % 1000;
startTime.setTimeInMillis(startTime.getTimeInMillis() - stuffYou);

当時は「もの」という言葉は使っていませんでしたが、その幸福を発見しました。

startTime.set(Calendar.MILLISECOND, 0);

しかし、私はまだそれについてかなりクロスしています。


1

私はこのように問題を修正しました(東部の8つのゾーン(北京時間)):

private Date getTruncatedDate(Date d) {
    if (d == null) {
        return null;
    }
    long h = 60 * 60 * 1000L;
    long dateStamp = d.getTime() - (d.getTime() + 8 * h) % (24 * h);
    return new Date(dateStamp);
}

まず、タイムスタンプとは何かを明確にする必要があります。タイムスタンプは、GMTの1月1日00:00:00 1970(UTCと同じ)、またはThu Jan 01 08:00:00 CST 1970から現在までの合計ミリ秒です。

注意:タイムスタンプはタイムゾーンに依存しません。

したがって、異なるタイムゾーンで次のステートメントを使用しても同じ結果が得られます。

System.out.println(new Date().getTime());

そして

System.out.println(new Date(0));

異なるタイムゾーンで異なる時間情報を出力します。PCタイムゾーンをUTCに設定すると、

Thu Jan 01 00:00:00 UTC 1970

しかし、タイムゾーンを(UTC +8:00)北京、重慶、香港、ウルムクに設定すると、次のようになります。

Thu Jan 01 08:00:00 CST 1970

Javaはタイムスタンプを取得し、タイムゾーンに従って日付と時刻の情報を表示します。

Javaが異なるタイムゾーンで日付と時刻の情報を表示する方法の紹介では、時刻の情報を変換する方法は簡単です。タイムスタンプを取得し、時間情報を切り取るときにタイムゾーンを考慮する必要があります。次に、カットタイムスタンプ(日付スタンプと呼ぶことができます)を使用して新しいDateオブジェクトを作成できます。Javaは日付情報を表示するときにタイムゾーンを補正します。

東部8ゾーン(北京時間)と同様に、北京時間はGMTより8時間早いので、モジュロ演算を行う場合はさらに8時間差し引く必要があります。つまり、最初にGMT時刻を取得する必要があります。次に、PCのタイムゾーン設定に基づいてJavaが表示時刻を8時間追加します。


タイムゾーンの問題はあいまいであり、長い間私も困惑しています。今私はそれを明確にします。願っています。


2018-01-04以下の方法でも動作します。

private Date getTruncatedDate2(Date d) {
    Calendar cal = Calendar.getInstance(); // locale-specific
    cal.setTime(d);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);


return cal.getTime();

}


ちなみに、この回答では、java.timeクラスによって何年も前に取って代わられた厄介な古い日時クラスを使用してます。
Basil Bourque 2017

1

これを行うと、タイムゾーンの問題を回避できます。

public static Date truncDate(Date date) {
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    cal.setTime(date);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    return cal.getTime();
}

Java Dateオブジェクトはタイムスタンプ値ですが、トランケート中にローカルタイムゾーンに変換されるため、UTCタイムゾーンからの値を期待している場合、驚くべき値が得られます。


面倒CalendarDateクラスがでレガシー年前になったjava.timeのジャワ8以降でJSR 310を実装するクラス。2018年にそれらを使用することを提案することはあまりお勧めできません。
バジルブルク2018年

0

応答が遅くなる可能性がありますが、ライブラリを使用せずに1行で実行する方法を次に示します。

new SimpleDateFormat("yyyy-MM-dd").parse(new SimpleDateFormat("yyyy-MM-dd").format(YOUR_TIMESTAMP))

0

ジョダタイムバージョン2.0以降を使用できLocalDate.toDate()

単に

// someDatetime is whatever java.util.Date you have.
Date someDay = new LocalDate(someDatetime).toDate();

[A]あなたの答えは冗長です。すでにBrian Agnewによって投稿されています。[B]質問で提起された問題そのものであるタイムゾーンを無視するため、コードは正しくありません。
バジルブルク2014

冗長になる可能性がありますが、コメントにコメントを入れてはいけないと認識したため、ここに簡単な例を示します。はい、java.util.DateはTimeZoneを無視しますが、元の質問はa Java Date object私が使用したものjava.util.Dateでした。さらに、彼のタイムゾーンがjava.util.Dateでどのように問題があるか(いつ?どこで?)についても説明していませんが、以外は使用できませんDate
ラムジーク2014

0

カレンダーを使用したすべての回答については、代わりにこのように使用する必要があります

public static Date truncateDate(Date date) {
    Calendar c = Calendar.getInstance();
    c.setTime(date);
    c.set(Calendar.HOUR_OF_DAY, c.getActualMinimum(Calendar.HOUR_OF_DAY));
    c.set(Calendar.MINUTE, c.getActualMinimum(Calendar.MINUTE));
    c.set(Calendar.SECOND, c.getActualMinimum(Calendar.SECOND));
    c.set(Calendar.MILLISECOND, c.getActualMinimum(Calendar.MILLISECOND));
    return c.getTime();
}

しかし、私はこれを好みます:

public static Date truncateDate(Date date) {
    return new java.sql.Date(date.getTime());
}

java.sql.Dateこのクラスは、日付のみの値を表すために、ふりが、実際の時刻UTCタイムゾーンの調整を持っています。したがって、質問に対する実際の解決策ではありません。
バジルブルク2016年

0

Java 8以降を使用している場合に時間なしで日付を取得する簡単な方法は次のとおりです。Dateではなくjava.time.LocalDateタイプを使用します。

LocalDate now = LocalDate.now();
 System.out.println(now.toString());

出力:

2019-05-30

https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html


1
LocalDateほとんどの目的で使用することをお勧めしますが、質問からの入力でこれがどのように機能するかは不明2008-01-01 13:15:00です。
Ole VV
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.