Ich muss UTC dateTime in DB speichern.
Ich habe die in einer bestimmten Zeitzone angegebene dateTime in UTC konvertiert. dafür folgte ich dem folgenden Code.
Mein EingabedatumZeit ist "20121225 10:00:00 Z" Zeitzone ist "Asien / Kalkutta"
Mein Server / DB (Orakel) läuft in derselben Zeitzone (IST) "Asien / Kalkutta"
Holen Sie sich das Date-Objekt in dieser bestimmten Zeitzone
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()));
In DB speichern
if (tsSchedStartTime != null) {
stmt.setTimestamp(11, tsSchedStartTime);
} else {
stmt.setNull(11, java.sql.Types.DATE);
}
AUSGABE
DB (Orakel) hat das gleiche dateTime: "20121225 10:00:00
nicht in UTC angegeben gespeichert .
Ich habe aus dem unten stehenden SQL bestätigt.
select to_char(sched_start_time, 'yyyy/mm/dd hh24:mi:ss') from myTable
Mein DB-Server läuft auch in derselben Zeitzone "Asia / Calcutta"
Es gibt mir die folgenden Erscheinungen
Date.getTime()
ist nicht in UTC- Oder der Zeitstempel hat Auswirkungen auf die Zeitzone beim Speichern in DB. Was mache ich hier falsch?
Noch eine Frage:
Wird timeStamp.toString()
wie in der lokalen Zeitzone gedruckt java.util.date
? Nicht UTC?
java.sql.Timestamp
in UTC, wenn in einem TIMESTAMP-Feld ohne Zeitzoneninformationen gespeichert, verwendet es das entsprechende Datum / die entsprechende Uhrzeit in der aktuellen Zeitzone der virtuellen MaschineAntworten:
Obwohl es nicht explizit für
setTimestamp(int parameterIndex, Timestamp x)
Fahrer angegeben ist , müssen die vomsetTimestamp(int parameterIndex, Timestamp x, Calendar cal)
Javadoc festgelegten Regeln befolgt werden :Wenn Sie mit
setTimestamp(int parameterIndex, Timestamp x)
dem JDBC-Treiber anrufen , wird anhand der Zeitzone der virtuellen Maschine das Datum und die Uhrzeit des Zeitstempels in dieser Zeitzone berechnet. Dieses Datum und diese Uhrzeit werden in der Datenbank gespeichert. Wenn in der Datenbankspalte keine Zeitzoneninformationen gespeichert sind, gehen alle Informationen über die Zone verloren (was bedeutet, dass es an den Anwendungen liegt, die die Datenbank verwenden, um die zu verwenden dieselbe Zeitzone konsistent oder mit einem anderen Schema zur Erkennung der Zeitzone (dh in einer separaten Spalte speichern).Beispiel: Ihre lokale Zeitzone ist GMT + 2. Sie speichern "2012-12-25 10:00:00 UTC". Der in der Datenbank gespeicherte tatsächliche Wert lautet "2012-12-25 12:00:00". Sie rufen es erneut ab: Sie erhalten es erneut als "2012-12-25 10:00:00 UTC" zurück (jedoch nur, wenn Sie es mit abrufen
getTimestamp(..)
). Wenn jedoch eine andere Anwendung in der Zeitzone GMT + 0 auf die Datenbank zugreift, wird dies der Fall sein Rufen Sie den Zeitstempel als "2012-12-25 12:00:00 UTC" ab.Wenn Sie es in einer anderen Zeitzone speichern möchten, müssen Sie die
setTimestamp(int parameterIndex, Timestamp x, Calendar cal)
mit einer Kalenderinstanz in der erforderlichen Zeitzone verwenden. Stellen Sie einfach sicher, dass Sie beim Abrufen von Werten auch den entsprechenden Getter mit derselben Zeitzone verwenden (wenn Sie eineTIMESTAMP
Information ohne Zeitzone in Ihrer Datenbank verwenden).Angenommen, Sie möchten die tatsächliche GMT-Zeitzone speichern, müssen Sie Folgendes verwenden:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); stmt.setTimestamp(11, tsSchedStartTime, cal);
Mit JDBC 4.2 sollte ein kompatibler Treiber
java.time.LocalDateTime
(undjava.time.LocalTime
) fürTIMESTAMP
(undTIME
) durch unterstützenget/set/updateObject
. Diejava.time.Local*
Klassen haben keine Zeitzonen, daher muss keine Konvertierung angewendet werden (obwohl dies zu neuen Problemen führen kann, wenn Ihr Code eine bestimmte Zeitzone angenommen hat).quelle
toString()
aufjava.lang.Date
(undjava.lang.Timestamp
) immer präsentieren sie in der lokalen Zeitzone.Ich denke, die richtige Antwort sollte java.sql sein. Der Zeitstempel ist NICHT zeitzonenspezifisch. Der Zeitstempel setzt sich aus java.util.Date und einem separaten Nanosekundenwert zusammen. In dieser Klasse gibt es keine Zeitzoneninformationen. Genau wie Datum enthält diese Klasse einfach die Anzahl der Millisekunden seit dem 1. Januar 1970, 00:00:00 GMT + Nanos.
In PreparedStatement.setTimestamp (int parameterIndex, Timestamp x, Calendar cal) wird der Kalender vom Treiber verwendet, um die Standardzeitzone zu ändern. Timestamp hält jedoch immer noch Millisekunden in GMT.
Die API ist unklar, wie genau der JDBC-Treiber den Kalender verwenden soll. Anbieter scheinen sich frei zu fühlen, wie sie es interpretieren sollen, z. B. als ich das letzte Mal mit MySQL 5.5 Calendar gearbeitet habe, hat der Treiber den Kalender sowohl in PreparedStatement.setTimestamp als auch in ResultSet.getTimestamp einfach ignoriert.
quelle
Für MySQL haben wir eine Einschränkung. Im Treiber-MySQL-Dokument haben wir:
useTimezone=true useLegacyDatetimeCode=false serverTimezone=UTC
Wenn wir diese Parameter nicht verwenden und
setTimestamp or getTimestamp
mit oder ohne Kalender aufrufen , haben wir den Zeitstempel in der JVM-Zeitzone.Beispiel:
Die JVM-Zeitzone ist GMT + 2. In der Datenbank haben wir einen Zeitstempel: 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
Die erste Methode gibt Folgendes zurück: 1461100256000 = 19/04/2016 - 21:10:56 GMT
Die zweite Methode gibt Folgendes zurück: 1461100256000 = 19/04/2016 - 21:10:56 GMT
Die dritte Methode gibt Folgendes zurück: 1461085856000 = 19/04/2016 - 17:10:56 GMT
Wenn wir anstelle von Oracle dieselben Aufrufe verwenden, haben wir:
Die erste Methode gibt Folgendes zurück: 1461093056000 = 19/04/2016 - 19:10:56 GMT
Die zweite Methode gibt Folgendes zurück: 1461100256000 = 19/04/2016 - 21:10:56 GMT
Die dritte Methode gibt Folgendes zurück: 1461085856000 = 19/04/2016 - 17:10:56 GMT
NB: Es ist nicht erforderlich, die Parameter für Oracle anzugeben.
quelle
ALTER SESSION SET TIME_ZONE = 'UTC'
".Es ist spezifisch von Ihrem Fahrer. Sie müssen einen Parameter in Ihrem Java-Programm angeben, um ihm die Zeitzone mitzuteilen, die Sie verwenden möchten.
java -Duser.timezone="America/New_York" GetCurrentDateTimeZone
Weiter dies:
to_char(new_time(sched_start_time, 'CURRENT_TIMEZONE', 'NEW_TIMEZONE'), 'MM/DD/YY HH:MI AM')
Kann auch für die ordnungsgemäße Handhabung der Konvertierung von Nutzen sein. Von hier genommen
quelle
Die Antwort ist, dass dies
java.sql.Timestamp
ein Chaos ist und vermieden werden sollte. Verwenden Siejava.time.LocalDateTime
stattdessen.Warum ist es ein Chaos? Aus dem
java.sql.Timestamp
JavaDoc ist ajava.sql.Timestamp
ein "Thin Wrapper"java.util.Date
, mit dem die JDBC-API dies als SQL TIMESTAMP-Wert identifizieren kann. Von demjava.util.Date
JavaDoc geht hervor, dass "dieDate
Klasse die koordinierte Weltzeit (UTC) widerspiegeln soll". Aus der ISO SQL-Spezifikation geht hervor, dass ein TIMESTAMP OHNE ZEITZONE "ein Datentyp ist, der datetime ohne Zeitzone ist". TIMESTAMP ist eine Kurzbezeichnung für TIMESTAMP WITHOUT TIME ZONE. Einjava.sql.Timestamp
"reflektiert" UTC, während SQL TIMESTAMP "ohne Zeitzone" ist.weil
java.sql.Timestamp
UTC seine Methoden widerspiegelt, werden Konvertierungen angewendet. Dies führt zu keinerlei Verwirrung. Aus SQL-Sicht ist es nicht sinnvoll, einen SQL-TIMESTAMP-Wert in eine andere Zeitzone zu konvertieren, da ein TIMESTAMP keine Zeitzone zum Konvertieren hat. Was bedeutet es, 42 in Fahrenheit umzurechnen? Es bedeutet nichts, weil 42 keine Temperatureinheiten hat. Es ist nur eine bloße Zahl. Ebenso können Sie einen TIMESTAMP von 2020-07-22T10: 38: 00 nicht nach Americas / Los Angeles konvertieren, da sich 2020-07-22T10: 30: 00 in keiner Zeitzone befindet. Es ist nicht in UTC oder GMT oder irgendetwas anderem. Es ist eine nackte Datumszeit.java.time.LocalDateTime
ist auch eine bloße Datumszeit. Es hat keine Zeitzone, genau wie SQL TIMESTAMP. Keine seiner Methoden wendet irgendeine Art von Zeitzonenumwandlung an, wodurch das Verhalten viel einfacher vorherzusagen und zu verstehen ist. Also nicht benutzenjava.sql.Timestamp
. Verwenden Siejava.time.LocalDateTime
.LocalDateTime ldt = rs.getObject(col, LocalDateTime.class); ps.setObject(param, ldt, JDBCType.TIMESTAMP);
quelle
Mit der folgenden Methode können Sie den Zeitstempel in einer Datenbank speichern, die für Ihre gewünschte Zone / Zonen-ID spezifisch ist.
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Calcutta")) ; Timestamp timestamp = Timestamp.valueOf(zdt.toLocalDateTime());
Ein häufiger Fehler, den Menschen machen, ist die Verwendung
LocaleDateTime
darin, den Zeitstempel dieses Augenblicks abzurufen, der alle für Ihre Zone angegebenen Informationen verwirft, selbst wenn Sie später versuchen, sie zu konvertieren. Es versteht die Zone nicht.Bitte beachten Sie,
Timestamp
ist von der Klassejava.sql.Timestamp
.quelle