글로벌 서비스 개발시 Timezone 에 맞춰 날짜 표기하기.

in spring •  6 years ago 

개발환경 : Spring 4.0
JDK : 1.7

날짜 표기가 중요한 글로벌 서비스를 제작시 전세계 타임존에 맞는 시간으로 포맷을 변경해줘야 한다.
서버시간인 서울 타임존을 기준으로 각 타임존에 맞는 시간으로 포맷 변경해주기 위한 제반 개발 절차를 정의한다.

  1. pom.xml

JDK 기본날짜 클래스에서 제공하는 java.util.Date, java.util.Calendar 클래스는 일관성이 없고 상수의 혼란, 일관성이 없으므로
가급적이면 joda-time을 사용하길 권장한다.

joda-time 2.9.9 추가

  1. 테스트용 테이블 생성
    데이터 타입이 VARCHAR인 expired 필드에 밀리세컨드값을 저장하게 됩니다.

CREATE TABLE sl_tz_test (
idx int(11) NOT NULL,
expired varchar(200) DEFAULT NULL,
PRIMARY KEY (idx)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

  1. DTO 생성

저장된 밀리세컨드값을 이용하여
서버시간인 서울 타임존을 기준으로 각 타임존에 맞는 시간으로 포맷 변경하여 출력한다.

import org.joda.time.*;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.util.*;

public class TestTimstampVO {
private int idx;
private String expired;
private String expiredLocalTime;

public int getIdx() {
    return idx;
}
public void setIdx(int idx){
    this.idx=idx;
}

public String getExpired() {
    return expired;
}
public void setExpired(String expired){

    DateTime expDT = new DateTime(Long.parseLong(expired));
    DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyyMMddHHmmss");
    formatter.withZone(DateTimeZone.forID("Asia/Seoul"));

    String tzExp=getTimeWithTimezone(expDT.toString(formatter),
            "yyyyMMddHHmmss",
            getMinuteCurrentTzOffset("Europe/Berlin"));

    this.expiredLocalTime = tzExp;
    this.expired=expired;
}

public String getExpiredLocalTime(){
    return expiredLocalTime;
}
public void setExpiredLocalTime(String expiredLocalTime){

    this.expiredLocalTime = expiredLocalTime;
}

/**
* 서버시간인 서울 타임존을 기준으로 각 타임존에 맞는 시간으로 포맷 변경하여 출력함.
* @param time 변경 대상 시간
* @param format 시간 포맷
* @param offset 변경할 타임존 offset (분) - (TIMEZONE = +540)
* @return
*/

public static String getTimeWithTimezone(String time, String format, String offset)
{
    String result = "";

    int timezoneOffset = Integer.parseInt(offset.replace("+", ""));

    try {

        if( !offset.equals("+540") ) {    // 서울 시간이 아닌경우에만 로직 수행

            DateTimeZone seoulTZ = DateTimeZone.forID("Asia/Seoul");
            DateTimeZone outputTz = DateTimeZone.forOffsetMillis(timezoneOffset * 60 * 1000); // 출력하고자 하는 Timezone 으로 변환


            DateTimeFormatter df = DateTimeFormat.forPattern(format + " Z");
            DateTime temp = df.withOffsetParsed().parseDateTime(time + " +0900"); // 서버시간인 서울시간 기준으로 입력
            Date date = temp.toDate();
            DateTime dateTime = new DateTime(date);


            DateTimeFormatter df2 = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
            DateTimeFormatter df3 = df2.withZone(seoulTZ);


            DateTimeFormatter rdf = DateTimeFormat.forPattern(format);
            DateTimeFormatter wdd = rdf.withZone(outputTz);
            result = dateTime.toString(wdd);
        }else{
            result = time;
        }
    } catch (Exception e) {
        result = time;
    }

    System.out.println("타임존 offset : "+offset);
    System.out.println("입력된 시간 : "+time);
    System.out.println("변환 시간 :"+ result);

    return result;

}

/**
 * 타임존 아이디의 밀리세컨드 offset을 구하고 이를 (분)으로 변경
 * @param zoneId
 * @return
 */
public static String getMinuteCurrentTzOffset(String zoneId) {

    int offsetInMillis = DateTimeZone.forID(zoneId).getOffset(new DateTime().getMillis());

    int minute=(Math.abs(offsetInMillis / 3600000) * 60) + ((offsetInMillis / 60000) % 60);
    String offsetMinute = (offsetInMillis >= 0 ? "+" : "-") + minute;

    return offsetMinute;
}

/**
 * 타임존 아이디에 해당하는 offset을 구함 (시간단위) .
 * @param zoneId
 * @return
 */
public static String getCurrentTzOffset(String zoneId) {

    int offsetInMillis = DateTimeZone.forID(zoneId).getOffset(new DateTime().getMillis());
    String offset = String.format("%02d:%02d", Math.abs(offsetInMillis / 3600000),
            Math.abs((offsetInMillis / 60000) % 60));
    offset = (offsetInMillis >= 0 ? "+" : "-") + offset;

    return offset;
}

}

  1. 프론트 jquery
    javascript의 Date 오브젝트에 'YYYYMMDDHHMMSS' 프로토타입 추가하고
    아래처럼 호출하여 Date Format을 맞춰준 후 서버측으로 보낸다.

var exp=$("#expired").val();
console.log(parseInt(new Date(exp).YYYYMMDDHHMMSS()));

Object.defineProperty(Date.prototype, 'YYYYMMDDHHMMSS', {
value: function() {
function pad2(n) { // always returns a string
return (n < 10 ? '0' : '') + n;
}

    return this.getFullYear() +
        pad2(this.getMonth() + 1) +
        pad2(this.getDate()) +
        pad2(this.getHours()) +
        pad2(this.getMinutes()) +
        pad2(this.getSeconds());
}

});

  1. 서버사이드

수신한 YYYYMMDDHHMMSS 값을 DateTimeZone.UTC 밀리세컨드로 변환 후
위에 기술한 테이블의 VARCHAR 타입의 필드에 String으로 입력한다.

DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyyMMddHHmmss");
DateTime dt = new DateTime(formatter.parseDateTime(String.valueOf(tzvo.getExpired())), DateTimeZone.UTC);

System.out.println("millis: " + dt.getMillis());

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

Congratulations @rumbus! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Do not miss the last post from @steemitboard:

SteemitBoard Ranking update - A better rich list comparator
Vote for @Steemitboard as a witness to get one more award and increased upvotes!

Congratulations @rumbus! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 1 year!

Click here to view your Board

Support SteemitBoard's project! Vote for its witness and get one more award!