최근에 시간 관련 Data 를 가지고 삽질을 해서 간단히 적어본다.
상황은 이렇다.
테이블에 특정 Data 를 저장 하고 있었는데 colum 에 언제나 그렇듯 생성 날짜, 시간 형태의 컬럼이 존재하고 있었다. Timestamp type 이었고 Data 는 잘 insert 가 되는 상황이었다. 그런데 이상하게 나는 분명 UTC 기준으로 Data 가 insert 될거라 생각을 했는데 그게 아니었다. Local 기준으로 Data 가 들어가고 있었다. 그러다 보니 이 Data를 사용하는 곳에서 예상치 못한 오류가 발생했다.
1 2 3 4 5 6 | @Test public void jodaTime(){ DateTime dateTime = new DateTime(DateTimeZone.UTC); System.out.println("dateTime : " + dateTime); System.out.println("dateTimeToDate : " + dateTime.toDate()); } | cs |
문제가 된 부분은 위에 코드에 toDate() 부분이었다. 위 코드를 실행하면 결과는 아래와 같이 나온다.
1 2 | dateTime : 2019-02-13T07:01:03.407Z dateTimeToDate : Wed Feb 13 16:01:03 KST 2019 | cs |
뭔가 좀 이상하다. dateTime 은 UTC 기준으로 나왔지만 toDate 값은 로컬 기준으로 나온다. 그리고 그 값이 DB 로 저장이 되고 있었다.
Why????
위에 있는 toDate() 함수는 아래와 같이 구현이 되어있다. 그런데 여기에서 저 Date 가 문제다.
1 2 3 | public Date toDate() { return new Date(getMillis()); } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 | /** * Allocates a <code>Date</code> object and initializes it to * represent the specified number of milliseconds since the * standard base time known as "the epoch", namely January 1, * 1970, 00:00:00 GMT. * * @param date the milliseconds since January 1, 1970, 00:00:00 GMT. * @see java.lang.System#currentTimeMillis() */ public Date(long date) { fastTime = date; } | cs |
@see 를 보면 java.lang.System을 참조하고 있다. -_-;. 그런 결과 아무리 앞에서 offset을 설정해봐야 결과값은 로컬에 있는 jvm 의 timezone을 따라간다는 거다.
만약 DB 에 컬럼 타입이 String 이었다면 이렇게 하면 해결이 되긴 한다.
1 2 3 4 5 | DateTime dateTime = new DateTime(DateTimeZone.UTC); System.out.println("dateTime : " + dateTime); SimpleDateFormat simpleDateFormat = new SimpleDateFormat(); simpleDateFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.of("UTC"))); System.out.println("dateTimeToDateFormatter : " + simpleDateFormat.format(dateTime.toDate())); | cs |
1 2 | dateTime : 2019-02-13T08:07:53.819Z dateTimeToDateFormatter : 19. 2. 13 오전 8:07 | cs |
값은 동일하게 나오긴 하지만 그렇다고 DB 컬럼을 바꾸기에는 뭔가 좀 부담스럽다.
그러면 어떻게 하는게 좋을까... 생각을 해보다가 이런 방법을 생각했다.
1. 현재 로컬의 OffsetDateTime 을 구한다.
2. 그리고 로컬에 있는 Timezone 의 offset을 구한다.
3. offset 에 따른 시간 차이를 분 또는 초로 환산한다.
4. 환산한 값을 현재 로컬 Time 값에서 빼거나 더한다.
절차가 좀 복잡 하긴 하지만 DB 에는 UTC 값을 저장할 수 있게 된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public void getUTC(){ OffsetDateTime now = OffsetDateTime.now(); System.out.println("현재 시간 : " + now); // Offset ZoneOffset offset = now.getOffset(); System.out.println("offset : " + offset); // Offset 을 second 로 변경 int totalSeconds = offset.getTotalSeconds(); System.out.println("totalSeconds : " + totalSeconds); OffsetDateTime offsetDateTime = null; if (totalSeconds > 0){ offsetDateTime = now.minusSeconds(totalSeconds); }else{ offsetDateTime = now.plusSeconds(totalSeconds); } System.out.println("offsetDateTime : " + offsetDateTime); } | cs |
1 2 3 4 | 현재 시간 : 2019-02-14T13:30:38.592+09:00 offset : +09:00 totalSeconds : 32400 offsetDateTime : 2019-02-14T04:30:38.592+09:00 | cs |
여기에서 plus 와 minus 할때 totalSecond 값이 음수이냐 양수이냐 에 따라서 반대로 해야 한다. 우리 나라 같은 경우 +9시간이기 때문에 UTC로 맞추려면 빼줘야 한다.
시간 들어가는 DATA 값은 정말 복잡하고 생각해야 될 것이 많은 것 같다.
'Development > Java' 카테고리의 다른 글
[Spring Boot] There is no PasswordEncoder mapped for the id "null" (0) | 2019.09.09 |
---|---|
Spring Boot Controller Test 하다가 마주친 IllegalArgumentException (0) | 2019.03.07 |
[SpringBoot] Properties 우선순위 (0) | 2018.06.07 |
[SpringSecurity]Spring Reference 수정 (0) | 2018.04.21 |
[SpringBoot] @Mock, @MockBean 차이가 뭘까? (2) | 2018.04.10 |