Java saat dilimini GMT / UTC olarak zorla


100

Makinede ayarlı saat dilimi ne olursa olsun, zamanla ilgili tüm işlemleri GMT / UTC'ye zorlamam gerekiyor. Kodda bunu yapmanın uygun bir yolu var mı?

Açıklamak gerekirse, tüm işlemler için DB sunucu saatini kullanıyorum, ancak yerel saat dilimine göre biçimlendirilmiş olarak çıkıyor.

Teşekkürler!


Aslında onun sorunu benim alt kümem, ama bir çözüm buldum.
SyBer

Yinelenen soruya bakın ve "Joda" ve "DateTimeZone" için arama yapın.
Basil Bourque

Yanıtlar:


127

OP, çalışan bir JVM'nin tek bir örneği için varsayılan saat dilimini değiştirmek için bu soruyu yanıtladı, user.timezonesistem özelliğini ayarlayın :

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

Veritabanından Tarih / Saat / Zaman Damgası nesnelerini alırken belirli saat dilimlerini ayarlamanız gerekiyorsa, nesneyi ResultSetalan getXXXyöntemlerin ikinci biçimini kullanın Calendar:

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

Veya bir PreparedStatement içinde tarih belirleme:

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

Bunlar, veritabanı sütunu saat dilimi bilgilerini tutmadığında veritabanında depolanan değerin tutarlı olmasını sağlayacaktır.

java.util.DateVe java.sql.Datesınıflar UTC olarak gerçek zaman (milisaniye) depolar. Bunları çıktıda başka bir saat dilimine biçimlendirmek için kullanın SimpleDateFormat. Ayrıca bir Takvim nesnesi kullanarak bir saat dilimini değerle ilişkilendirebilirsiniz:

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

Faydalı Referans

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


Tüm JVM için saat dilimini ayarlama konusunda dikkat edilmesi gereken bir nokta, günlük kaydı gibi şeyler de dahil olmak üzere her şeyi etkilemesidir. İstenilen etki buysa akılda tutulması gereken bir şey.
Hermann Hans

Evet, o kadar iyi. Bir noktaya değinmek gerekirse, user.timezone'u -D parametresi yerine doğrudan kodda ayarladım.
SyBer

6
@SyBer: Bu çalışır, ancak herhangi bir yöntem TimeZone.getDefault () yöntemini çağırmadan önce bunu ayarladığınızdan emin olmalısınız. Aksi takdirde, ilk çalıştırmadan sonra varsayılan önbelleğe alındığından biraz kafa karışıklığı yaşarsınız. Bu aynı zamanda, bunu bir API / kitaplıkta (düz görünümden gizlenmiş olarak) yaparsanız sorun olabileceği anlamına gelir - ne yaptığınızı büyük ölçüde belgelediğinizden emin olun.
Kevin Brock

23

Ayrıca JVM saat dilimini bu şekilde ayarlayabilirseniz

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

veya -Duser.timezone=GMTJVM parametrelerinde.


System.setProperty("user.timezone" ...)çalışmıyor.
wilmol


11

TimeZone.setDefault () kullanarak saat dilimini değiştirebilirsiniz :

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

Alınma ama geçici olarak küresel statik bir durumu değiştirmek kulağa çok kötü bir fikir gibi geliyor ...
G.Demecki

Yapabilirsin, ama yapmamalısın. Bu son derece kötü bir tavsiye. Tüm JVM'nin saat dilimi değişmiştir.
scot

1
Bazen tam olarak ulaşmak istediğiniz şey budur. Örneğin. Saat dilimi sorunlarını önlemek için her zaman UTC ile çalışan Java tabanlı mikro hizmetler gördüm. Bu sistemlerde veritabanı arka ucu da UTC ile çalışır, bu nedenle JVM'yi UTC'ye "zorlamak" doğaldır. Önemli olan: ne yaptığınızı ve sonuçlarının ne olduğunu bilmelisiniz ...
snorbi

kesinlikle hayır. Sisteminizin tamamını UTC olarak istiyorsanız (çok iyi bir fikir), sistem saat dilimini UTC'ye ayarlayın ve Java saat dilimini olduğu gibi bırakın.
scot

3
Farklı gereksinimleri olan birden fazla JVM'niz olması dışında. Sonsuza kadar tartışabiliriz, ancak her durum benzersizdir: bazen tüm sistemin zaman dilimini ayarlamanız gerekir, bazen yalnızca bir JVM ayarlarsınız. Bugünün sistemleri o kadar esnek ki ikisini de yapabiliyoruz 😉
snorbi

8

benim için hızlı SimpleDateFormat,

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

ardından tarihi farklı saat dilimiyle biçimlendirin.


7

tl; dr

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

Varsayılan saat dilimi için ana bilgisayar işletim sistemine veya JVM'ye bağlı olmaktan kaçının

İstenen / beklenen saat dilimini açıkça belirtmek için tüm kodunuzu yazmanızı tavsiye ederim. JVM'nin mevcut varsayılan saat dilimine bağlı olmanız gerekmez. Ve JVM'nin geçerli varsayılan saat diliminin , herhangi bir uygulama çağrısının herhangi bir iş parçacığındaki herhangi bir kodla, çalışma süresi sırasında herhangi bir anda değişebileceğini unutmayın TimeZone.setDefault. Böyle bir çağrı, o JVM içindeki tüm uygulamaları hemen etkiler.

java.time

Diğer Cevaplardan bazıları doğruydu, ancak artık modası geçmiş durumda. Java'nın en eski sürümleriyle birlikte verilen korkunç tarih-saat sınıfları, tarih-saat işlemenin karmaşıklıklarını ve inceliklerini anlamayan insanlar tarafından yazılmış, kusurluydu.

Eski tarih-saat sınıflarının yerini , JSR 310'da tanımlanan java.time sınıfları almıştır .

Bir saat dilimini temsil etmek için kullanın ZoneId. UTC'den uzaklığı temsil etmek için kullanın ZoneOffset. Bir sapma, yalnızca ana meridyenin önünde veya arkasında birkaç saat-dakika-saniye sayısıdır. Bir saat dilimi çok daha fazlasıdır. Bir saat dilimi, belirli bir bölgedeki insanlar tarafından kullanılan farkın geçmiş, şimdiki ve gelecekteki değişikliklerinin geçmişidir.

Zamanla ilgili herhangi bir işlemi GMT / UTC'ye zorlamam gerekiyor

Sıfır saat-dakika-saniye farkı için sabiti kullanın ZoneOffset.UTC.

Instant

Geçerli anı UTC'de yakalamak için bir Instant. Bu sınıf, UTC'de bir anı temsil eder, tanımı gereği her zaman UTC'dir.

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

ZonedDateTime

Aynı anı, belirli bir bölgedeki insanlar tarafından kullanılan duvar saati zamanına göre görmek için, bir saat dilimine ayarlayın. Aynı an, zaman çizelgesinde aynı nokta, farklı duvar saati zamanı.

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

Veri tabanı

Bir veritabanından bahsediyorsunuz.

Veritabanından bir anı geri almak için, sütununuz SQL standardına benzer bir veri türünde olmalıdır TIMESTAMP WITH TIME ZONE. Bir dizeden ziyade bir nesneyi alın. JDBC 4.2 ve sonrasında, java.time nesnelerini veritabanı ile değiştirebiliriz. OffsetDateTimeİse, JDBC gereklidir Instantve ZonedDateTimeisteğe bağlıdır.

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

Çoğu veritabanında ve sürücüde, UTC'de görüldüğü gibi anı alacağınızı tahmin ediyorum. Ancak değilse, iki yoldan birini kullanarak ayarlama yapabilirsiniz:

  • A'yı çıkarın Instant: odt.toInstant()
  • Verilen ofsetten sıfır ofsetine ayarlayın: OffsetDateTime odtUtc = odt.withOffsetSameInstant (ZoneOffset.UTC); `.

Java'da (hem eski hem de modern) ve standart SQL'de tarih-saat türleri tablosu


Hakkında java.time

Java.time çerçevesi daha sonra Java 8 ve yerleşiktir. Bu sınıflar zahmetli eski yerini mirası gibi tarih-saat sınıfları java.util.Date, Calendar& SimpleDateFormat.

Daha fazla bilgi edinmek için Oracle Eğitimi'ne bakın . Ve birçok örnek ve açıklama için Stack Overflow'da arama yapın. Spesifikasyon JSR 310'dur .

Şu anda bakım modunda olan Joda-Time projesi, java.time sınıflarına geçişi önerir .

Sen değiştirebilir java.time sizin veritabanı ile doğrudan nesneleri. JDBC 4.2 veya üstü ile uyumlu bir JDBC sürücüsü kullanın . Dizelere gerek yok, derslere gerek yok .java.sql.*

Java.time derslerini nereden edinebilirim?


6

Zamanı DB'den ham bir biçimde (uzun zaman damgası veya java'nın Tarihi) alırdım ve sonra biçimlendirmek için SimpleDateFormat'ı veya onu işlemek için Takvim'i kullanırdım. Her iki durumda da nesnelerin saat dilimini kullanmadan önce ayarlamalısınız.

Bkz SimpleDateFormat.setTimeZone(..)ve Calendar.setTimeZone(..)detaylar için


1

bir istemci / sunucu çifti oluşturun, böylece yürütmeden sonra istemci sunucusu doğru saat ve tarihi gönderir. Ardından, istemci sunucuya pm GMT'yi sorar ve sunucu yanıtı doğru olarak geri gönderir.


1

Sistem özelliğini kullan:

-Duser.timezone=UTC

5
Neden bunu kullanmalı? Lütfen cevabınıza diğerlerinin ondan öğrenebileceği bir açıklama ekleyin
Nico Haase

1

Saat diliminizi sıfırlamak için bu satırı MySQL'de çalıştırın:

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

0

Vay. Bunun eski bir iş parçacığı olduğunu biliyorum ama tek söyleyebileceğim herhangi bir kullanıcı düzeyi kodunda TimeZone.setDefault () 'u çağırmamak. Bu her zaman tüm JVM için Zaman Dilimini belirler ve neredeyse her zaman çok kötü bir fikirdir. Java 8'de joda.time kitaplığına çok benzeyen joda.time kitaplığını veya yeni DateTime sınıfını kullanmayı öğrenin.


0

Aşağıdaki kodun size yardımcı olacağını umuyoruz.

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

-6

GMT saatini yalnızca intiger ile almak istiyorsanız: 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)

5
bana JavaScript (! = Java) gibi görünüyor.
Phil
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.