반응형

최근에 시간 관련 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 값은 정말 복잡하고 생각해야 될 것이 많은 것 같다.



728x90
반응형

+ Recent posts