Forțați fusul orar Java ca GMT/UTC (Programare, Java, Fus Orar, Utc, Gmt)

SyBer a intrebat.
a intrebat.

Am nevoie să forțez orice operațiune legată de timp la GMT/UTC, indiferent de fusul orar setat pe mașină. Există vreo modalitate convenabilă de a face acest lucru în cod?

Pentru a clarifica, utilizez ora serverului DB pentru toate operațiunile, dar aceasta iese formatată în funcție de fusul orar local.

Vă mulțumim!

Comentarii

  • De fapt, problema lui este un subset al meu, dar am găsit o soluție. –  > Por SyBer.
  • Uitați-vă la întrebarea duplicată și căutați „Joda” și „DateTimeZone”. –  > Por Basil Bourque.
13 răspunsuri
Kevin Brock

OP a răspuns la această întrebare pentru a schimba fusul orar implicit pentru o singură instanță a unui JVM în execuție, setați user.timezone proprietatea de sistem:

java -Duser.timezone=GMT ... <main-class>

Dacă aveți nevoie să setați zone orare specifice atunci când preluați obiecte Date/Time/Timestamp dintr-o bază de date ResultSetutilizați a doua formă a proprietății getXXX care primește un parametru Calendar obiect:

Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
ResultSet rs = ...;
while (rs.next()) {
    Date dateValue = rs.getDate("DateColumn", tzCal);
    // Other fields and calculations
}

Sau, setarea datei într-un PreparedStatement:

Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
PreparedStatement ps = conn.createPreparedStatement("update ...");
ps.setDate("DateColumn", dateValue, tzCal);
// Other assignments
ps.executeUpdate();

Acestea vor asigura că valoarea stocată în baza de date este consecventă atunci când coloana din baza de date nu păstrează informații despre fusul orar.

Adresa java.util.Date și java.sql.Date stochează ora reală (milisecunde) în UTC. Pentru a formata aceste date la ieșire în alt fus orar, utilizați SimpleDateFormat. De asemenea, puteți asocia un fus orar cu valoarea folosind un obiect Calendar:

TimeZone tz = TimeZone.getTimeZone("<local-time-zone>");
//...
Date dateValue = rs.getDate("DateColumn");
Calendar calValue = Calendar.getInstance(tz);
calValue.setTime(dateValue);

Referință utilă

https://docs.oracle.com/javase/9/troubleshoot/time-zone-settings-jre.htm#JSTGD377

https://confluence.atlassian.com/kb/setting-the-timezone-for-the-java-environment-841187402.html

Comentarii

  • Un lucru de reținut cu privire la setarea fusului orar pentru întreaga JVM este faptul că afectează totul, inclusiv lucruri precum logarea. Doar un lucru de care trebuie să țineți cont dacă acesta este efectul dorit. –  > Por Hermann Hans.
  • Da, este în regulă. Un singur lucru de menționat: de fapt, am setat zona de timp user.timezone direct în cod, mai degrabă decât prin intermediul parametrului -D. –  > Por SyBer.
  • @SyBer: Funcționează, dar trebuie să vă asigurați că ați setat acest lucru înainte ca orice metodă să apeleze metoda TimeZone.getDefault(). În caz contrar, veți avea unele confuzii, deoarece valoarea implicită este memorată în memoria cache după prima execuție. Acest lucru înseamnă, de asemenea, că ar putea fi o problemă dacă faceți acest lucru în interiorul unei API/biblioteci (ascunsă la vedere) – asigurați-vă că documentați temeinic ceea ce faceți. –  > Por Kevin Brock.
Dezvoltator MG

De asemenea, dacă puteți seta fusul orar al JVM în acest fel

System.setProperty("user.timezone", "EST");

sau -Duser.timezone=GMT în argetele JVM.

Comentarii

  • System.setProperty("user.timezone" ...) nu funcționează. –  > Por wilmol.
  • System.setProperty(„user.timezone”, „EST”); acest lucru funcționează bine. Mulțumesc.  > Por pravin kottawar.
Todd

A trebuit să setez fusul orar JVM pentru Windows 2003 Server deoarece întotdeauna a returnat GMT pentru new Date();

-Duser.timezone=America/Los_Angeles

Sau fusul orar corespunzător. Găsirea unei liste de fusuri orare s-a dovedit a fi o mică provocare, de asemenea…

Aici sunt două liste;

http://wrapper.tanukisoftware.com/doc/english/prop-timezone.html

http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzatz%2F51%2Fadmin%2Freftz.htm

snorbi

Ați putea schimba fusul orar folosind TimeZone.setDefault():

TimeZone.setDefault(TimeZone.getTimeZone("GMT"))

Comentarii

  • Fără supărare, dar modificarea temporară a unei stări statice globale pare o idee foarte proastă… –  > Por G. Demecki.
  • Ați putea, dar nu ar trebui să o faceți. Acesta este un sfat extraordinar de prost. Întregul JVM are fusul orar modificat. –  > Por scot.
  • Uneori este exact ceea ce doriți să obțineți. De ex. am văzut microservicii bazate pe Java care rulează întotdeauna cu UTC pentru a evita problemele de fus orar. În aceste sisteme, backend-ul bazei de date rulează și el cu UTC, așa că este firesc să „forțezi” și JVM-ul la UTC. Ceea ce este important: trebuie să știți ce faceți și care sunt consecințele… –  > Por snorbi.
  • absolut deloc. Dacă doriți ca întregul sistem să fie în UTC (o idee foarte bună), setați fusul orar al sistemului la UTC și lăsați fusul orar Java în pace. –  > Por scot.
  • Cu excepția cazului în care aveți mai multe JVM-uri cu cerințe diferite. Ne putem certa la nesfârșit, dar fiecare caz este unic: uneori trebuie să setați fusul orar al întregului sistem, alteori îl setați doar pe cel al unui JVM. Să fim fericiți că sistemele de astăzi sunt atât de flexibile încât putem face ambele -.  > Por snorbi.
lwpro2

pentru mine, doar SimpleDateFormat rapid,

  private static final SimpleDateFormat GMT = new SimpleDateFormat("yyyy-MM-dd");
  private static final SimpleDateFormat SYD = new SimpleDateFormat("yyyy-MM-dd");
  static {
      GMT.setTimeZone(TimeZone.getTimeZone("GMT"));
    SYD.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
  }

apoi formatați data cu un fus orar diferit.

Basil Bourque

tl;dr

String sql = "SELECT CURRENT_TIMESTAMP ;
…
OffsetDateTime odt = myResultSet.getObject( 1 , OffsetDateTime.class ) ;

Evitați să depindeți de sistemul de operare gazdă sau de JVM pentru fusul orar implicit

Vă recomand să vă scrieți tot codul pentru a indica explicit fusul orar dorit/prevăzut. Nu trebuie să depindeți de fusul orar implicit actual al JVM-ului. Și fiți conștienți de faptul că fusul orar implicit actual al JVM se poate schimba în orice moment în timpul execuției, cu orice cod din orice fir de execuție din orice aplicație care apelează TimeZone.setDefault. Un astfel de apel afectează imediat toate aplicațiile din cadrul JVM-ului respectiv.

java.time

Unele dintre celelalte răspunsuri au fost corecte, dar acum sunt depășite. Clasele teribile de date-timp incluse în primele versiuni de Java erau defectuoase, scrise de persoane care nu înțelegeau complexitatea și subtilitățile manipulării datelor-timp.

Clasele de date-timp vechi au fost înlocuite de clasele java.time definite în JSR 310.

Pentru a reprezenta un fus orar, utilizați ZoneId. Pentru a reprezenta un decalaj față de ora UTC, utilizați ZoneOffset. Un decalaj este pur și simplu un număr de ore-minute-secunde înainte sau după meridianul principal. Un fus orar reprezintă mult mai mult. Un fus orar este o istorie a modificărilor trecute, prezente și viitoare ale decalajului folosit de locuitorii unei anumite regiuni.

Trebuie să forțez orice operațiune legată de timp la GMT/UTC

Pentru un decalaj de zero ore-minute-secunde, utilizați constanta ZoneOffset.UTC.

Instant

Pentru a captura momentul curent în UTC, utilizați o constantă Instant. Această clasă reprezintă un moment în UTC, întotdeauna în UTC prin definiție.

Instant instant = Instant.now() ;  // Capture current moment in UTC.

ZonedDateTime

Pentru a vedea același moment prin intermediul ceasului de perete folosit de locuitorii unei anumite regiuni, trebuie să vă adaptați la un fus orar. Același moment, același punct de pe linia timpului, ora ceasului de perete diferită.

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

Baza de date

Ați menționat o bază de date.

Pentru a prelua un moment din baza de date, coloana dvs. ar trebui să fie de un tip de date asemănător cu standardul SQL TIMESTAMP WITH TIME ZONE. Recuperați mai degrabă un obiect decât un șir de caractere. În JDBC 4.2 și versiunile ulterioare, putem schimba java.time cu baza de date. Adresa OffsetDateTime este necesară pentru JDBC, în timp ce Instant & ZonedDateTime sunt opționale.

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

În majoritatea bazelor de date și a driverelor, aș presupune că veți obține un moment așa cum se vede în UTC. Dar dacă nu este așa, puteți ajusta în oricare dintre cele două moduri:

  • Extrageți un Instant: odt.toInstant()
  • Ajustați de la decalajul dat la un decalaj de zero: OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;`.


Despre java.time

java.time este încorporat în Java 8 și în versiunile ulterioare. Aceste clase înlocuiesc vechea și problematică moștenire clase de date-timp, cum ar fi java.util.Date, Calendar, , & SimpleDateFormat.

Pentru a afla mai multe, consultați pagina Tutorial Oracle. Și căutați în Stack Overflow pentru multe exemple și explicații. Specificația este JSR 310.

Joda-Time în prezent în modul de întreținere, recomandă migrarea la java.time clase.

Puteți schimba java.time direct cu baza de date. Folosiți un driver JDBC compatibil cu JDBC 4.2 sau o versiune ulterioară. Nu este nevoie de șiruri de caractere, nu este nevoie de java.sql.* clase.

De unde se pot obține clasele java.time?

  • Java SE 8, Java SE 9, Java SE 10, Java SE 11, și ulterior – Parte a API Java standard cu o implementare la pachet.
    • Java 9 adaugă câteva caracteristici și corecturi minore.
  • Java SE 6 și Java SE 7
  • Android
    • Versiunile ulterioare ale Android includ în pachet implementări ale funcției java.time clase.
    • În cazul Android anterior (<26), se utilizează ThreeTenABP adaptează ThreeTen-Backport (menționat mai sus). A se vedea Cum se utilizează ThreeTenABP….

Eyal Schneider

Aș prelua ora din BD într-o formă brută (timestamp lung sau java’s Date), apoi aș folosi SimpleDateFormat pentru a o formata sau Calendar pentru a o manipula. În ambele cazuri, ar trebui să setați fusul orar al obiectelor înainte de a-l utiliza.

A se vedea SimpleDateFormat.setTimeZone(..) și Calendar.setTimeZone(..) pentru detalii

Dawid Stępień

Utilizați proprietatea de sistem:

-Duser.timezone=UTC

Comentarii

  • De ce ar trebui să se folosească asta? Vă rugăm să adăugați o explicație la răspunsul dumneavoastră, astfel încât și alții să poată învăța din el –  > Por Nico Haase.
bertan

creați o pereche de client / server, astfel încât, după execuție, clientul server să trimită ora și data corecte. Apoi, clientul întreabă serverul pm GMT și serverul trimite înapoi răspunsul corect.

Saeed

Executați această linie în MySQL pentru a reseta fusul orar:

SET @@global.time_zone = '+00:00';

Vijay Kesanupalli

Sper că codul de mai jos vă va ajuta.

    DateFormat formatDate = new SimpleDateFormat(ISO_DATE_TIME_PATTERN);
    formatDate.setTimeZone(TimeZone.getTimeZone("UTC")); 
    formatDate.parse(dateString);

scot

Wow. Știu că acesta este un fir vechi, dar tot ce pot spune este să nu apelați TimeZone.setDefault() în niciun cod la nivel de utilizator. Acest lucru setează întotdeauna Timezone pentru întregul JVM și este aproape întotdeauna o idee foarte proastă. Învățați să utilizați biblioteca joda.time sau noua clasă DateTime din Java 8, care este foarte asemănătoare cu biblioteca joda.time.

Comentarii

  • Eu o folosesc pentru teste. Nu știu niciodată ce fus orar au colegii mei de echipă pe computerele lor sau ce va fi setat în CI. –  > Por Auras.
Incmos

Dacă doriți să obțineți ora GMT doar cu intiger: var currentTime = new Date(); var currentYear =’2010′ var currentMonth = 10; var currentDay =’30’ var currentHours =’20’ var currentMinutes =’20’ var currentSeconds =’00’ var currentMilliseconds =’00’

currentTime.setFullYear(currentYear);
currentTime.setMonth((currentMonth-1)); //0is January
currentTime.setDate(currentDay);  
currentTime.setHours(currentHours);
currentTime.setMinutes(currentMinutes);
currentTime.setSeconds(currentSeconds);
currentTime.setMilliseconds(currentMilliseconds);

var currentTimezone = currentTime.getTimezoneOffset();
currentTimezone = (currentTimezone/60) * -1;
var gmt ="";
if (currentTimezone !== 0) {
  gmt += currentTimezone > 0 ? ' +' : ' ';
  gmt += currentTimezone;
}
alert(gmt)

Comentarii

  • care mie mi se pare a fi JavaScript (!= Java). –  > Por Phil.