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

in #spring6 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());

Sort:  

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!

Coin Marketplace

STEEM 0.18
TRX 0.16
JST 0.030
BTC 65974.40
ETH 2637.70
USDT 1.00
SBD 2.67