java.util.Dateのタイムゾーンを設定する方法


225

a java.util.Dateからa を解析しましたStringが、ローカルタイムゾーンをdateオブジェクトのタイムゾーンとして設定しています。

解析されるStringfromでタイムゾーンが指定されていませんDatedateオブジェクトの特定のタイムゾーンを設定したい。

どうやってやるの?


8
あなたの質問への答えにはなりませんが、ここで何度か言及されているJoda Timeを使用しました。標準のAPIよりも合理的で、このようなことを簡単に行うことができます。
clstrfsck 2010年

2
@msandiford最近では、Joda -Timeではなくjava.timeクラスを使用してくださいジョダタイムプロジェクトは、今でメンテナンスモードへの移行を助言チームと、java.timeのクラス。Oracleによるチュートリアルを参照してください。
バジルブルク

回答:


315

DateFormatを使用します。例えば、

SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");

6
日付がCalendarクラスから作成された場合は、カレンダーのタイムゾーンを設定できます。
lwpro2 2013年

19
@ lwpro2そのステートメントは誤解を招くものです。Calendarオブジェクトのタイムゾーンを設定できますが、getTime()メソッドを使用してDateオブジェクトを取得すると、ホストコンピュータのタイムゾーンを含むDateオブジェクトが返されます。
BrDaHa 14

02/20/15 14:44の解析に問題があります。だれでも助けることができます
MS

@BrDaHaは正しいです。TimeZone.setDefault()呼び出す前にgetTime()、新しい日付オブジェクトが必要なタイムゾーンになるようにする必要があります。JDK 1.8では、をCalendar.getTime()呼び出しますreturn new Date(getTimeInMillis());
jpllosa 2017年

182

java.util.Dateオブジェクト自体にはタイムゾーン情報が含まれていないことに注意してくださいDate。オブジェクトにタイムゾーンを設定することはできません。Dateオブジェクトに含まれる唯一のものは、「エポック」からのミリ秒数-1970年1月1日00:00:00 UTCです。

ZZ Coderが示すように、DateFormatオブジェクトにタイムゾーンを設定して、日付と時刻を表示するタイムゾーンを伝えます。


77
グーグル操作、実験、削除を行った結果、これが答えに正確かつ役立つ追加であり、強調する価値があることに気付きました。日付にはミリ秒の値しか含まれていません。ソースを見ると、longと呼ばれるフィールドがほとんどありますfastTimeDate.toString()実際には、Calendarこのミリ秒の時間を解釈するためにa を使用します。したがって、aを出力Dateすると、(デフォルトの)タイムゾーンがあるように見え、そのタイムゾーンの設定方法について理解しやすい質問が表示されます。
David Carboni

3
Dateオブジェクト内にタイムゾーン情報があります。しかし、それは本当かもしれません、あなたはそれを変えることができません。
lwpro2 2013年

3
@ Iwpro2、Jesperは、Dateオブジェクトにはタイムゾーンが格納されていないと主張しています(同意します)。タイムゾーンがjava.util.Date内に格納されていると主張する場合は、参照を提供してください。
ジム

6
@ジム、これはjava.util.Dateのソースコードです。unixエポックとしてのfastTimeと、定義されている場合はfastTimeを優先して使用されるBaseCalendar.Date cdateが含まれます。これにはタイムゾーン情報が含まれています。Dateインスタンスにタイムゾーン情報を含めることができるように理解していますが、そうではない場合があります。
eis 2013

2
@ジム私はあなたがそれを設定できるとは言わなかった、私はそれがこの情報を含んでいると言っていた。ユーザーとして設定する方法も見ていません。OPは、常にユーザー/システムのデフォルトのタイムゾーンのように見えるという点で正しいと思います。
eis

95

tl; dr

…解析された…文字列から…時間帯が指定されていない…特定の時間帯を設定したい

LocalDateTime.parse( "2018-01-23T01:23:45.123456789" )  // Parse string, lacking an offset-from-UTC and lacking a time zone, as a `LocalDateTime`.
    .atZone( ZoneId.of( "Africa/Tunis" ) )              // Assign the time zone for which you are certain this date-time was intended. Instantiates a `ZonedDateTime` object.

juDateにタイムゾーンがありません

他の正解が述べたように、java.util.DateにはタイムゾーンがありませんUTC / GMTを表します(タイムゾーンオフセットなし)。toString文字列表現を生成するときにそのメソッドがJVMのデフォルトのタイムゾーンを適用するため、非常に混乱します。

juDateを避ける

このため、他の多くの理由により、組み込みのjava.util.Date&.Calendar&java.text.SimpleDateFormatの使用は避けてください。彼らは悪名高いほど厄介です。

代わりに、Java 8にバンドルされているjava.timeパッケージを使用してください

java.time

java.timeクラスは、3つの方法でタイムライン上の瞬間を表すことができます。

  • UTC(Instant
  • オフセットあり(OffsetDateTimeありZoneOffset
  • タイムゾーンあり(ZonedDateTimeありZoneId

Instant

java.time、基本的なビルディング・ブロックであるInstant、UTCのタイムライン上の瞬間。Instantビジネスロジックのほとんどにオブジェクトを使用します。

Instant instant = Instant.now();

OffsetDateTime

UTCからオフセットを適用して、地域の実時間に合わせます。

ZoneOffsetを取得するにはを適用しますOffsetDateTime

ZoneOffset zoneOffset = ZoneOffset.of( "-04:00" );
OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );

ZonedDateTime

ベターは適用することであるタイムゾーン、オフセットプラスなどの異常処理するためのルール夏時間(DST)を

をに適用ZoneIdしてInstantを取得しZonedDateTimeます。常に適切なタイムゾーン名を指定してください。など3-4略語は使用しないでくださいESTまたはISTユニークでも標準化でもありません。

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

LocalDateTime

入力文字列にオフセットまたはゾーンのインジケーターがない場合は、として解析しますLocalDateTime

意図したタイムゾーンに確信がある場合は、を割り当ててZoneIdを生成しZonedDateTimeます。上記のtl; drセクションのコード例を参照してください。

書式設定された文字列

toStringこれらの3つのクラスのいずれかでメソッドを呼び出して、標準のISO 8601形式で日時値を表す文字列を生成します。ZonedDateTimeクラスは、括弧内のタイムゾーンの名前を追加することによって、標準的なフォーマットを拡張しています。

String outputInstant = instant.toString(); // Ex: 2011-12-03T10:15:30Z
String outputOdt = odt.toString(); // Ex: 2007-12-03T10:15:30+01:00
String outputZdt = zdt.toString(); // Ex: 2007-12-03T10:15:30+01:00[Europe/Paris]

他のフォーマットについてはDateTimeFormatterクラスを使用してください。一般に、そのクラスに、ユーザーの予想される人間の言語と文化的規範を使用してローカライズされたフォーマットを生成させるのが最善です。または、特定のフォーマットを指定できます。


モダンとレガシーの両方のJavaのすべての日時タイプの表


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クラスはどこで入手できますか?

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


ジョーダタイム

一方でジョダ時はまだ積極的に維持され、そのメーカーはすぐに便利なようjava.timeへの移行を私たちに語っています。このセクションは参照用としてそのまま残していますが、java.time代わりに上記のセクションを使用することをお勧めします。

ジョダタイム、日付時刻オブジェクト(DateTime)本当にその割り当てられたタイムゾーンを知っているん。これは、UTCからのオフセット、そのタイムゾーンの夏時間(DST)の規則と履歴、およびその他のそのような異常を意味します。

String input = "2014-01-02T03:04:05";
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" );
DateTime dateTimeIndia = new DateTime( input, timeZone );
DateTime dateTimeUtcGmt = dateTimeIndia.withZone( DateTimeZone.UTC );

toStringメソッドを呼び出して、文字列をISO 8601形式で生成します。

String output = dateTimeIndia.toString();

Joda-Timeは、他のあらゆる種類の文字列フォーマットを生成するための豊富な機能も提供します。

必要に応じて、Joda-Time DateTimeからjava.util.Dateに変換できます。

Java.util.Date date = dateTimeIndia.toDate();

StackOverflowで「joda date」を検索して、さらに詳細な例を見つけてください。


実際に、java.util.Dateに埋め込まれたタイムゾーンがあり、一部の内部関数に使用されています(この回答のコメントを参照)。ただし、この内部タイムゾーンはプロパティとして公開されていないため、設定できません。この内部タイムゾーンは、日付時刻値の文字列表現を生成するときにメソッドが使用するものではありませんtoString。代わりに、JVMの現在のデフォルトのタイムゾーンがオンザフライで適用されます。したがって、省略形として、「juDateにはタイムゾーンがない」とよく言います。混乱していますか?はい。これらの疲れた古いクラスを避けるもう一つの理由。


3
「juDateにタイムゾーンがありません」は間違っています。BaseCalendar.Date cdate設定されている場合、そのプロパティに格納されているjuDateのタイムゾーン情報があります。ここでソースコードを見てください。を呼び出してJVMのデフォルトのタイムゾーンを変更しない限り、juDateオブジェクトのタイムゾーンを設定することはできませんTimeZone.setDefault(TimeZone.getTimeZone("NEW_TIME_ZONE"));。したがって、タイムゾーンのオフセットがあり、非推奨のメソッドjuDate.getTimezoneOffset()を呼び出すことでオフセットを取得できます
Thai Bui

3
@blquythai正解、宿題をやりました。私もそうでしたが、そのソースコードを以前に見たことがあります。そこにタイムゾーンが埋まっています。しかし、すべての実用的な目的のために、そのタイムゾーンは無視されます。java.util.Dateは、タイムゾーンなしで機能します。つまり、実質的にUTCであり、埋め込まれたタイムゾーンは無視されます。toStringJVMの現在のデフォルトのタイムゾーンを適用するメソッドを除きます。埋もれた時間帯を再び無視します。したがって、簡潔にするために、java.util.Dateにはタイムゾーンがないと言います。アートのように、それは真実を語る嘘です。
バジルブルク2015年

@blquythaiとしては呼び出すためにTimeZone.setDefault、あなたがされていない java.util.Dateオブジェクトのタイムゾーンを設定する- DateオブジェクトがまだUTCに効果的に作用して、その埋葬タイムゾーンを無視します。日付のtoString方法に影響します。デフォルトを設定すると、通常はホストオペレーティングシステムのタイムゾーンに設定されるJVMのデフォルトタイムゾーンが変更されます。その呼び出しは、そのJVMで実行されているすべてのアプリのすべてのスレッドのすべてのコードに影響し、実行中にオンザフライで実行されるため、お勧めません。失礼で危険なため、この電話は最後の手段と見なす必要があります。
バジルブルク2015年

5
その時間帯は非常に頻繁に使用されている(で使用されるequalshashcodegetTime...)あなたが見てみましょう場合equalsの方法、それが呼び出すgetTime()どの呼び出しgetTimeImpl()、その呼び出しnormalize()た場合cdateプロパティは正規化されていません。normalize()方法、最後には、条件の時間帯があれば、その記憶されたタイムゾーン情報に基づいて1/1/70からのミリ秒を再計算する場合cdate、それが実行されている現在のJVM環境のタイムゾーンとは異なるが。(ご覧くださいsun.util.calendar.AbstractCalendar getCalendarDate(long millis, CalendarDate date)
タイのブイ

2
@MichalMあなたのアドバイスに従って、少し前に埋め込みゾーンについてのあとがきを追加しました。
バジルブルク2017

75

JVMレベルでタイムゾーンを設定することもできます

Date date1 = new Date();
System.out.println(date1);

TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// or pass in a command line arg: -Duser.timezone="UTC"

Date date2 = new Date();
System.out.println(date2);

出力:

Thu Sep 05 10:11:12 EDT 2013
Thu Sep 05 14:11:12 UTC 2013

これは私を助けました。SDFでtimeZoneを設定しても
違い

もっと信頼できると思います。(+1)
foob​​ar

23
注意:呼び出しTimeZone.setDefaultは、JVM全体に影響し、他のすべてのオブジェクトとスレッドに影響するため、かなり劇的です。参照してくださいこの回答あなたはSecurityManagerをして実行している場合でも、多くの合併症を含む詳細については、を。さらに複雑になる:この質問で説明されているように、この動作はさまざまなバージョンのJavaで変更されています。
バジルブルク2014年

これにより、このステートメントの後に生成されたすべてのスレッドに共通のタイムゾーンが設定されます。
Jaydev 2016年

これは、受け入れられたものよりも質問に対するより良い答えです。
francogrex 2018

10

標準のJDKクラスのみを使用する必要がある場合は、次のように使用できます。

/**
 * Converts the given <code>date</code> from the <code>fromTimeZone</code> to the
 * <code>toTimeZone</code>.  Since java.util.Date has does not really store time zome
 * information, this actually converts the date to the date that it would be in the
 * other time zone.
 * @param date
 * @param fromTimeZone
 * @param toTimeZone
 * @return
 */
public static Date convertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone)
{
    long fromTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, fromTimeZone);
    long toTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, toTimeZone);

    return new Date(date.getTime() + (toTimeZoneOffset - fromTimeZoneOffset));
}

/**
 * Calculates the offset of the <code>timeZone</code> from UTC, factoring in any
 * additional offset due to the time zone being in daylight savings time as of
 * the given <code>date</code>.
 * @param date
 * @param timeZone
 * @return
 */
private static long getTimeZoneUTCAndDSTOffset(Date date, TimeZone timeZone)
{
    long timeZoneDSTOffset = 0;
    if(timeZone.inDaylightTime(date))
    {
        timeZoneDSTOffset = timeZone.getDSTSavings();
    }

    return timeZone.getRawOffset() + timeZoneDSTOffset;
}

クレジットはこの投稿に行きます。


1
タイムゾーンのオフセットは常に一定ではありません。実際、それらは地政学的な理由により変更される場合があります。TimeZone.getDSTSavings()はこれを考慮せず、常に現在のオフセットを返します。これは、その日付以降にオフセットが変更されたfromTimeZone / toTimeZoneで履歴日付を処理している場合、誤った変換を取得する可能性があることを意味します。
andrerobot 2016年

6

java.util.CalendarJDKクラスだけを使用してタイムゾーンを処理する通常の方法です。Apache Commonsには、さらに役立つ可能性のある代替/ユーティリティがいくつかあります。Edit Spongのメモは、私がJoda-Timeについて本当に良いことを聞いたことを思い出させました(私自身はそれを使用していません)。


ジョーダ時間の+1。Joda Timeは、標準のJava APIからは得られなかった追加機能(いずれにせよ私が見つけたもので、他に表示されて嬉しい)を提供していませんが、いくつかのタスクを容易にします。
ジョシュアハッチソン

2
@JoshuaHutchisonジョダ-時間がありトン追加機能のを。例:クラスとの時間のスパンを表現するPeriodDurationInterval。これらのスパンは、次のような比較方法を含むcontainsabutsoverlap、およびgap。そしてPeriodFormatterBuilder、このような「15年と8ヶ月」などの記述的なフレーズを構築することができます。
バジルブルク2014年

1

日付を文字列に変換し、SimpleDateFormatでそれを行います。

    SimpleDateFormat readFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    readFormat.setTimeZone(TimeZone.getTimeZone("GMT" + timezoneOffset));
    String dateStr = readFormat.format(date);
    SimpleDateFormat writeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
    Date date = writeFormat.parse(dateStr);

1
Stack Overflowの回答には、いくつかの議論または説明が必要です。このサイトは、単なるコードスニペットライブラリではありません。
バジルブルク2018年

コメントをありがとう@Basil Bourque 私は答えを編集します
アビスパー

0

誰かがこれを必要とする場合、XMLGregorianCalendarタイムゾーンをUTCから現在のタイムゾーンに変換する必要がある場合は、タイムゾーンを0に設定し、次に呼び出すだけtoGregorianCalendar()です。同じタイムゾーンのままですが、Date変換方法はわかっています。そこからデータを取得できます。

XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(
        ((GregorianCalendar)GregorianCalendar.getInstance());
xmlStartTime.setTimezone(0);
GregorianCalendar startCalendar = xmlStartTime.toGregorianCalendar();
Date startDate = startCalendar.getTime();
XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
    .newXMLGregorianCalendar(startCalendar);
xmlStartTime.setHour(startDate.getHours());
xmlStartTime.setDay(startDate.getDate());
xmlStartTime.setMinute(startDate.getMinutes());
xmlStartTime.setMonth(startDate.getMonth()+1);
xmlStartTime.setTimezone(-startDate.getTimezoneOffset());
xmlStartTime.setSecond(startDate.getSeconds());
xmlStartTime.setYear(startDate.getYear() + 1900);
System.out.println(xmlStartTime.toString());

結果:

2015-08-26T12:02:27.183Z
2015-08-26T14:02:27.183+02:00

0

このコードは、私が取り組んでいるアプリで役に立ちました:

    Instant date = null;
    Date sdf = null;
    String formatTemplate = "EEE MMM dd yyyy HH:mm:ss";
    try {
        SimpleDateFormat isoFormat = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss");
        isoFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.of("US/Pacific")));
        sdf = isoFormat.parse(timeAtWhichToMakeAvailable);
        date = sdf.toInstant();

    } catch (Exception e) {
        System.out.println("did not parse: " + timeAtWhichToMakeAvailable);
    }

    LOGGER.info("timeAtWhichToMakeAvailable: " + timeAtWhichToMakeAvailable);
    LOGGER.info("sdf: " + sdf);
    LOGGER.info("parsed to: " + date);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.