再現可能なシナリオを示すために、私は次のことをしています
現在のシステム時刻(ローカル時刻)を取得します
現地時間をUTCに変換する//ここまでうまく動作する
UTC時間を逆にし、現地時間に戻します。 3つの異なるアプローチ(以下にリスト)に従いましたが、3つのアプローチはすべてUTCのみで時刻を保持します。
{
long ts = System.currentTimeMillis();
Date localTime = new Date(ts);
String format = "yyyy/MM/dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat (format);
// Convert Local Time to UTC (Works Fine)
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date gmtTime = new Date(sdf.format(localTime));
System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:" + gmtTime.toString() + "-" + gmtTime.getTime());
// Reverse Convert UTC Time to Locale time (Doesn't work) Approach 1
sdf.setTimeZone(TimeZone.getDefault());
localTime = new Date(sdf.format(gmtTime));
System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:" + gmtTime.toString() + "-" + gmtTime.getTime());
// Reverse Convert UTC Time to Locale time (Doesn't work) Approach 2 using DateFormat
DateFormat df = new SimpleDateFormat (format);
df.setTimeZone(TimeZone.getDefault());
localTime = df.parse((df.format(gmtTime)));
System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:" + gmtTime.toString() + "-" + gmtTime.getTime());
// Approach 3
Calendar c = new GregorianCalendar(TimeZone.getDefault());
c.setTimeInMillis(gmtTime.getTime());
System.out.println("Local Time " + c.toString());
}
前述のようにJodaを使用することもお勧めします。
標準のJavaDate
オブジェクトを使用して問題を解決するには、次のようにします。
// **** YOUR CODE **** BEGIN ****
long ts = System.currentTimeMillis();
Date localTime = new Date(ts);
String format = "yyyy/MM/dd HH:mm:ss";
SimpleDateFormat sdf = new SimpleDateFormat(format);
// Convert Local Time to UTC (Works Fine)
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date gmtTime = new Date(sdf.format(localTime));
System.out.println("Local:" + localTime.toString() + "," + localTime.getTime() + " --> UTC time:"
+ gmtTime.toString() + "," + gmtTime.getTime());
// **** YOUR CODE **** END ****
// Convert UTC to Local Time
Date fromGmt = new Date(gmtTime.getTime() + TimeZone.getDefault().getOffset(localTime.getTime()));
System.out.println("UTC time:" + gmtTime.toString() + "," + gmtTime.getTime() + " --> Local:"
+ fromGmt.toString() + "-" + fromGmt.getTime());
出力:
Local:Tue Oct 15 12:19:40 CEST 2013,1381832380522 --> UTC time:Tue Oct 15 10:19:40 CEST 2013,1381825180000
UTC time:Tue Oct 15 10:19:40 CEST 2013,1381825180000 --> Local:Tue Oct 15 12:19:40 CEST 2013-1381832380000
更新: Joda-Time プロジェクトは現在 メンテナンスモード であり、チームは移行をアドバイスしています Java.time クラスへ。 Tutorial by Oracle を参照してください。
my other Answer 業界をリードするJava.timeクラスの使用を参照してください。
通常、StackOverflow.comでは、代替技術を提案して特定の質問に答えることは悪いと考えています。ただし、Java 7以前にバンドルされている日付、時刻、カレンダークラスの場合、これらのクラスは設計と実行の両方で非常に悪名高いため、3番目のクラスを使用することをお勧めします代わりにパーティライブラリ: Joda-Time 。
Joda-Timeは 不変オブジェクト を作成することで機能します。したがって、DateTimeオブジェクトのタイムゾーンを変更するのではなく、異なるタイムゾーンを割り当てて新しいDateTimeをインスタンス化します。
Joda-Timeでは、ローカル時間とUTC時間の両方を使用する際の中心的な関心事は非常に単純で、わずか3行のコードしか必要ありません。
_ org.joda.time.DateTime now = new org.joda.time.DateTime();
System.out.println( "Local time in ISO 8601 format: " + now + " in zone: " + now.getZone() );
System.out.println( "UTC (Zulu) time zone: " + now.toDateTime( org.joda.time.DateTimeZone.UTC ) );
_
北米の西海岸で実行した場合の出力は次のとおりです。
_Local time in ISO 8601 format: 2013-10-15T02:45:30.801-07:00
_
UTC (Zulu) time zone: 2013-10-15T09:45:30.801Z
これは、いくつかの例と追加のコメントを含むクラスです。 Joda-Time 2.5を使用します。
_/**
* Created by Basil Bourque on 2013-10-15.
* © Basil Bourque 2013
* This source code may be used freely forever by anyone taking full responsibility for doing so.
*/
public class TimeExample {
public static void main(String[] args) {
// Joda-Time - The popular alternative to Sun/Oracle's notoriously bad date, time, and calendar classes bundled with Java 8 and earlier.
// http://www.joda.org/joda-time/
// Joda-Time will become outmoded by the JSR 310 Date and Time API introduced in Java 8.
// JSR 310 was inspired by Joda-Time but is not directly based on it.
// http://jcp.org/en/jsr/detail?id=310
// By default, Joda-Time produces strings in the standard ISO 8601 format.
// https://en.wikipedia.org/wiki/ISO_8601
// You may output to strings in other formats.
// Capture one moment in time, to be used in all the examples to follow.
org.joda.time.DateTime now = new org.joda.time.DateTime();
System.out.println( "Local time in ISO 8601 format: " + now + " in zone: " + now.getZone() );
System.out.println( "UTC (Zulu) time zone: " + now.toDateTime( org.joda.time.DateTimeZone.UTC ) );
// You may specify a time zone in either of two ways:
// • Using identifiers bundled with Joda-Time
// • Using identifiers bundled with Java via its TimeZone class
// ----| Joda-Time Zones |---------------------------------
// Time zone identifiers defined by Joda-Time…
System.out.println( "Time zones defined in Joda-Time : " + Java.util.Arrays.toString( org.joda.time.DateTimeZone.getAvailableIDs().toArray() ) );
// Specify a time zone using DateTimeZone objects from Joda-Time.
// http://joda-time.sourceforge.net/apidocs/org/joda/time/DateTimeZone.html
org.joda.time.DateTimeZone parisDateTimeZone = org.joda.time.DateTimeZone.forID( "Europe/Paris" );
System.out.println( "Paris France (Joda-Time zone): " + now.toDateTime( parisDateTimeZone ) );
// ----| Java Zones |---------------------------------
// Time zone identifiers defined by Java…
System.out.println( "Time zones defined within Java : " + Java.util.Arrays.toString( Java.util.TimeZone.getAvailableIDs() ) );
// Specify a time zone using TimeZone objects built into Java.
// http://docs.Oracle.com/javase/8/docs/api/Java/util/TimeZone.html
Java.util.TimeZone parisTimeZone = Java.util.TimeZone.getTimeZone( "Europe/Paris" );
System.out.println( "Paris France (Java zone): " + now.toDateTime(org.joda.time.DateTimeZone.forTimeZone( parisTimeZone ) ) );
}
}
_
Instant.now() // Capture the current moment in UTC.
.atZone( ZoneId.systemDefault() ) // Adjust into the JVM's current default time zone. Same moment, different wall-clock time. Produces a `ZonedDateTime` object.
.toInstant() // Extract a `Instant` (always in UTC) object from the `ZonedDateTime` object.
.atZone( ZoneId.of( "Europe/Paris" ) ) // Adjust the `Instant` into a specific time zone. Renders a `ZonedDateTime` object. Same moment, different wall-clock time.
.toInstant() // And back to UTC again.
最新のアプローチでは、面倒な古いレガシー日時クラス(Date
、Calendar
など)に取って代わるJava.timeクラスを使用します。
Wordの「ローカル」の使用は、Java.timeクラスでの使用と矛盾します。 Java.timeでは、「ローカル」はany局所性またはall局所性を意味しますが、特定の1つの局所性を意味しません。名前が「Local…」で始まるJava.timeクラスには、すべてタイムゾーンまたはUTCからのオフセットという概念がありません。したがって、それらは特定の瞬間を表すnotであり、notのタイムライン上のポイントですが、あなたの質問はすべての瞬間、さまざまな壁時計の時間を通して見たタイムライン上のポイントです。
現在のシステム時刻(ローカル時刻)を取得します
UTCで現在の瞬間をキャプチャする場合は、Instant
を使用します。 Instant
クラスは、 [〜#〜] utc [〜#〜] のタイムライン上の瞬間を ナノ秒 (小数の9桁までの解像度)で表します)。
Instant instant = Instant.now() ; // Capture the current moment in UTC.
ZoneId
を適用してZonedDateTime
を取得することにより、タイムゾーンに調整します。同じ瞬間、タイムライン上の同じポイント、異なる壁時計時間。
continent/region
、 America/Montreal
、またはAfrica/Casablanca
などのPacific/Auckland
の形式で 適切なタイムゾーン名 を指定します。 EST
やIST
などの3〜4文字の略語は、notの真のタイムゾーンであり、標準化されておらず、一意(!)でもないため使用しないでください。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, different wall-clock time.
ショートカットとして、Instant
の使用をスキップしてZonedDateTime
を取得できます。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
現地時間をUTCに変換する//ここまでうまく動作する
Instant
からZonedDateTime
を抽出することにより、ゾーン化された日時からUTCに調整できます。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
Instant instant = zdt.toInstant() ;
UTC時間を逆にし、現地時間に戻します。
上記のように、ZoneId
を適用して、特定の地域の人々(タイムゾーン)が使用する別の実時間に同じ瞬間を調整します。
Instant instant = Instant.now() ; // Capture current moment in UTC.
ZoneId zDefault = ZoneId.systemDefault() ; // The JVM's current default time zone.
ZonedDateTime zdtDefault = instant.atZone( zDefault ) ;
ZoneId zTunis = ZoneId.of( "Africa/Tunis" ) ; // The JVM's current default time zone.
ZonedDateTime zdtTunis = instant.atZone( zTunis ) ;
ZoneId zAuckland = ZoneId.of( "Pacific/Auckland" ) ; // The JVM's current default time zone.
ZonedDateTime zdtAuckland = instant.atZone( zAuckland ) ;
ゾーン日時からUTCに戻り、ZonedDateTime::toInstant
を呼び出します。概念的には、ZonedDateTime = Instant + ZoneIdと考えてください。
Instant instant = zdtAuckland.toInstant() ;
これらのオブジェクト、Instant
および3つのZonedDateTime
オブジェクトはすべて、まったく同じ瞬間、つまり履歴の同じ時点を表します。
3つの異なるアプローチ(以下にリスト)に従いましたが、3つのアプローチはすべてUTCのみで時刻を保持します。
これらのひどいDate
、Calendar
、およびGregorianCalendar
クラスを使用してコードを修正しようとすることを忘れてください。彼らは悪いデザインと欠陥の惨めな混乱です。二度と触れる必要はありません。まだJava.timeに更新されていない古いコードとのインターフェイスが必要な場合は、古いクラスに追加された新しい変換メソッドを介して前後に変換できます。
Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは、面倒な古い legacy のような日時クラスに取って代わります Java.util.Date
、 Calendar
、& SimpleDateFormat
。
Joda-Time プロジェクトは、現在 メンテナンスモード であり、 Java.time クラスへの移行を推奨しています。
詳細については、 Oracle Tutorial を参照してください。また、多くの例と説明についてはStack Overflowを検索してください。仕様は JSR 31 です。
Java.timeオブジェクトをデータベースと直接交換できます。 JDBC 4.2 以降に準拠する JDBCドライバー を使用します。文字列もJava.sql.*
クラスも必要ありません。
Java.timeクラスはどこで入手できますか?
ThreeTen-Extra プロジェクトは、Java.timeを追加のクラスで拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。 Interval
、 YearWeek
、 YearQuarter
、および more 。
私は合唱団に参加していますが、今では長く古くなったクラスDate
、Calendar
、SimpleDateFormat
および友人をスキップすることをお勧めします。特に、使用したDate(String)
コンストラクターのように、Date
クラスの非推奨のメソッドとコンストラクターを使用することに対して警告します。タイムゾーンを越えて確実に機能しないため、使用しないでください。そして、はい、そのクラスのコンストラクタとメソッドのほとんどは非推奨です。
あなたが質問をしたとき、Joda-Timeは(私が知っているすべてから)明らかにより良い代替手段でしたが、時間が再び動きました。現在、Joda-Timeはほぼ完成したプロジェクトであり、その開発者は、代わりに_Java.time
_、最新のJava日時APIを使用することを推奨しています。方法をお見せします。
_ ZonedDateTime localTime = ZonedDateTime.now(ZoneId.systemDefault());
// Convert Local Time to UTC
OffsetDateTime gmtTime
= localTime.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC);
System.out.println("Local:" + localTime.toString()
+ " --> UTC time:" + gmtTime.toString());
// Reverse Convert UTC Time to Local time
localTime = gmtTime.atZoneSameInstant(ZoneId.systemDefault());
System.out.println("Local Time " + localTime.toString());
_
手始めに、コードがあなたのコードの半分の長さであるだけでなく、読みやすいことにも注意してください。
私のコンピューターでは、コードが印刷されます:
_Local:2017-09-02T07:25:46.211+02:00[Europe/Berlin] --> UTC time:2017-09-02T05:25:46.211Z
Local Time 2017-09-02T07:25:46.211+02:00[Europe/Berlin]
_
エポックからのミリ秒を省きました。あなたはあなたの質問のようにSystem.currentTimeMillis();
からいつでもそれらを取得することができ、それらはタイムゾーンから独立しているので、私はそれらがここで面白いとは思いませんでした。
私はためらいながら変数名localTime
を保持しました。いい名前だと思います。最新のAPIにはLocalTime
というクラスがあります。そのため、LocalTime
型を持たないオブジェクトに対して、大文字ではなくその名前を使用すると、一部を混乱させる可能性があります(LocalTime
は適切な変換を行うためにここに保持する必要があるタイムゾーン情報を保持しません。また、日付ではなく時刻のみを保持します。
現地時間からUTCへの変換は不正確で不可能でした
古いDate
クラスはタイムゾーン情報を保持していないため(内部的には常にUTCを使用していると言えます)、あるタイムゾーンから別のタイムゾーンにDate
を変換するようなことはありません。 。コンピューターでコードを実行したとき、印刷された最初の行は次のとおりでした。
_Local:Sat Sep 02 07:25:45 CEST 2017,1504329945967 --> UTC time:Sat Sep 02 05:25:45 CEST 2017-1504322745000
_
_07:25:45 CEST
_はもちろん正しいです。正しいUTC時間は_05:25:45 UTC
_でしたが、再びCEST
と表示されますが、これは正しくありません。
これでDate
クラスは二度と必要なくなりますが、:-)に行くなら、必読は Jon Skeetのコーディングに関するすべてのJava.util.Dateについて ですブログ。
質問:Javaバージョンで最新のAPIを使用できますか?
少なくともJava6を使用している場合、可能です。
既知のタイムゾーンの日付があります(ここEurope/Madrid
)、およびターゲットタイムゾーン(UTC
)
次の2つのSimpleDateFormatが必要です。
long ts = System.currentTimeMillis(); Date localTime = new Date(ts); SimpleDateFormat sdfLocal = new SimpleDateFormat( "yyyy/MM/dd HH:mm:ss "); sdfLocal.setTimeZone(TimeZone.getTimeZone(" Europe/Madrid ")); SimpleDateFormat sdfUTC = new SimpleDateFormat(" yyyy/MM/dd HH:mm:ss "); sdfUTC.setTimeZone(TimeZone.getTimeZone(" UTC ")); //ローカル時間をUTC に変換日付utcTime = sdfLocal.parse(sdfUTC.format(localTime)); System.out.println( "Local:" + localTime.toString()+ "、" + localTime.getTime()+ "- > UTC時間: "+ utcTime.toString()+"-"+ utcTime.getTime()); // UTC時間をロケール時間に逆変換 localTime = sdfUTC .parse(sdfLocal.format(utcTime)); System.out.println( "UTC:" + utcTime.toString()+ "、" + utcTime.getTime()+ "->現地時間: "+ localTime.toString()+"-"+ localTime 。時間をもらう());
したがって、動作を確認したら、このメソッドをユーティリティに追加できます。
public Date convertDate(Date dateFrom、String fromTimeZone、String toTimeZone)throws ParseException { String pattern = "yyyy/MM/dd HH:mm:ss"; SimpleDateFormat sdfFrom = new SimpleDateFormat(パターン); sdfFrom.setTimeZone(TimeZone.getTimeZone(fromTimeZone)); SimpleDateFormat sdfTo = new SimpleDateFormat(パターン); sdfTo.setTimeZone (TimeZone.getTimeZone(toTimeZone)); Date dateTo = sdfFrom.parse(sdfTo.format(dateFrom)); return dateTo; }
Joda Timeの使用を強くお勧めします http://joda-time.sourceforge.net/faq.html