web-dev-qa-db-ja.com

javaで現在のタイムゾーンの日付を取得する

過去数時間からネット上で検索して、システムのタイムゾーンの日時を取得しています。

Calendar.getTimezone.getDefaultNameを使用すると、常にGMTが返されます。 (理想的には、現在のタイムゾーン(IST)を返す必要があります)GMTにあるこの文字列「2014-02-14T06:04:00:00」をタイムゾーンdatetimeに変換しようとしています。 GMTで常に同じ時間を返します。

私が見るすべては、誰もがタイムゾーンを使用することを提案しているということです。すなわち、

dateFormatter.setTimezone("any_arbitary_timezone");

ポイントは、私のアプリケーションが地理的に異なる場所で使用されることです。特定のタイムゾーンに設定することはできません。ユーザーが現在いるどのタイムゾーンでも表示できるように、システムのタイムゾーンに設定する必要があります

25
Kiran Kulkarni

ローカルシステムクロックのオフセットと一致するTimeZoneのIDを取得する方法は次のとおりです。

Calendar cal = Calendar.getInstance();
long milliDiff = cal.get(Calendar.ZONE_OFFSET);
// Got local offset, now loop through available timezone id(s).
String [] ids = TimeZone.getAvailableIDs();
String name = null;
for (String id : ids) {
  TimeZone tz = TimeZone.getTimeZone(id);
  if (tz.getRawOffset() == milliDiff) {
    // Found a match.
    name = id;
    break;
  }
}
System.out.println(name);
12
Elliott Frisch

tl; dr

最新のJava.timeクラスを使用します。

ZonedDateTime.now(           // Capture the current moment in the wall-clock time used by the people of a certain region (a time zone).
    ZoneId.systemDefault()   // Get the JVM’s current default time zone. Can change at any moment during runtime. If important, confirm with the user.
)                            // Renders a `ZonedDateTime` object. To see the same moment in UTC, extract a `Instant` object by calling `ZonedDateTime::getInstant`.

ZoneId.systemDefaultへの明示的な呼び出しを省略できます。

ZonedDateTime.now()          // Capture the current moment in the JVM’s current default time zone.

文字列を LocalDateTime として解析し、目的のタイムゾーンに調整します。

LocalDateTime.parse( "2014-02-14T06:04:00:00" )    // Parse a string lacking any indicator of time zone or offset-from-UTC. *Not* a specific point on the timeline.
             .atOffset( ZoneOffset.UTC )           // Apply UTC as we are certain that offset-from-UTC of zero was intended by the supplier of that input string. Returns a `OffsetDateTime` object.
             .atZoneSameInstant(                   // Adjust into another time zone. The `sameInstant` part means the same moment, different wall-clock time. 
                 ZoneId.of( "Africa/Tunis" )       // Specify the particular zone of interest to you.
             )                                     // Returns a `ZonedDateTime` object.

Java.util.Date.Calendarを避ける

これらのレガシークラスは厄介なことで有名です。 Sun/Oracleは、それらを置き換えるためにJava 8に Java.time パッケージを追加しました。このパッケージは、 Joda-Time に触発されました。

レガシークラスの問題の中には、この混乱する動作があります。Java.util.Dateにはタイムゾーン情報がありませんが、toString実装は、文字列を生成するときにJVMの現在のデフォルトタイムゾーンを適用します。そのため、タイムゾーンがないように見えるので、誤解を招きます。

Java.time

この文字列「2014-02-14T06:04:00:00」を変換しようとしています...

入力文字列には、タイムゾーンまたはUTCからのオフセットのインジケータがありません。したがって、 LocalDateTime として解析しますが、これにはゾーン/オフセットの概念がありません。

LocalDateTime not は瞬間を表し、 not はタイムライン上のポイントです。ここでの「ローカル」という言葉は、 not は特定の地域を意味します。 「特定の地域性がまったくない」という意味です。ゾーン/オフセットのコンテキストがなければ、実際の意味はありません。

LocalDateTime ldt = LocalDateTime.parse( "2014-02-14T06:04:00:00" ) ;

…GMTにあります…

あなたは、UTCをコンテキストとして意図した入力文字列のサプライヤであると確信しています。 OffsetDateTimeオブジェクトを取得するために、ゼロのUTCからのオフセット、またはUTC自体を適用できます。 OffsetDateTime is は、タイムライン上のポイントです。 UTCの定数 ZoneOffset.UTC を使用して、ZoneOffsetを指定できます。

OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;

…タイムゾーンdatetimeに

どうやらその瞬間を別のタイムゾーンに合わせて調整し、特定の地域の人々が使用している実時間を表示したいようです。 ZoneId を取得するには、タイムゾーン(ZonedDateTime)を適用する必要があります。

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = odt.atZone( z ) ;

タイムゾーンを指定する代わりに、現在のデフォルトのタイムゾーンをJVMに問い合わせることができます。注意:JVMの現在のデフォルトタイムゾーンは、そのJVM内のアプリのスレッドのコードによっていつでも変更できます。

ZoneId z = ZoneId.systemDefault() ;
ZonedDateTime zdt = odt.atZone( z ) ;

ポイントは、私のアプリケーションが地理的に異なる場所で使用されることです。

希望する/予想されるタイムゾーンを明示的に指定するだけです。私の意見では、これは always の良い習慣です。デフォルトのタイムゾーンはプログラマーとしてあなたの管理外にあるため、信頼できません。

適切なタイムゾーン名 を、 continent/region などのAmerica/Montrealの形式で指定します。 /、 Africa/Casablanca 、またはPacific/AucklandESTISTなどの3〜4文字の略語は、 not 真のタイムゾーンであり、標準化されておらず、一意でさえないため( !)。

別のヒント:作業、思考、保存、およびUTCでの交換。あなた自身の偏狭なタイムゾーンを忘れてください、あなたのホームゾーンに前後に翻訳することはあなたを苦しめるので。 UTCは One True Time と考えてください。他のゾーン/オフセットは単なるバリエーションです。

Instant instant = Instant.now() ;  // Capture current moment in UTC.

ZoneId zAuckland = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdtAuckland = instant.atZone( zAuckland ) ;

ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" ) ;  
ZonedDateTime zdtKolkata = instant.atZone( zKolkata ) ;

ZoneId zCasablanca = ZoneId.of( "Africa/Casablanca" ) ;  
ZonedDateTime zdtCasablanca = instant.atZone( zCasablanca ) ;

そこでは、タイムライン上の同じポイントである非常に同じ同時の瞬間を見る4つの方法(instantzdtAucklandzdtKolkatazdtCasablanca)があります。

instant.toString():2018-05-08T20:55:14.761721Z

zdtAuckland.toString():2018-05-09T08:55:14.761721 + 12:00 [太平洋/オークランド]

zdtKolkata.toString():2018-05-09T02:25:14.761721 + 05:30 [アジア/コルカタ]

zdtCasablanca.toString():2018-05-08T21:55:14.761721 + 01:00 [アフリカ/カサブランカ]

ゾーンとオフセット

UTCからのオフセットは、単に時間、分、秒の数です。これ以上でもそれ以下でもありません。特定の時点で、任意の数のタイムゾーンが特定のオフセットを共有できます。

タイムゾーンは、特定の地域の人々が使用するオフセットの過去、現在、および将来の変更の履歴です。たとえば、夏時間(DST)は、地域の人々が(不可解なことに)年に2回オフセットを変更することを決定するプラクティスです。

したがって、単なるオフセットよりも常にタイムゾーンの方が適しています。ゾーンを持つことにより、意味のある方法で時間を加算または減算して、その地域の履歴のオフセットの変化を考慮することができます。


Java.timeについて

Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、厄介な古い legacy の代わりに、 Java.util.DateCalendar 、& SimpleDateFormat

Joda-Time プロジェクト、現在 maintenance modeJava.time クラスへの移行を推奨します。

詳細については、 Oracle Tutorial を参照してください。また、Stack Overflowで多くの例と説明を検索してください。仕様は JSR 310 です。

Java.timeオブジェクトをデータベースと直接交換できます。 JDBC driver を使用して、 JDBC 4.2 以降に準拠します。文字列も、Java.sql.*クラスも必要ありません。

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

ThreeTen-Extra プロジェクトは、追加のクラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。 IntervalYearWeek などの便利なクラスがあります。 、 YearQuarter 、および more


ジョーダタイム

更新:Joda-Timeプロジェクトは現在、メンテナンスモードになっています。チームは、Java.timeクラスへの移行を推奨しています。このアンサーの以下のJava.timeセクションにスキップしてください。

Joda-Timeパッケージは、タイムゾーンを明確にサポートしています。 Java.util.Dateとは異なり、Joda-Time DateTimeは割り当てられたタイムゾーンを認識しています。タイムゾーンの指定に失敗すると、JVMの現在のデフォルトのタイムゾーンが暗黙的に割り当てられます。

DateTime dateTime = DateTime.now(); // Applies JVM’s default time zone implicitly.

暗黙的にデフォルトのタイムゾーンに依存しないことをお勧めします。これを行うと、日時の作業を行うときに混乱とエラーが発生します。

DateTime dateTime = DateTime.now( DateTimeZone.getDefault() ); // Explicitly using default time zone.

必要に応じて、タイムゾーンを割り当てることができます。

DateTime dateTimeKolkata = DateTime.now( DateTimeZone.forID( "Asia/Kolkata" ) ); // Specify a time zone.

サーバー側の作業のベストプラクティスは、 [〜#〜] utc [〜#〜] でビジネスロジックとデータベースストレージを実行することです。

DateTime dateTimeUtc = DateTime.now( DateTimeZone.UTC ); // Assign UTC (GMT) time zone.

JVMの現在のデフォルトのタイムゾーンを含め、割り当てられたタイムゾーンから別のタイムゾーンに変換できます。

DateTime dateTime = dateTimeUtc.withZone( DateTimeZone.getDefault() );

不変

スレッドセーフのために、Joda-Timeは immutable objects を使用します。オブジェクトを変更する代わりに、withZoneなどのメソッドは、元のインスタンスに基づいて新しいインスタンスを作成します。

文字列の解析

文字列をDateTimeとして解析するには、文字列にUTCまたはタイムゾーンからのオフセットが含まれているかどうかに注意する必要があります。あなたのものはありません。そのため、文字列を解釈するタイムゾーンを指定する必要があります。指定しない場合、解析中にJVMの現在のデフォルトのタイムゾーンが使用されます。

あなたの質問では、文字列は [〜#〜] utc [〜#〜][ 〜#〜] gmt [〜#〜] )。

DateTime dateTimeUtc = new DateTime( "2014-02-14T06:04:00:00", DateTimeZone.UTC );

解析後、必要に応じて別のタイムゾーンを割り当てることができます。宇宙のタイムラインの同じ瞬間ですが、異なる Wall-Clock time を示しています。

DateTime dateTimeDefaultZone = dateTimeUtc.withZone( DateTimeZone.getDefault() );

したがって、これは2段階のプロセスでした。まず、そのタイムゾーンまたはオフセットの内部表現が不足しているため、ストリングの意図されたタイムゾーンに関する外部の知識を使用して、ストリングを解析しました。次に、タイムゾーンを別のタイムゾーンに調整しました(JVMのデフォルトゾーン)。

文字列に+00:00または慣例的なZのオフセットが含まれていた場合、これらの2つのステップを1つにまとめることができました。

DateTime dateTimeDefaultZone = new DateTime(  "2014-02-14T06:04:00:00Z", DateTimeZone.getDefault() ); // Apply time zone adjustment *after* parsing.

このDateTimeコンストラクターは上記のように見えますが、実際にはかなり異なっていることに注意してください。この1つのタイムゾーン引数は、 /解析ではなく、 after 解析に適用されます。ここでは、タイムゾーン引数を使用して、既に解析されたDateTimeを調整します。最後のZは違いの世界を作ります。

デフォルトのタイムゾーンのソース

[〜#〜] jvm [〜#〜] は、最初にホストオペレーティングシステムからデフォルトのタイムゾーンを取得します。ただし、プログラマは次の方法でこれをオーバーライドできることに注意してください。

このオーバーライドを行うと、そのJVMで実行されているすべてのアプリのすべてのスレッドに影響します。したがって、JVMのデフォルトのタイムゾーンは通常ホストOSと同じですが、必ずしも同じではないことを知っておく必要があります。

52
Basil Bourque
      private String receivedFormat = "yyyy-MM-dd'T'HH:mm:ss", expectedFormat = "dd-MM-yyyy HH:mm:ss"; //Globall variables

        //Write these three lines in your Test Class and below 2 methods

        String dateString = "2018-08-14T07:00:00:00";
        String returnString = correctDateFormat(dateString, receivedFormat, expectedFormat);
        String result = getTimeInSelectedLocale(returnString);
    Log.i("Ayaz", "Date: " +result);



     /**
         * @param receivedDate
         * @param givenFormat
         * @param expectedFormat
         * @return returns date time in expected format
         */
        public static String correctDateFormat(String receivedDate, String givenFormat, String expectedFormat) {
            if (TextUtils.isEmpty(receivedDate)) {
                return "";
            }
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat(givenFormat);
            Date newDate = null;
            try {
                newDate = simpleDateFormat.parse(receivedDate);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            simpleDateFormat = new SimpleDateFormat(expectedFormat);
            receivedDate = simpleDateFormat.format(newDate);
            return receivedDate;
        }



        /**
         * @param dateString
         * @return passed string date in different locale, My Db is in IST so I an converting IST in different locale
         */
        public  String getTimeInSelectedLocale(String dateString) {
            if (TextUtils.isEmpty(dateString)) {
                return dateString;
            }
            SimpleDateFormat sdf = new SimpleDateFormat(expectedFormat);
            sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata")); //We want Indian time to change in different locale, so this line is compulsory, you can replace with your country
            Date date1 = null;
            try {
                date1 = sdf.parse(dateString);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            //below this line -> TimeZone.getTimeZone(TimeZone.getDefault().getID(), will return current locale for example for India "Asia/Kolkata" for UAE "Asia/Dubai"
            sdf.setTimeZone(TimeZone.getTimeZone(TimeZone.getDefault().getID())); //This line chooses current local in which you want time
            String localDate = sdf.format(date1);
            return localDate;
        }

//I am converting the IST time "2018-08-14T07:00:00:00"  into UAE(Duabai) "14-08-2018 05:30:00" and other countries
1
Ayaz Ahmad

あなたが探しているのは Joda ライブラリだと思います。答え here で指定されているCalendarまたはDateクラスよりも優れた機能を備えています。

この関数 は特に便利です。

0
BCza