2013-04-18 6 views
7

Ich habe eine Abfrage in MySQL, die wie dieser 2 Tage, vergleichtTime-Zone Diskrepanz in MySQL und Java

convert_tz(updatedDate,'+05:30','-05:00') < ? 

die Konvertierungsfunktion den Wert der Spalte CreatedDate in US-Zeit zurück. wenn ich diese Abfrage in MySQL Query Browser laufen wie

convert_tz(updatedDate,'+05:30','-05:00') < '2013-04-14 09:30:00' 

gibt es mir korrekte Werte zum Beispiel

product count 
------- ------ 
    A  123 
    B  7 

Nun, ich dies in Java setze mit PreparedStatement wie diese

pst.setTimestamp(1, new java.sql.Timestamp(end.getTimeInMillis())); 

       rs=pst.executeQuery(); 
       System.out.println("=====new Open Tickets Query executed====="); 
       System.out.println(pst); 

Die letzte Zeile gibt die gesamte Abfrage aus, und der eingestellte Wert ist

convert_tz(updatedDate,'+05:30','-05:00') < '2013-04-14 09:30:00' 

aber es gibt mir verschiedene Werte wie diese

product count 
------- ------ 
    A  155 
    B  19 

Also, vermutete ich, dass es Time-Zone Problem ist, ich meinen Code

end.setTimeZone(TimeZone.getTimeZone("America/New York")); 
pst.setTimestamp(1, new java.sql.Timestamp(end.getTimeInMillis())); 

       rs=pst.executeQuery(); 
       System.out.println("=====new Open Tickets Query executed====="); 
       System.out.println(pst); 

zu

geändert, aber es gibt immer noch gleiche falsche Ergebnis.

Mehr Info: Wie Ich gründe Kalender endet Variable

Ich habe eine Web-Anwendung, die mir Datum string "2013.04.14 09.30.00" Auch

  DateFormat df1=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); 
       Calendar end=Calendar.getInstance(); 
       end.setTime(df1.parse(endString)); 
       end.set(Calendar.HOUR, 9); 
       end.set(Calendar.MINUTE, 30); 
       end.set(Calendar.SECOND, 0); 

gibt , für Experiment I mit java.util.Date versucht Objekt, das es mir richtiges Ergebnis gibt den Code wird wie folgt

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); 
end.setTime(sdf.parse("2012-10-01 00:00:00")); 
pst.setTimestamp(1, new java.sql.Timestamp(end.getTime())); 

UPDATE: - Wenn ich eine veraltete Methode verwenden, die Antwort ist richtig

pst.setTimestamp(1, new java.sql.Timestamp(octDate.get(Calendar.YEAR)-1900,octDate.get(Calendar.MONTH),octDate.get(Calendar.DATE),octDate.get(Calendar.HOUR),octDate.get(Calendar.MINUTE),octDate.get(Calendar.SECOND),0)); 
pst.setTimestamp(2, new java.sql.Timestamp(end.get(Calendar.YEAR)-1900,end.get(Calendar.MONTH),end.get(Calendar.DATE),end.get(Calendar.HOUR),end.get(Calendar.MINUTE),end.get(Calendar.SECOND),0)); 

UPDATE 2: - Nach dem Vorschlag der ersten Antwort, die ich tat dies

1) SELECT NOW() in mysql ausgeführt und es kehrte '2013-04-22 11:56:08'

2) ausgeführt

System.out.println(new Date(System.currentTimeMillis())); 

Ausgabe: Mon Apr 22 11:56:25 IST 2013

bedeutet, dass beide Systeme gleiche Zeitzone

+0

MySQL Zeitzoneninformationen hat keinen Einfluss auf Ihr Problem , da MySQL nicht die Aufgabe übernimmt, das Datum zu analysieren. Siehe meine Antwort. –

Antwort

6

Hintergrund: Eine überraschend häufige - und große - Fehlvorstellung, die sogar von brillanten Programmierern geteilt wird, ist die Vorstellung, dass gespeicherte Zeitstempel (in Ihrer Datenbank, Datum, Kalender, Zeitstempel usw.) irgendwie Zeitzoneninformationen haben. Sie nicht. Ein Zeitstempel (jedenfalls bis Java 8) wird als die Anzahl der Millisekunden seit Mitternacht am 1. Januar 1970 UTC gespeichert. Ende des Satzes. Das einzige, was die Zeitzone einstellt, ist, dem Computer genügend Informationen zur Verfügung zu stellen, um diesen Zeitstempel in ein für Menschen lesbares Format umzuwandeln, und umgekehrt.

Antwort: Als Sie vermuteten, dass dies ein Zeitzonenproblem war, haben Sie Recht. Aber der Code, den Sie verwendet, um zu versuchen, dies zu überprüfen, auch ein Problem hat:

end.setTimeZone(TimeZone.getTimeZone("America/New York")); 
pst.setTimestamp(1, new java.sql.Timestamp(end.getTimeInMillis())); 

Das setTimeZone Aussage keine Wirkung hat auf die gespeicherte Zeit in end, weil die Zeit bereits eingestellt wurde. Es hätte nur einen Effekt gehabt, wenn Sie die Zeit danach gespeichert hätten und nur dann, wenn Sie eine der Methoden von Calendar verwendet hätten, die die Zeit aus einem für Menschen lesbaren Format umwandelt (und nicht setTimeInMillis).

Wenn Sie getTimeInMillis verwenden, um den Zeitstempel an Ihre vorbereitete Anweisung zu übergeben, rufen Sie den Zeitstempel direkt ab. Da Sie es nicht in ein menschliches Format konvertieren, werden die Zeitzoneninformationen erneut ignoriert.

Wenn Sie versuchen,

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); 
end.setTime(sdf.parse("2012-10-01 00:00:00")); 
pst.setTimestamp(1, new java.sql.Timestamp(end.getTime())); 

und

pst.setTimestamp(1, new java.sql.Timestamp(octDate.get(Calendar.YEAR)-1900,octDate.get(Calendar.MONTH),octDate.get(Calendar.DATE),octDate.get(Calendar.HOUR),octDate.get(Calendar.MINUTE),octDate.get(Calendar.SECOND),0)); 
pst.setTimestamp(2, new java.sql.Timestamp(end.get(Calendar.YEAR)-1900,end.get(Calendar.MONTH),end.get(Calendar.DATE),end.get(Calendar.HOUR),end.get(Calendar.MINUTE),end.get(Calendar.SECOND),0)); 

Dinge erscheinen zu arbeiten, weil Sie jetzt Methoden verwenden, die zu/von einem Menschen lesbaren Format zu konvertieren und damit die angegebene Zeitzone Informationen werden verwendet. Dies deckt jedoch nur das eigentliche Problem ab. Das wirkliche Problem ist, dass die Zeit falsch konvertiert wurde, als Sie es von endString analysierten. Das heißt, die Zeitzone, in der endString ausgedrückt wurde, stimmt nicht mit der Zeitzone überein, die zum Zeitpunkt der Analyse des Datums in df1 festgelegt wurde.

kurze Antwort: vor dieser Zeile:

end.setTime(df1.parse(endString)); 

Sie müssen.

  • herauszufinden, welche Zeitzone die Zeit in endString in ausgedrückt wurde
  • Set df1 und nichtend in derselben Zeitzone. Da df1 das Datum ist, das das Datum vom menschlichen Format konvertiert, ist es die Zeitzoneninformation, die verwendet wird.

Prost!

+0

@Matt Johnson macht auch einen sehr guten Punkt.Stellen Sie an allen Stellen, an denen Sie eine Zeit aus Text konvertieren, sicher, dass Sie eine ortsbasierte Zeitzone und keinen Offset verwenden ("Amerika/New York" und nicht "EST"). –

2

haben, die den Wert Ihrer TimeZone.getDefault().getID() und von MySQL Standard-Zeitzone zurückgeführt wird?

BTW können Sie versuchen, ein Dienstprogramm wie diese mit Datumzeit über Zeitzonen zu konvertieren:

public Calendar convertDateToServerTimeZone(Date dateTime, String timeZone) { 
    Calendar userDefinedTime = Calendar.getInstance(); 
    userDefinedTime.setTime(dateTime); 
    if(!TimeZone.getDefault().getID().equalsIgnoreCase(timeZone)) { 
    System.out.println  ("original defined time: " + userDefinedTime.getTime().toString() + " on tz:" + timeZone); 
    Calendar quartzStartDate = new GregorianCalendar(TimeZone.getTimeZone(timeZone)); 
    quartzStartDate.set(Calendar.YEAR, userDefinedTime.get(Calendar.YEAR)); 
    quartzStartDate.set(Calendar.MONTH, userDefinedTime.get(Calendar.MONTH)); 
    quartzStartDate.set(Calendar.DAY_OF_MONTH, userDefinedTime.get(Calendar.DAY_OF_MONTH)); 
    quartzStartDate.set(Calendar.HOUR_OF_DAY, userDefinedTime.get(Calendar.HOUR_OF_DAY)); 
    quartzStartDate.set(Calendar.MINUTE, userDefinedTime.get(Calendar.MINUTE)); 
    quartzStartDate.set(Calendar.SECOND, userDefinedTime.get(Calendar.SECOND)); 
    quartzStartDate.set(Calendar.MILLISECOND, userDefinedTime.get(Calendar.MILLISECOND)); 
    System.out.println("adapted time for " + TimeZone.getDefault().getID() + ": " + quartzStartDate.getTime().toString()); 
    return quartzStartDate; 
    } else { 
    return userDefinedTime; 
    } 
} 

Ich habe mit dieser Funktion hier gearbeitet: Java Quartz-Scheduler across TimeZone

Hoffnung sein hilft.

+0

Ich glaube nicht, dass es hier ein Problem der Zeitzone gibt. weil, wenn ich eine veraltete Methode verwende, es gut funktioniert. Wenn ich Daten direkt in die Abfrage einfüge, ist das Ergebnis korrekt. –

+0

Ich glaube nicht, dass die Zeitzone von MySQL das Problem ist. Die Zeitzoneninformationen von MySQL werden nur verwendet, wenn sie den Job zum Konvertieren der Zeit von/in Text verarbeiten. Da Bhavik die Zeit als Parameter in einer vorbereiteten Anweisung verstreichen lässt, wurde sie bereits konvertiert. Wenn Bhavik die Zeit als Text direkt in die Abfrage eingegeben hätte, wäre die Zoneninformation von MySQL dazu benutzt worden, sie zu parsen. Siehe meine Antwort. –

1

Ohne die Werte zu sehen, die bei der zweiten Abfrage und nicht bei der ersten übereinstimmen, ist es schwierig, absolut sicher zu sein. Beachten Sie jedoch, dass eine Zeitzone nicht mit einem Offset identisch ist. Bitte lesen Sie den Abschnitt "TimeZone! = Offset" von the TimeZone tag wiki.

Zum Beispiel sagen Sie, dass Sie in die Zeitzone America/New_York konvertieren. Diese Zone ist manchmal in UTC-05: 00 (für Eastern Standard Time) und manchmal in UTC-04: 00 (für Eastern Daylight Time). Es ist durchaus möglich, dass einige Ihrer Daten aufgrund des -4-Offsets während der Sommerzeit abgerufen werden.

Wenn Sie den Offset -5 fest codieren, berücksichtigen Sie keine Zeitzonenregeln. Das würde die Diskrepanz erklären.

1

Zeitzone Informationen zu Terminen nicht angewendet wird/Zeiten, es sei denn Sie entweder useTimezone = true in Ihrer Verbindung URL. Sie können auch die Methode getTimestamp() verwenden, die Kalender als Argument verwenden.

+0

Auch dann hat es keinen Einfluss darauf, wie die Uhrzeit gespeichert wird. Es hat nur eine Auswirkung darauf, wie die Zeit angezeigt/analysiert wird. Siehe meine Antwort. –

1

Probieren Sie es aus.

Set Zeitstempel-Parameter, wie Sie jetzt

pst.setTimestamp(1, new java.sql.Timestamp(end.getTimeInMillis())); 

setzen.

Während des Datenbankaufrufs konvertiert der JDBC-Treiber die eingegebenen Datums-/Uhrzeitwerte möglicherweise bereits in GMT. Daher muss der Datumswert, mit dem die Datenbank zu tun hat, keine Zeitzonen des Eingabedatums in Betracht ziehen, die sich von einem Client zum anderen unterscheiden können.

Statt Einstellung FROM_TZ als '+05: 30'

convert_tz(updatedDate,'+05:30','-05:00') 

Set FROM_TZ als '00: 00'

convert_tz(updatedDate,'00:00','-05:00')