Db2 11.1

Datums-, Zeit-und Zeitmarkenwerte, die zu Problemen in JDBC-und SQLJ-Anwendungen führen können

Sie erhalten möglicherweise unerwartete Ergebnisse in JDBC-und SQLJ-Anwendungen, wenn Sie Datums-, Zeit-und Zeitmarkenwerte verwenden, die nicht realen Datums-und Zeitangaben entsprechen.

Die folgenden Punkte können zu Problemen führen:

  • Verwendung der Stunde '24' für die Darstellung von Mitternacht
  • Verwendung eines Datums zwischen dem 5. Oktober 1582 und dem 14. Oktober 1582 (einschließlich)

Probleme mit der Verwendung der Stunde '24' als Mitternacht

Der IBM® Data Server Driver for JDBC and SQLJ verwendet Java™-Datentypen für die interne Verarbeitung von Eingabe-und Ausgabeparametern sowie ResultSet -Inhalt in JDBC-und SQLJ-Anwendungen. Der Java-Datentyp, der vom Treiber verwendet wird, basiert auf der besten Übereinstimmung für den entsprechenden SQL-Typ, wenn der Ziel-SQL-Typ dem Treiber bekannt ist.

Für Werte, die den SQL-Typen DATE, TIME oder TIMESTAMP zugeordnet oder abgerufen werden, verwendet der IBM Data Server Driver for JDBC and SQLJ java.sql.Date für DATE-SQL-Typen, java.sql.Time für TIME-SQL-Typen und java.sql.Timestamp für TIMESTAMP SQL-Typen.

Wenn Sie einen Zeichenfolgewert einem DATE-, TIME-oder TIMESTAMP-Ziel zuordnen, verwendet der IBM Data Server Driver for JDBC and SQLJ Java-Funktionen, um den Zeichenfolgewert in einen java.sql.Date-, java.sql.Time-oder java.sql.Timestamp-Wert umzuwandeln. Wenn eine Zeichenfolgedarstellung eines Datums-, Zeit-oder Zeitmarkenwerts nicht mit einem realen Datum oder Zeitpunkt übereinstimmt, passt Java den Wert an einen realen Datums-oder Zeitwert an. Insbesondere passt Java einen Stundenwert von '24' bis '00' am nächsten Tag an. Diese Anpassung kann zu einer Ausnahmebedingung für einen Zeitmarkenwert von '9999-12-31 24 :00:00.0' führen, da der Wert für das bereinigte Jahr '10000' wird.

Wichtig: Um unerwartete Ergebnisse zu vermeiden, wenn Sie Datums-, Zeit-oder Zeitmarkenwerte in JDBC-oder SQLJ-Anwendungen zuordnen oder abrufen, stellen Sie sicher, dass die Werte reale Datums-, Zeit-oder Zeitmarkenwerte sind. Verwenden Sie außerdem nicht '24' als Stundenkomponente eines Datums-oder Zeitmarkenwerts.

Wenn ein Wert, der nicht einem realen Datum oder einer Uhrzeit entspricht, z. B. ein Wert mit einer Stundenkomponente von '24', in einer Spalte TIME oder TIMESTAMP gespeichert ist, können Sie die Anpassung während des Abrufs vermeiden, indem Sie die SQL-Funktion CHAR für diese Spalte in der Anweisung SELECT ausführen, die eine ResultSet definiert. Wenn Sie die Funktion CHAR ausführen, wird der Datums-oder Zeitwert in einen Zeichenfolgewert auf der Datenbankseite konvertiert. Wenn Sie jedoch die Methode getTime oder getTimestamp verwenden, um diesen Wert aus der ResultSet abzurufen, konvertiert der IBM Data Server Driver for JDBC and SQLJ den Wert in einen java.sql.Timestamp-Typ oder einen java.sql.Timestamp-Typ, und Java passt den Wert an. Um eine Datumsanpassung zu vermeiden, führen Sie die Funktion CHAR für den Spaltenwert aus, und rufen Sie den Wert aus der ResultSet -Methode mit der Methode getString ab.

Die folgenden Beispiele zeigen die Ergebnisse der Aktualisierung von DATE-, TIME-oder TIMESTAMP-Spalten in JDBC-oder SQLJ-Anwendungen, wenn die Anwendungsdaten keine realen Daten oder Uhrzeiten darstellen.

Tabelle 1. Beispiele für die Aktualisierung von DATE-, TIME-oder TIMESTAMP-SQL-Werten mit Datums-, Zeit-oder Zeitmarkenwerten von Java , die keine realen Daten oder Uhrzeiten darstellen
Zeichenfolgeeingabewert Zieltyp in Datenbank Wert, der an die Tabellenspalte gesendet wird, oder Ausnahmebedingung
2008-13-35 DATUM 2009-02-04
25:00:00 ZEIT 01:00:00
24:00:00 ZEIT 00:00:00
2008-15-36 28 :63:74.0 TIMESTAMP 2009-04-06 05 :04:14.0
9999-12-31 24 :00:00.0 TIMESTAMP Ausnahme, da der angepasste Wert (10000-01-01 00 :00:00.0) das maximale Jahr 9999 überschreitet.

Die folgenden Beispiele veranschaulichen die Ergebnisse beim Abrufen von Daten aus TIMESTAMP-Spalten in JDBC-oder SQLJ-Anwendungen, wenn die Werte in diesen Spalten keine realen Daten oder Uhrzeiten darstellen.

Tabelle 2. Ergebnisse beim Abrufen von SQL-Werten des Typs DATE, TIME oder TIMESTAMP, die keine realen Datumsangaben oder Zeiten in Java-Anwendungsvariablen darstellen
Anweisung SELECT Wert in der Spalte TIMESTAMP TS_COL Zieltyp in Anwendung (getXXX-Methode für Abruf) Wert aus Tabellenspalte abgerufen
SELECT TS_COL FROM TABLE1 2000-01-01 24 :00:00.000000 java.sql.Timestamp ( getTimestamp ) 2000-01-02 00 :00:00.000000
SELECT TS_COL FROM TABLE1 2000-01-01 24 :00:00.000000 Zeichenfolge ( getString ) 2000-01-02 00 :00:00.000000
SELECT CHAR (TS_COL) FROM TABLE1 2000-01-01 24 :00:00.000000 java.sql.Timestamp ( getTimestamp ) 2000-01-02 00 :00:00.000000
SELECT CHAR (TS_COL) FROM TABLE1 2000-01-01 24 :00:00.000000 Zeichenfolge ( getString ) 2000-01-01 24 :00:00.000000 (keine Anpassung durch Java)

Probleme bei der Verwendung von Datumsangaben im Bereich vom 5. Oktober 1582 bis zum 14. Oktober 1582

Die Klassen Java java.util.Date und java.util.Timestamp verwenden den julianischen Kalender für Datumsangaben vor dem 4. Oktober 1582 und den gregorianischen Kalender für Datumsangaben, die mit dem 4. Oktober 1582 beginnen. Im Gregorianischen Kalender, dem 4. Oktober 1582, folgt der 15. Oktober 1582. Wenn ein Java-Programm einen java.util.Date -oder java.util.Timestamp -Wert feststellt, der zwischen dem 5. Oktober, 1582 und dem 14. Oktober 1582 (einschließlich) liegt, fügt Java diesem Datum 10 Tage hinzu. Daher wird ein DATE-oder TIMESTAMP-Wert in einer Db2-Tabelle, die einen Wert zwischen dem 5. Oktober 1582 und dem 14. Oktober 1582 enthält, in einem Java-Programm als java.util.Date -oder java.util.Timestamp -Wert zwischen dem 15. Oktober 1582 und dem 24. Oktober 1582 (einschließlich) abgerufen. Ein java.util.Date -oder java.util.Timestamp -Wert in einem Java-Programm, das zwischen dem 5. Oktober 1582 und dem 14. Oktober 1582 (einschließlich) liegt, wird in einer Db2-Tabelle als DATE-oder TIMESTAMP-Wert zwischen dem 15. Oktober 1582 und dem 24. Oktober 1582 (einschließlich) gespeichert.

Beispiel: Den 10. Oktober 1582 aus einer DATE-Spalte abrufen.

// DATETABLE verfügt über eine einzige Datumsspalte mit einer einzigen Zeile.
// Der zugehörige Wert lautet 1582-10-10.
java.sql.ResultSet rs = 
 statement.executeQuery(select * from DATETABLE);
rs.next();
System.out.println(rs.getDate(1)); // Der Wert wird als 1582-10-20 abgerufen.

Beispiel: Store October 10, 1582 in einer DATE-Spalte speichern.

java.sql.Date d = java.sql.Date.valueOf("1582-10-10");
java.sql.PreparedStatement ps = 
 c.prepareStatement("Insert into DATETABLE values(?)");
ps.setDate(1, d);
ps.executeUpdate(); // Der Wert wird als 1582-10-20 eingefügt. 

Um einen Wert im Bereich vom 5. Oktober 1582 bis zum 14. Oktober 1582 aus einer Db2-Tabelle ohne Datumsanpassung abzurufen, führen Sie die SQL-CHAR-Funktion für die Spalte DATE oder TIMESTAMP in der Anweisung SELECT aus, die eine ResultSet -Tabelle definiert. Wenn Sie die Funktion CHAR ausführen, wird der Datums-oder Zeitwert in einen Zeichenfolgewert auf der Datenbankseite konvertiert.

Um einen Wert im Bereich vom 5. Oktober 1582 bis zum 14. Oktober 1582 in einer Db2-Tabelle ohne Datumsanpassung zu speichern, können Sie eine der folgenden Methoden verwenden:
  • Verwenden Sie für eine JDBC-oder eine SQLJ-Anwendung die Methode setString , um den Wert einem Eingabeparameter für Zeichenfolgen zuzuordnen. Setzen Sie den Eingabeparameter als VARCHAR ab und führen Sie die Funktion DATE oder TIMESTAMP gegen das Ergebnis der Umsetzung aus. Speichern Sie anschließend das Ergebnis der Funktion DATE oder TIMESTAMP in der Spalte DATE oder TIMESTAMP.
  • Setzen Sie für eine JDBC-Anwendung die Eigenschaft Connection oder DataSource sendDataAsIs auf true und verwenden Sie die Methode setString , um den Datums-oder Zeitmarkenwert dem Eingabeparameter zuzuordnen. Führen Sie anschließend eine SQL-Anweisung aus, um den Zeichenfolgewert der Spalte DATE oder TIMESTAMP zuzuordnen.

Beispiel: Der 10. Oktober 1582 wird aus einer DATE-Spalte ohne Datumsanpassung abgerufen.

// DATETABLE verfügt über eine einzige Datumsspalte (DATECOL) mit einer einzigen Zeile.
// Der zugehörige Wert lautet 1582-10-10.
java.sql.ResultSet rs = 
 statement.executeQuery(SELECT CHAR(DATECOL) FROM DATETABLE);
rs.next();
System.out.println(rs.getString(1)); // Der Wert wird als 1582-10-10 abgerufen.

Beispiel: Store October 10, 1582, in einer DATE-Spalte ohne Datumsanpassung.

String s = "1582-10-10";
java.sql.Statement stmt = c.createStatement;
java.sql.PreparedStatement ps = 
 c.prepareStatement("Insert INTO DATETABLE VALUES " +
  "(DATE(CAST (? AS VARCHAR)))");
ps.setString(1, s);
ps.executeUpdate(); // Der Wert wird als 1582-10-10 eingefügt. 

Um eine Datumsanpassung zu vermeiden, setzen Sie die SQLJ-Option sqljAvoidTimeStampConversion auf true. Die SQLJ-Option sqljAvoidTimeStampConversion = true gibt die Zeitmarkendaten im CHAR-Format zurück.

Beispiel: Abruf vom 12. Oktober 1582 aus einer DATE-Spalte ohne Datumsanpassung.

import java.sql.*;
import javax.sql.DataSource;
import sqlj.runtime.ref.DefaultContext;
import com.ibm.db2.jcc.DBTimestamp;
import com.ibm.db2.jcc.DB2BaseDataSource;
#sql context DBContext;

public class UpdateTest 
{
// Zeitmarkenkonvertierung inaktivieren
static boolean SqljAvoidTimeStampConversion =true;
static DefaultContext ctx = null;
java.sql.Connection con;
 public static void main(String[] args) throws Exception
  { 
   javax.sql.DataSource ds = new com.ibm.db2.jcc.DB2SimpleDataSource(); 
     ((com.ibm.db2.jcc.DB2BaseDataSource) ds).setServerName 
                                             ("myserver.svl.ibm.com");
     ((com.ibm.db2.jcc.DB2BaseDataSource) ds).setPortNumber(446);
     ((com.ibm.db2.jcc.DB2BaseDataSource) ds).setDatabaseName("MYDB");
     ((com.ibm.db2.jcc.DB2BaseDataSource) ds).setDriverType(4);
     ((com.ibm.db2.jcc.DB2BaseDataSource) ds).setTimestampOutputType
                                             (DB2BaseDataSource.JCC_DBTIMESTAMP);
     ((com.ibm.db2.jcc.DB2BaseDataSource) ds).setSqljAvoidTimeStampConversion 
                                             (true); 
	   java.sql.Connection con = ds.getConnection("myid", "mypwd");
// An Methode 'insertAndSelectTimestamp' zu übergebende
// Verbindungskontextinstanz erstellen
     ctx = new DefaultContext(con); 
	   System.out.println(" Default Context  Obtained Successfully...");
     insertAndSelectTimestamp(ctx);   
     }
   public static  void insertAndSelectTimestamp
           (DefaultContext ctx)throws java.sql.SQLException 
     {         
		 String temp = "";    
      #sql[ctx]  { CREATE TABLE Mytable (C1 TIMESTAMP(12))}; 
// Tabelle erstellen
      System.out.println ("table created"); 
      #sql[ctx]  { INSERT INTO Mytable (C1) 
                   VALUES('1582-10-12-21.22.33.123456789012') }; 
// Wert aus Zeitraum vom 5. Okt. 1582 bis 14. Okt. 1582 einfügen
// Für sqljAvoidTimeStampConversion ist 'true' festgelegt,
// sodass der Wert unverändert gespeichert wird.
      System.out.println ("table inserted"); 
      #sql[ctx] { COMMIT};
// Einfügten Wert abrufen. Aufgrund von 'sqljAvoidTimeStampConversion = true'
// sollte die Zeitmarke nicht angepasst worden sein, sodass der
// Wert zurückgegeben werden müsste, den Sie eingegeben haben.
      #sql[ctx] { select C1 into :temp from Mytable };
      } 
}