sql >> Database >  >> RDS >> Mysql

TimeZone discrepantie in mysql en java

Achtergrond:Een verrassend veel voorkomende - en grote - misvatting die zelfs door briljante programmeurs wordt gedeeld, is het idee dat opgeslagen tijdstempels (in uw database, Datum, Kalender, Tijdstempel, et al) op de een of andere manier tijdzone-informatie bevatten. Dat doen ze niet. Een tijdstempel (in ieder geval tot Java 8) wordt opgeslagen als het aantal milliseconden sinds middernacht op 1 januari 1970 UTC. Einde van de zin. Het enige dat het instellen van de tijdzone doet, is voldoende informatie aan de computer verstrekken om die tijdstempel om te zetten in een voor mensen leesbaar formaat, en vice versa.

Antwoord:Toen je vermoedde dat dit een tijdzoneprobleem was, je had gelijk . Maar de code die je hebt gebruikt om dit te verifiëren, heeft ook een probleem:

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

Dat setTimeZone verklaring heeft geen effect op de tijd opgeslagen in end , omdat de tijd al is ingesteld. Het zou alleen effect hebben gehad als je de tijd achteraf had opgeslagen, en dan alleen als je een van de methoden van Calendar had gebruikt die de tijd van een voor mensen leesbaar formaat converteerde (en niet setTimeInMillis ).

Wanneer u getTimeInMillis gebruikt om de tijdstempel door te geven aan uw voorbereide verklaring, haalt u de tijdstempel rechtstreeks op. Aangezien je het niet naar een menselijk formaat converteert, wordt de tijdzone-informatie opnieuw genegeerd.

Wanneer je probeert

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()));

en

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));

dingen verschijnen om te werken omdat u nu methoden gebruikt die converteren naar/van een voor mensen leesbaar formaat, en daarom wordt de gespecificeerde tijdzone-informatie gebruikt. Dit verbergt echter alleen het echte probleem. Het echte probleem is dat de tijd onjuist werd geconverteerd toen je het ontleden van endString . Dat wil zeggen, de tijdzone die endString werd uitgedrukt in komt niet overeen met de tijdzone die is ingesteld in df1 op het moment dat de datum werd geparseerd.

KORT ANTWOORD:voor deze regel:

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

U moet:

  • Bepaal in welke tijdzone de tijd is in endString werd uitgedrukt in.
  • Stel df1 in en niet end naar diezelfde tijdzone. Sinds df1 is het ding dat de datum converteert van menselijk formaat, het is die tijdzone-informatie die wordt gebruikt.

Proost!



  1. Hoe de MySQL 8.0-gegevensmap te wijzigen. Kan ik OneDrive-mappen gebruiken?

  2. Max echte ruimte in een varbinary (max) in SQL Server

  3. Onderscheiden versus groeperen op basis van

  4. Snelste manier om dezelfde query meerdere keren uit te voeren in SQL Server