Java 시간대를 GMT / UTC로 강제 적용


97

컴퓨터에 설정된 시간대에 관계없이 시간 관련 작업을 GMT / UTC로 강제 적용해야합니다. 코드에서 편리한 방법이 있습니까?

명확히하기 위해 모든 작업에 DB 서버 시간을 사용하고 있지만 현지 시간대에 따라 형식이 나옵니다.

감사!


사실 그의 문제는 나의 부분 집합이지만 해결책을 찾았습니다.
SyBer 2010

중복 질문을보고 "Joda"및 "DateTimeZone"을 검색합니다.
Basil Bourque 2014 년

답변:


126

OP는이 질문에 응답하여 실행중인 JVM의 단일 인스턴스에 대한 기본 시간대를 변경하고 user.timezone시스템 속성을 설정합니다 .

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

데이터베이스에서 Date / Time / Timestamp 객체를 검색 할 때 특정 시간대를 설정해야하는 경우 객체를받는 ResultSet두 번째 형식의 getXXX메서드를 사용 Calendar합니다.

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

또는 PreparedStatement에서 날짜 설정 :

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

이렇게하면 데이터베이스 열이 시간대 정보를 유지하지 않을 때 데이터베이스에 저장된 값이 일관되게 유지됩니다.

java.util.Datejava.sql.Date클래스는 UTC의 실제 시간 (밀리 초)을 저장합니다. 출력시 다른 시간대로 형식을 지정하려면 SimpleDateFormat. Calendar 개체를 사용하여 시간대를 값과 연결할 수도 있습니다.

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

유용한 참조

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


전체 JVM의 시간대 설정에 대해주의해야 할 사항은 로깅과 같은 것을 포함하여 모든 것에 영향을 미친다는 것입니다. 그것이 원하는 효과 인 경우 명심해야 할 사항입니다.
Hermann Hans

네, 괜찮습니다. 한 가지 언급 할 사항은 실제로 user.timezone을 -D 매개 변수를 통해 설정하는 것이 아니라 코드에서 직접 설정한다는 것입니다.
SyBer 2010

6
@SyBer : 작동하지만 메서드가 TimeZone.getDefault () 메서드를 호출하기 전에이를 설정했는지 확인해야합니다. 그렇지 않으면 첫 번째 실행 후 기본값이 캐시되기 때문에 약간의 혼란이있을 것입니다. 이것은 또한 API / 라이브러리 (일반보기에서 숨겨 짐) 내에서이 작업을 수행하는 경우 문제가 될 수 있음을 의미합니다. 수행중인 작업을 많이 문서화해야합니다.
Kevin Brock

23

또한 이런 식으로 JVM 시간대를 설정할 수 있다면

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

또는 -Duser.timezone=GMTJVM 인수에서.


System.setProperty("user.timezone" ...)작동하지 않습니다.
wilmol


10

TimeZone.setDefault () 사용하여 시간대를 변경할 수 있습니다 .

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

화내는 없지만, 아주 나쁜 생각처럼 일시적으로 전역 정적 상태 소리를 수정 ...
G. Demecki

할 수 있지만 그렇게해서는 안됩니다. 이것은 매우 나쁜 조언입니다. 전체 JVM의 시간대가 변경되었습니다.
scot

1
때로는 정확히 달성하고자하는 것입니다. 예 : 시간대 문제를 피하기 위해 항상 UTC로 실행되는 Java 기반 마이크로 서비스를 보았습니다. 이러한 시스템에서 데이터베이스 백엔드는 UTC로도 실행되므로 JVM도 UTC로 "강제"하는 것이 당연합니다. 중요한 점 : 당신은 당신이 무엇을하고 있는지 알아야하고 무슨 일이 ... 결과입니다
snorbi

절대적으로하지. 전체 시스템을 UTC (아주 좋은 생각)로하려면 시스템 시간대를 UTC로 설정하고 Java 시간대는 그대로 두십시오.
scot

3
요구 사항이 다른 여러 JVM이있는 경우는 예외입니다. 우리는 영원히 논쟁 할 수 있지만 모든 경우는 고유합니다. 때로는 전체 시스템의 시간대를 설정해야하고 때로는 하나의 JVM 만 설정해야합니다. 의 오늘날의 시스템은 우리가 모두 😉 할 수 있도록 유연 행복하자
snorbi

8

저에게는 빠른 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"));
  }

그런 다음 다른 시간대로 날짜 형식을 지정하십시오.


6

DB에서 원시 형식 (긴 타임 스탬프 또는 자바의 날짜)으로 시간을 검색 한 다음 SimpleDateFormat을 사용하여 형식을 지정하거나 Calendar를 사용하여 조작합니다. 두 경우 모두 사용하기 전에 객체의 시간대를 설정해야합니다.

자세한 내용은 SimpleDateFormat.setTimeZone(..)Calendar.setTimeZone(..)참조


6

tl; dr

String sql = "SELECT CURRENT_TIMESTAMP ;

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

기본 시간대에 대해 호스트 OS 또는 JVM에 의존하지 마십시오.

원하는 / 예상 시간대를 명시 적으로 나타내는 모든 코드를 작성하는 것이 좋습니다. JVM의 현재 기본 시간대에 의존 할 필요가 없습니다. JVM의 현재 기본 시간대는 .을 호출하는 모든 스레드의 모든 코드로 런타임 중에 언제든지 변경 될 수 있습니다 TimeZone.setDefault. 이러한 호출은 해당 JVM 내의 모든 앱에 즉시 영향을 미칩니다.

java.time

다른 답변 중 일부는 정확했지만 이제는 구식입니다. Java의 초기 버전과 함께 번들로 제공되는 끔찍한 날짜-시간 클래스는 날짜-시간 처리의 복잡성과 미묘함을 이해하지 못한 사람들이 작성한 결함이있었습니다.

레거시 날짜-시간 클래스는 JSR 310에 정의 된 java.time 클래스 로 대체되었습니다 .

시간대를 나타내려면을 사용하십시오 ZoneId. UTC로부터의 오프셋을 나타내려면 ZoneOffset. 오프셋은 단지 본초 자오선보다 몇 시간-분-초 앞이나 뒤에 있습니다. 시간대는 훨씬 더 많습니다. 시간대는 특정 지역의 사람들이 사용하는 오프셋에 대한 과거, 현재 및 미래 변경 내역입니다.

GMT / UTC에 대한 모든 시간 관련 작업을 강제해야합니다.

0 시간-분-초 오프셋의 경우 상수를 사용하십시오 ZoneOffset.UTC.

Instant

UTC로 현재 순간을 캡처하려면 Instant. 이 클래스는 정의에 따라 항상 UTC로 순간을 나타냅니다.

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

ZonedDateTime

특정 지역의 사람들이 사용하는 벽시계 시간을 통해 같은 순간을 보려면 시간대를 조정하십시오. 같은 순간, 타임 라인의 같은 지점, 다른 벽시계 시간.

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

데이터 베이스

데이터베이스를 언급합니다.

데이터베이스에서 순간을 검색하려면 열이 SQL 표준과 유사한 데이터 유형이어야합니다 TIMESTAMP WITH TIME ZONE. 문자열이 아닌 객체를 검색합니다. JDBC 4.2 이상에서는 데이터베이스와 java.time 객체를 교환 할 수 있습니다 . 는 OffsetDateTime동안, JDBC에 필요한 InstantZonedDateTime선택 사항입니다.

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

대부분의 데이터베이스와 드라이버에서 UTC에서 볼 수있는 순간을 얻게 될 것입니다. 그러나 그렇지 않은 경우 다음 두 가지 방법 중 하나로 조정할 수 있습니다.

  • 추출 Instant: odt.toInstant()
  • 주어진 오프셋에서 0의 오프셋으로 조정합니다. OffsetDateTime odtUtc = odt.withOffsetSameInstant (ZoneOffset.UTC);`.

Java (레거시 및 최신 모두) 및 표준 SQL의 날짜-시간 유형 표


java.time 정보

java.time의 프레임 워크는 나중에 자바 8에 내장되어 있습니다. 이 클래스는 까다로운 기존에 대신 기존 과 같은 날짜 - 시간의 수업을 java.util.Date, Calendar,SimpleDateFormat .

자세한 내용은 Oracle Tutorial을 참조하십시오 . 그리고 많은 예제와 설명을 위해 Stack Overflow를 검색하십시오. 사양은 JSR 310 입니다.

Joda 타임 프로젝트는 지금에 유지 관리 모드 의로 마이그레이션을 조언 java.time의 클래스.

java.time 객체를 데이터베이스와 직접 교환 할 수 있습니다 . JDBC 4.2 이상을 준수 하는 JDBC 드라이버를 사용하십시오 . 문자열이나 클래스 가 필요하지 않습니다 .java.sql.*

java.time 클래스는 어디서 구할 수 있습니까?


1

실행 후 클라이언트 서버가 정확한 시간과 날짜를 보내도록 클라이언트 / 서버 쌍을 만듭니다. 그런 다음 클라이언트는 서버 pm GMT에 요청하고 서버는 바로 응답을 보냅니다.


1

시스템 속성 사용 :

-Duser.timezone=UTC

5
왜 그것을 사용해야합니까? 다른 사람들이 배울 수 있도록 당신의 대답에 약간의 설명을 추가하세요
니코 하세

1

MySQL에서 다음 줄을 실행하여 시간대를 재설정하십시오.

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

0

와. 나는 이것이 고대 스레드라는 것을 알고 있지만 내가 말할 수있는 것은 사용자 수준 코드에서 TimeZone.setDefault ()를 호출하지 않는 것입니다. 이것은 항상 전체 JVM의 시간대를 설정하며 거의 항상 매우 나쁜 생각입니다. joda.time 라이브러리 또는 joda.time 라이브러리와 매우 유사한 Java 8의 새로운 DateTime 클래스를 사용하는 방법을 배웁니다.


-6

intiger로만 GMT 시간을 얻으려면 : 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
그것은 나에게 JavaScript (! = Java)처럼 보입니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.