95

UTC dateTime を DB に保存する必要があります。
特定のタイムゾーンで指定された dateTime を UTC に変換しました。そのために、以下のコードに従いました。
私の入力dateTimeは「20121225 10:00:00 Z」です。タイムゾーンは「アジア/カルカッタ」です。
サーバー/DB(オラクル)は同じタイムゾーン(IST)「アジア/カルカッタ」で実行されています。

この特定のタイムゾーンで Date オブジェクトを取得します

        String date = "20121225 10:00:00 Z";
        String timeZoneId = "Asia/Calcutta";
        TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);

        DateFormat dateFormatLocal = new SimpleDateFormat("yyyyMMdd HH:mm:ss z");
                    //This date object is given time and given timezone
        java.util.Date parsedDate = dateFormatLocal.parse(date + " "  
                         + timeZone.getDisplayName(false, TimeZone.SHORT));

        if (timeZone.inDaylightTime(parsedDate)) {
            // We need to re-parse because we don't know if the date
            // is DST until it is parsed...
            parsedDate = dateFormatLocal.parse(date + " "
                    + timeZone.getDisplayName(true, TimeZone.SHORT));
        }

       //assigning to the java.sql.TimeStamp instace variable
        obj.setTsSchedStartTime(new java.sql.Timestamp(parsedDate.getTime()));

DBに格納

        if (tsSchedStartTime != null) {
            stmt.setTimestamp(11, tsSchedStartTime);
        } else {
            stmt.setNull(11, java.sql.Types.DATE);
        }

出力

dateTime: "20121225 10:00:00DB(オラクル)はUTCではなく同じものを保存しています。

以下のSQLから確認しました。

     select to_char(sched_start_time, 'yyyy/mm/dd hh24:mi:ss') from myTable

私のDBサーバーも同じタイムゾーン「アジア/カルカッタ」で実行されています

それは私に以下の外観を与えます

  1. Date.getTime()はUTCではありません
  2. または、Timestamp は DB への保存中にタイムゾーンに影響を与えます。ここで何が間違っていますか?

もう 1 つの質問:

timeStamp.toString()のようにローカルタイムゾーンで印刷されjava.util.dateますか? UTC ではないのですか?

4

7 に答える 7

113

setTimestamp(int parameterIndex, Timestamp x)ドライバーには明示的に指定されていませんが、 setTimestamp(int parameterIndex, Timestamp x, Calendar cal)javadocによって確立されたルールに従う必要があります。

java.sql.Timestamp指定されたオブジェクトを使用して、指定されたパラメータを指定された値に設定しCalendarます。ドライバーはCalendarオブジェクトを使用してSQLTIMESTAMP値を作成し、SQL値をデータベースに送信します。オブジェクトを使用するCalendarと、ドライバーはカスタムタイムゾーンを考慮してタイムスタンプを計算できます。オブジェクトが指定されていない場合Calendar、ドライバーはデフォルトのタイムゾーンを使用します。これは、アプリケーションを実行している仮想マシンのタイムゾーンです。

JDBCドライバーを使用して呼び出すとsetTimestamp(int parameterIndex, Timestamp x)、仮想マシンのタイムゾーンを使用して、そのタイムゾーンのタイムスタンプの日付と時刻が計算されます。この日時はデータベースに保存されるものであり、データベース列にタイムゾーン情報が保存されていない場合、ゾーンに関する情報はすべて失われます(つまり、データベースを使用するアプリケーションは、同じタイムゾーンを一貫して作成するか、タイムゾーンを識別するための別のスキームを考え出します(つまり、別の列に保存します)。

例:ローカルタイムゾーンはGMT+2です。「2012-12-2510:00:00UTC」を保存します。データベースに保存されている実際の値は「2012-12-2512:00:00」です。再度取得します。「2012-12-2510:00:00 UTC」として再度取得しますが(ただし、を使用して取得した場合のみgetTimestamp(..))、別のアプリケーションがタイムゾーンGMT + 0でデータベースにアクセスすると、タイムスタンプを「2012-12-2512:00:00UTC」として取得します。

別のタイムゾーンに保存するsetTimestamp(int parameterIndex, Timestamp x, Calendar cal)場合は、必要なタイムゾーンのCalendarインスタンスでを使用する必要があります。値を取得するときは、同じタイムゾーンで同等のゲッターも使用するようにTIMESTAMPしてください(データベースでタイムゾーンなしの情報を使用する場合)。

したがって、実際のGMTタイムゾーンを保存する場合は、次を使用する必要があります。

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
stmt.setTimestamp(11, tsSchedStartTime, cal);

JDBC 4.2では、準拠ドライバーは(および)から(および)までをサポートするjava.time.LocalDateTime必要java.time.LocalTimeTIMESTAMPありTIMEますget/set/updateObject。クラスにはjava.time.Local*タイムゾーンがないため、変換を適用する必要はありません(ただし、コードが特定のタイムゾーンを想定している場合は、新しい一連の問題が発生する可能性があります)。

于 2012-12-28T14:11:02.117 に答える
38

正しい答えは java.sql.Timestamp はタイムゾーン固有ではありません。Timestamp は、java.util.Date と別のナノ秒値の合成です。このクラスにはタイムゾーン情報がありません。したがって、Date と同様に、このクラスは 1970 年 1 月 1 日 00:00:00 GMT + nanos からのミリ秒数を単純に保持します。

PreparedStatement.setTimestamp(int parameterIndex, Timestamp x, Calendar cal) では、デフォルトのタイムゾーンを変更するためにドライバが Calendar を使用します。しかし、Timestamp は依然として GMT でミリ秒を保持します。

API は、JDBC ドライバーが Calendar をどのように使用することになっているのかについて明確ではありません。プロバイダはそれをどのように解釈するか自由に考えているようです。たとえば、前回 MySQL 5.5 Calendar を使用したとき、ドライバは PreparedStatement.setTimestamp と ResultSet.getTimestamp の両方で Calendar を単純に無視しました。

于 2012-12-28T14:42:50.793 に答える
6

Mysql には制限があります。ドライバー Mysql docには、次のものがあります。

以下は、MySQL Connector/J の既知の問題と制限事項です。 Connector/J が結果セットで getTimeStamp() メソッドを使用して夏時間 (DST) 切り替え日のタイムスタンプを取得する場合、返される値の一部が間違っている可能性があります。データベースへの接続時に次の接続オプションを使用すると、エラーを回避できます。

useTimezone=true
useLegacyDatetimeCode=false
serverTimezone=UTC

したがって、このパラメーターを使用せず、カレンダーを使用して呼び出すsetTimestamp or getTimestampか、カレンダーを使用せずに呼び出すと、jvm タイムゾーンにタイムスタンプがあります。

例 :

jvm のタイムゾーンは GMT+2 です。データベースには、タイムスタンプがあります: 1461100256 = 19/04/16 21:10:56,000000000 GMT

Properties props = new Properties();
props.setProperty("user", "root");
props.setProperty("password", "");
props.setProperty("useTimezone", "true");
props.setProperty("useLegacyDatetimeCode", "false");
props.setProperty("serverTimezone", "UTC");
Connection con = DriverManager.getConnection(conString, props);
......
Calendar nowGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Calendar nowGMTPlus4 = Calendar.getInstance(TimeZone.getTimeZone("GMT+4"));
......
rs.getTimestamp("timestampColumn");//Oracle driver convert date to jvm timezone and Mysql convert date to GMT (specified in the parameter)
rs.getTimestamp("timestampColumn", nowGMT);//convert date to GMT 
rs.getTimestamp("timestampColumn", nowGMTPlus4);//convert date to GMT+4 timezone

最初のメソッドの戻り値: 1461100256000 = 19/04/2016 - 21:10:56 GMT

2 番目のメソッドの戻り値: 1461100256000 = 19/04/2016 - 21:10:56 GMT

3 番目のメソッドの戻り値: 1461085856000 = 19/04/2016 - 17:10:56 GMT

Oracle の代わりに、同じ呼び出しを使用すると、次のようになります。

最初のメソッドの戻り値: 1461093056000 = 19/04/2016 - 19:10:56 GMT

2 番目のメソッドの戻り値: 1461100256000 = 19/04/2016 - 21:10:56 GMT

3 番目のメソッドの戻り値: 1461085856000 = 19/04/2016 - 17:10:56 GMT

注意 : Oracle のパラメータを指定する必要はありません。

于 2016-05-02T13:06:28.570 に答える
6

以下の方法を使用して、目的のゾーン/ゾーン ID に固有のデータベースにタイムスタンプを保存できます。

ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Calcutta")) ;
Timestamp timestamp = Timestamp.valueOf(zdt.toLocalDateTime());

人々が行うよくある間違いはLocaleDateTime、後で変換しようとしても、ゾーンに固有の情報を破棄するその瞬間のタイムスタンプを取得することです。ゾーンを理解していません。

Timestampクラスですのでご注意くださいjava.sql.Timestamp

于 2020-07-24T14:53:06.090 に答える
5

それはあなたのドライバーに固有です。Java プログラムにパラメータを指定して、使用するタイム ゾーンを指定する必要があります。

java -Duser.timezone="America/New_York" GetCurrentDateTimeZone

さらにこれ:

to_char(new_time(sched_start_time, 'CURRENT_TIMEZONE', 'NEW_TIMEZONE'), 'MM/DD/YY HH:MI AM')

変換を適切に処理する際にも役立つ場合があります。ここから撮影

于 2012-12-28T14:01:46.577 に答える