프로그래밍 언어/Java

[Java] Java Project TimeZone 설정하기(UTC, KST, Asia/Seoul), TimeZone 뜯어보기

코딩하는흑구 2021. 2. 10. 09:31

안녕하세요.

 

이번 포스팅은 자바 프로젝트를 진행할때 시간대를 매번 계산하기 어려워서 시간대 설정이 필요한 부분에 대해서 전체적으로 프로젝트의 시간대를 설정하는 방법과 원리에 대해서 소개해보고자 합니다.

 

일단 시간대는 기본적으로 시스템 default를 따르게 됩니다. 대한민국에서 이 블로그를 보고 있으시면 그냥 KST 한국 표준시라고 생각하시면 됩니다.

 

하지만 다국어 및 다양한 시간대를 제공해야하는 어플리케이션의 경우 기본적으로 UTC 시간대를 기준으로 잡고 해당 시간대를 기준으로 날짜/시간 객체를 처리하곤 할 것입니다.

 

일단 먼저 프로젝트의 전체 시간대를 시스템 default 시간대가 아닌 UTC 시간대를 바라보도록 수정해보겠습니다.

 

프로젝트 UTC 시간대 바라보기
TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("UTC")));

일단 위와 같이 TimeZone 객체의 static 메소드인 setDefault 메소드에 TimeZone 타입을 넣어주게 되면 해당 Zone에 해당하는 ID값으로 TimeZone이 셋팅되게 됩니다.

 

이제 TimeZone 객체를 뜯어보겠습니다.

 


TimeZone 클래스

 

setDefault 메소드

public static void setDefault(TimeZone zone)
    {
        SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            sm.checkPermission(new PropertyPermission
                               ("user.timezone", "write"));
        }
        defaultTimeZone = zone;
    }

위에서 호출한 setDefault 메소드는 내부 프로퍼티를 수정하면서 timezone을 파라미터로 넘어온 timezone으로 수정하게 됩니다. 이때 defaultTimeZone이라는 변수에 저장되게 되는데요. TimeZone 클래스는 대부분 static 클래스라서 static 변수인 defaultTimeZone에 초기화된 값은 시스템 내에서 결국 이 값을 호출하게 되므로써 날짜 시간 객체들이 초기화됩니다.

 

getDefaultRef 메소드

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

위에서 설명했듯이 defaultTimeZone의 값을 받아서 주석을 보게되면 clone이 아니라는 것이고 결국 참조를 넘겨주게 되는 것입니다.

 

그럼 getDefaultRef 메소드는 어디서 호출될까요??

 


Calendar
public static Calendar getInstance()
    {
        return createCalendar(TimeZone.getDefault(), 
                              Locale.getDefault(Locale.Category.FORMAT));
    }

자바에서 LocalDateTime 이전에 많이 사용되었던 Calendar 클래스입니다.

getInstance 메소드를 호출해서 인스턴스를 만들고 createCalendar 메소드를 보시면 TimeZonegetDefault() 메소드를 호출합니다. 이 메소드는 결국 안쪽에서 getDefaultRef().clone()을 호출하고 있는데요. 이는 같은 값을 지녔다고 볼 수 있고, TimeZone의 defaultTimeZone의 값은 Calendar로 넘어가서 설정한 TimeZone으로 설정된 시간값의 Calendar 인스턴스가 생성됩니다.

 

마찬가지로 맨 위에서 호출한 LocalDateTime.now()를 살펴보면

 

public static ZoneId systemDefault() {
return TimeZone.getDefault().toZoneId();
}

LocalDateTime
/* LocalDateTime now() 메소드 */
public static LocalDateTime now() {
    return now(Clock.systemDefaultZone());
}

/* Clock systemDefaultZone() 메소드 */
public static Clock systemDefaultZone() {
    return new SystemClock(ZoneId.systemDefault());
}

/* ZoneId systemDefault() 메소드 */
public static ZoneId systemDefault() {
    return TimeZone.getDefault().toZoneId();
}

길을 돌아돌아 가겠지만 결국 TimeZone.getDefault() 를 호출하게 되고 이는 곧 위에서 봤던 메소드인 getDefaultRef()의 결과의 clone을 만들게 되므로 같은 값일 것이고 해당 timezone에 해당되는 now() 값을 리턴하게 될 것입니다. 즉, 한국시각 9시라면 설정된 TimeZone은 UTC이므로 9시간 느린 자정을 반환하게 되겠습니다.