web-dev-qa-db-ja.com

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

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

Stringの解析元のDateにタイムゾーンが指定されていません。 dateオブジェクトの特定のタイムゾーンを設定したいです。

どうやってやるの?

183
Yatendra Goel

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");
277
ZZ Coder

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

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

153
Jesper

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.

J.u.Dateにタイムゾーンがない

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

J.u.Dateを避ける

これと他の多くの理由から、組み込みのJava.util.Date&.Calendar&Java.text.SimpleDateFormatを使用しないでください。彼らは悪名高いほど面倒です。

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

Java.time

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

  • UTC(Instant
  • オフセット付き(OffsetDateTimeZoneOffset
  • タイムゾーン付き(ZonedDateTimeZoneId

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

タイムゾーン 、オフセットplus夏時間(DST) などの規則を適用することをお勧めします。 。

ZoneIdInstantに適用して ZonedDateTime を取得します。常に 適切なタイムゾーン名 を指定してください。 ESTISTなど、一意でも標準化されてもいない3〜4の略語は絶対に使用しないでください。

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

LocalDateTime

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

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

書式付き文字列

これら3つのクラスのいずれかでtoStringメソッドを呼び出して、標準の ISO 8601 形式で日時値を表すStringを生成します。 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.timeについて

Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、 Java.util.DateCalendar 、& SimpleDateFormat などの厄介な古い レガシー 日時クラスに代わるものです。

Joda-Time プロジェクトは メンテナンスモード になっており、 Java.time に移行することをお勧めします。クラス。

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

あなたのデータベースとJava.timeオブジェクトを直接交換することができます。 JDBC 4.2 に準拠した JDBCドライバ を使用してください。文字列もJava.sql.*クラスも必要ありません。

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

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


ジョダタイム

Joda-Time はまだ活発に維持されていますが、そのメーカーは都合がよいとすぐにJava.timeに移行するように私たちに言っています。このセクションは参照としてそのまま残しますが、代わりに上記のJava.timeセクションを使用することをお勧めします。

Joda-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に埋め込まれたタイムゾーンであり、いくつかの内部関数に使用されます(この回答のコメントを参照)。しかし、この内部タイムゾーンはプロパティとして公開されていないため、設定できません。この内部タイムゾーンは、not日時値の文字列表現を生成する際に toString メソッドで使用されるものです。代わりに、JVMの現在のデフォルトタイムゾーンが即座に適用されます。そのため、簡単に言うと、「j.u.Dateにはタイムゾーンがありません」とよく言われます。混乱しますか?はい。これらの疲れた古いクラスを避けるもう一つの理由。

70
Basil Bourque

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
65
starmer

標準の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;
}

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

7
diadyne

Java.util.Calendar は、JDKクラスだけを使用してタイムゾーンを処理するための通常の方法です。 Apache Commons には、役に立つかもしれない他の選択肢/ユーティリティがあります。 EditSpongのメモは、私が Joda-Time について本当に良いことを聞いたことを思い出させてくれました。自分では使っていません。

6
T.J. Crowder

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

    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);
0
VikR

日付を文字列に変換して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);
0
avisper

誰かがこれを必要とする場合、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
EpicPandaForce