자바 Default Time Zone은 어떻게 설정되는가

박진선·2024년 9월 11일
0
post-custom-banner

자바의 LocalDate, LocalDateTime 클래스의 now() 메소드를 호출하면 현재날짜, 시각을 반환하는데 결국 TimeZone 클래스의 getDefaultRef() 메소드를 호출하여 defaultTimeZone 필드에 저장된 값을 가져와 해당 필드에 저장된 Timezone을 기준으로 현재시각 날짜를 반환한다. 그렇다면 defaultTimeZone 필드에는 과연 어떻게 값이 대입되는지 알아보자

아래 setDefaultZone 메소드를 통해 defaultTimeZone 필드에 값을 대입하는데 기본 Timezone을 설정하는 역할을 한다. 코드를 보면
우선 GetPropertyAction.privilegedGetProperties() 메소드를 호출하는데 해당 메소드에서 System.getProperties() 호출하여 Properties 클래스를 반환받고 그 다음 Properties 의 ConcurrentHashMap 타입 필드에서 key로 user.timezone 존재하면 반환 받는데 JVM 옵션을 설정하지 않았을 경우 존재하지 않는다.
그러하여 getSystemTimeZoneID(javaHome) 메소드를 호출하는데 해당 메소드는 네이티브 메소드로 자바에서 구현되지 않고, C나 C++ 같은 언어로 작성된 외부 라이브러리를 통해 호출하여 운영체제에 설정된 Timezone 을 가져와 반환한다.
반환받은 String 타입의 zoneID 변수로 getTimeZone 메소드를 호출하여 ZoneInfo 클래스를 가져와 defaultTimeZone 변수에 대입하고 프로퍼티에 user.timezone 을 설정한 뒤 반환하면서 메소드가 끝이난다.
이제 지정한 기본 Timezone을 기준으로 now() 메소드가 호출되면 현재 시간 또는 날짜를 반환하는 것이다.

운영체제에 설정된 타임존과 별도의 타임존을 사용하고 싶다면 JVM 실행옵션으로 -Duser.timezone=Asia/Seoul 이와 같이 설정하면 된다.

JPA Auditing 기능으로 보통 생성, 수정일자 필드를 갖는 별도의 클래스를 만들고 각 엔티티에서 상속하면 저장, 수정이 일어날 때 마다 자동으로 현재시간이 엔티티에 매칭되는 테이블의 로우데이터로 저장되는데 결국 코드 내부에서도 현재시간을 LocalDateTime.now() 메소드를 호출하여 현재시간을 얻어오기 때문에 -Duser.timezone JVM 실행 옵션 설정 하나만으로 배포한 서버의 운영체제의 타임존을 변경하지 않고도 타임존 변경이 가능하니 유용하게 사용할 수 있다.

public abstract class TimeZone implements Serializable, Cloneable {
	...
    ...
    
    private static native String getSystemTimeZoneID(String javaHome);
    
    ...
    ...
    
    private static volatile TimeZone defaultTimeZone;
    
    ...
    ...
    
	static TimeZone getDefaultRef() {
        TimeZone defaultZone = defaultTimeZone;
        if (defaultZone == null) {
            // Need to initialize the default time zone.
            defaultZone = setDefaultZone();
            assert defaultZone != null;
        }
        // Don't clone here.
        return defaultZone;
    }

    private static synchronized TimeZone setDefaultZone() {
        TimeZone tz;
        // get the time zone ID from the system properties
        Properties props = GetPropertyAction.privilegedGetProperties();
        String zoneID = props.getProperty("user.timezone");

        // if the time zone ID is not set (yet), perform the
        // platform to Java time zone ID mapping.
        if (zoneID == null || zoneID.isEmpty()) {
            String javaHome = StaticProperty.javaHome();
            try {
                zoneID = getSystemTimeZoneID(javaHome);
                if (zoneID == null) {
                    zoneID = GMT_ID;
                }
            } catch (NullPointerException e) {
                zoneID = GMT_ID;
            }
        }

        // Get the time zone for zoneID. But not fall back to
        // "GMT" here.
        tz = getTimeZone(zoneID, false);

        if (tz == null) {
            // If the given zone ID is unknown in Java, try to
            // get the GMT-offset-based time zone ID,
            // a.k.a. custom time zone ID (e.g., "GMT-08:00").
            String gmtOffsetID = getSystemGMTOffsetID();
            if (gmtOffsetID != null) {
                zoneID = gmtOffsetID;
            }
            tz = getTimeZone(zoneID, true);
        }
        assert tz != null;

        final String id = zoneID;
        props.setProperty("user.timezone", id);

        defaultTimeZone = tz;
        return tz;
    }

}
profile
주니어 개발자 입니다
post-custom-banner

0개의 댓글