Java/java.time

SimpleDateFormat - setTimeZone(TimeZone.getTimeZone()) / ZonedDateTime - ZoneId.of()

limbit 2024. 7. 8. 11:26

Java를 사용하면서 시간 관련 데이터를 다룰 때 흔히 사용하는 객체 LocalDateTime이 있다. 

main 메서드를 통해 코드를 컴파일하거나 프로젝트를 로컬에서 작업할 때는 이 LocalDateTime을 사용할 때 전혀 문제가 없다. 하지만 AWS를 통해 서비스를 배포할 때 약간의 문제가 생길 수가 있다. 

 

그것은 바로 표준시와 관련된 문제이다.

나만 그런 것일수도 있겠지만 어째선지 로컬로 작업할 때 LocalDateTime.now()의 표준시가 "Asia/Seoul" 이었으나 AWS를 통해 배포한 서버 안에서는 다른 표준시로 적용이 되어 시간이 가져와지는 것이었다. 

 

사실 DB에 데이터를 삽입할 때 삽입한 시간을 기록하기 위해 oracle에서 SYSDATE 또는 CURRENT_TIMESTAMP를 사용했으나 이마저도 미국으로 추정되는 표준시로 적용되는 것이 아닌가..

그래서 자바의 LocalDateTime을 사용한 것인데 이 녀석마저 한국시간을 가져오질 않으니... 그래서!! 이를 해결하기 위해 사용한 방법은 두 가지가 있었다.

 

1. SimpleDateFormat - setTimeZone(TimeZone.getTimeZone())

SimpleDateFormat은 Date 객체에서 가져오는 시간 데이터를 원하는 String 형태로 쉽게 가져올 수 있게 도와주는 객체이다. 보통 이 객체를 사용할 때

SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD")

이렇게 사용하는게 통상적일 것이다.  나도 이러한 방법으로 현재 시간을 구해 사용하려 했었지만, 한국시간이 구해지지 않았던 것. 여튼 본인들이 원하는 표준시에 대한 설정을 하기 위해선 SimpleDateFormat 객체의 setTimeZone() 이라는 메서드를 사용하면 된다.

그리고 그 함수 안에 매개변수로 TimeZone 객체의 getTimeZone 메서드를 사용하여 특정 표준시를 선언하면 된다.

SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Seoul"));

이렇게 말이다. 이후에 저 sdf.format() 함수 안에 Date 객체의 새로운 인스턴스를 만들어 집어 넣어도 되고, 바로 Date 객체를 집어넣어도 된다.

// 첫 번째 방법
String date = sdf.format(new java.util.Date());

// 두 번째 방법
LocalDateTime localDateTime = LocalDateTime.now();
String date = sdf.format(localDateTime);

그리고 참고로 나는 요일을 구하려고 했었기 때문에 나랑 동일하게 요일을 구하려는 분들은 아래 코드를 사용하면 된다.

// 요일 한국어로 가져오기
SimpleDateFormat sdf = new SimpleDateFormat("EEEE");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Seoul"));
String date = sdf.format(new java.util.Date());

// 요일 영어로 가져오기
SimpleDateFormat sdf = new SimpleDateFormat("EEEE", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Seoul"));
String date = sdf.format(new java.util.Date());

LocalDateTime 자체에서도 요일을 가져올 수 있지만 지금은 해당 이 LocalDateTime의 표준시를 변경시키는 SimpleDateFormat에서 시간을 가져오는 중이기에 변경된 표준시의 요일을 가져오려면 SimpleDateFormat에서 요일을 가져와야 하기 때문~

 

어쨌든 이렇게 하면 본인이 원하는 표준시의 시간 혹 요일을 가져올 수 있다. 원하는 표준시의 지역의 종류(목록)을 보고 싶다면 자바에서 ZoneId 클래스에 접근하면 확인할 수 있다. 이클립스든 인텔리제이든 ZoneId 타이핑 후 해당 텍스트를 ctrl 키 누른 상태에서 마우스 왼쪽 클릭 하면 해당 객체를 만드는 클래스에 접근할 수 있다.

public abstract class ZoneId implements Serializable {

    /**
     * A map of zone overrides to enable the short time-zone names to be used.
     * <p>
     * Use of short zone IDs has been deprecated in {@code java.util.TimeZone}.
     * This map allows the IDs to continue to be used via the
     * {@link #of(String, Map)} factory method.
     * <p>
     * This map contains a mapping of the IDs that is in line with TZDB 2005r and
     * later, where 'EST', 'MST' and 'HST' map to IDs which do not include daylight
     * savings.
     * <p>
     * This maps as follows:
     * <ul>
     * <li>EST - -05:00</li>
     * <li>HST - -10:00</li>
     * <li>MST - -07:00</li>
     * <li>ACT - Australia/Darwin</li>
     * <li>AET - Australia/Sydney</li>
     * <li>AGT - America/Argentina/Buenos_Aires</li>
     * <li>ART - Africa/Cairo</li>
     * <li>AST - America/Anchorage</li>
     * <li>BET - America/Sao_Paulo</li>
     * <li>BST - Asia/Dhaka</li>
     * <li>CAT - Africa/Harare</li>
     * <li>CNT - America/St_Johns</li>
     * <li>CST - America/Chicago</li>
     * <li>CTT - Asia/Shanghai</li>
     * <li>EAT - Africa/Addis_Ababa</li>
     * <li>ECT - Europe/Paris</li>
     * <li>IET - America/Indiana/Indianapolis</li>
     * <li>IST - Asia/Kolkata</li>
     * <li>JST - Asia/Tokyo</li>
     * <li>MIT - Pacific/Apia</li>
     * <li>NET - Asia/Yerevan</li>
     * <li>NST - Pacific/Auckland</li>
     * <li>PLT - Asia/Karachi</li>
     * <li>PNT - America/Phoenix</li>
     * <li>PRT - America/Puerto_Rico</li>
     * <li>PST - America/Los_Angeles</li>
     * <li>SST - Pacific/Guadalcanal</li>
     * <li>VST - Asia/Ho_Chi_Minh</li>
     * </ul>
     * The map is unmodifiable.
     */

요렇게 말이다.

 

2. ZonedDateTime - ZoneId.of()

두 번째 방법으로는 ZonedDateTime 객체가 있다. 사실 첫 번째 방법이나 두 번째 방법이나 크게 차이 없지만 이 녀석은 여로모로 장점이 있는 녀석이니 자주 사용하면서 미리 사용법을 익히는 것도 나쁘지 않다.

여러 장점들이 있지만 그 중 하나만 꼽자면 이 녀석은 시간대 정보도 포함하고 있어 서로 다른 시간대를 사용해야 할 때 시간 조작에 용이하며 시간대 간 데이터 동기화가 편리하다.

여튼, ZonedDateTime을 통해 표준시 변경하여 시간을 가져오는 방법을 위의 방법보다 간단하다.

ZonedDateTime koreanDateTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul"));
ZonedDateTime ParisDateTime = ZonedDateTime.now(ZoneId.of("Europe/Paris"));

ZonedDateTime 객체를 선언하고 ZonedDateTime.now() 함수 안에 ZoneId.of() 메서드를 넣어주고, ZoneId.of() 함수 안에는 원하는 표준시의 지역을 선언하면 된다. 

끝이다.

정말 간단하다.

 

이러한 방법으로 AWS에서 서버를 배포하고, 해당 서버에서 현재 시간을 가져올 때 내가 원했던 한국시간이 제대로 출력할 수 있다.

 

나도 아직 ZonedDateTime 객체를 온전히 다 활용해보지는 않았지만, 앞으로 자주 사용해보면서 더 익숙해져야겠다.