Date는 어떻게 주고 받는게 바람직할까요?

2023년 3월 23일

주의 ⛔️

  • 이 글이 작성된지 1년이 넘었어요.
  • 누구나 숨기고 싶은 흑역사가 있답니다.

제품을 만들다 보면, Date를 관리할 일이 정말 많습니다.

  • 인증 만료까지 남은 시간
  • 이벤트 종료까지 남은 시간
  • 등등 …

그리고 이런 Date를 외부의 존재와 함께 다루어야 하는 일이 많이 생기게 됩니다. 가장 가까운 예시가 서버와 Date를 주고받는 것이죠.

이 때 Date를 어떤 형태로 주고받고, 관리하는 것이 좋을까요?

우선, Date를 표현하고 교환하는 표준이 담긴 ISO 8601과, 국제표준시인 UTC 부터 알아봅시다.

ISO 8601 표준과 UTC

UTC는 1972년부터 시행된 협정 세계시로, 전세계의 시간 계산의 기준이 되는 시간입니다.

컴퓨터는 UTC를 기준으로 시간을 계산하고, 그 시간을 데이터로 표현할 때는 ISO 8601 표준을 사용합니다.

아래처럼 시간을 표현하는게 ISO 8601 표준입니다.

"2022-09-21"
"2022-09-21T12:00:00"

UTC와의 시차는 어떻게 표현하나요?

UTC와 현지 시간의 차이를 UTC offset 이라고 합니다. 그리고 ISO 8601 표준에서 UTC offset은 아래와 같은 형식으로 표현됩니다.

"2022-09-21T12:00:00±[hh]:[mm]"

예를 들어, 한국시(KST)는 UTC보다 9시간 만큼 뒤에 있으므로, KST로 2022년 9월 21일 12시는 아래와 같이 표현할 수 있습니다.

"2022-09-21T12:00:00+09:00"

위 문자열은 “UTC인 2022년 9월 21일 3시에, UTC와의 시차인 9시간을 더한, 2022년 9월 21일 12시” 를 의미합니다.

그리고 국가/지역별 UTC offset을 분류해둔 것(예시: KST)을 타임존이라고 합니다. 우리는 이 타임존 정보를 활용해 Date를 현지 시간에 맞추어 읽어들일 수 있는 것입니다.

그럼 UTC는 어떻게 표현할 수 있어요?

UTC를 직접적으로 표현할 때는, 맨 끝에 꼭 Z 또는 UTC offset +00:00 을 붙여줘야 합니다.

"2022-09-21T12:00:00Z"
"2022-09-21T12:00:00+00:00"

Z 하나 차이일 뿐인데, (Javascript 기준)아래 코드는 왜 다른 결과를 보여줄까요?

// Fri May 06 2022 00:00:00 GMT+0900 (한국 표준시)
new Date("2022-09-21T00:00:00").toString();

// Fri May 06 2022 09:00:00 GMT+0900 (한국 표준시)
new Date("2022-09-21T00:00:00Z").toString();

"2022-09-21T00:00:00" 은 UTC라는 명시도 없고, UTC offset에 대한 명시도 없습니다. 그래서 자동으로 로컬 타임존인 KST로 가정하고 계산되어 결과가 나오게 됩니다.

그에 반해 "2022-09-21T00:00:00Z" 는 맨 끝에 Z를 붙여주어, 2022년 9월 21일 0시가 UTC라고 명시해 주었기 때문에, 현지 시간인 KST에 맞춰 계산되면, UTC인 "2022-09-21T00:00:00" 에 9시간을 더한 결과가 나오게 됩니다.

Date를 외부와 주고 받는 방법

앞서 설명한 내용을 읽으셨다면 눈치 채셨을 겁니다. 외부의 존재와 Date를 주고 받을 때에는 항상 타임존을 명시하고 주고받아야 합니다.

따라서 아래와 같이 타임존을 알 수 있는 형태로 Date를 주고 받아야 합니다.

1. UTC offset 명시
"2022-09-21T12:00:00+09:00"

2. UTC ISO string
"2022-09-21T03:00:00Z"

3. Unix Timestamp
1663729200000

Unix Timestamp는 UTC 기준 1970년 1월 1일 0시 0분 0초 부터 몇 밀리초가 지났는지를 나타내는 숫자 값입니다.

타임존을 명시하지 않으면 어떻게 돼요?

예를 들어서, 한국 시간 기준 2022년 9월 21일 12시를 타임존 명시 없이 아래와 같이 다룬다고 가정하고, 여러 상황을 예시로 들어보겠습니다.

"2022-09-21T12:00:00"

만약 한국에 위치한 서버에서 유저에게 "2022-09-21T12:00:00"를 응답했는데, 그 유저는 미국에 살고 있는 유저라면? 응답받은 Date를 미국 시간 기준으로 변환해서 보여줘야 할 것입니다. 하지만 해당 Date가 한국 시간이라는 정보가 명시되어 있지 않기 때문에, 당연히 미국 시간으로도 변환할 수가 없습니다.

반대로 만약 한국에 살고 있는 유저가, 미국에 위치한 서버에 "2022-09-21T12:00:00"와 함께 요청을 보냈는데, 서버에서 Date 비교를 해야하는 상황이라면? 올바른 비교를 위해 두 Date의 타임존을 통일해야 하지만, 유저가 보낸 Date에 타임존 명시가 없기 때문에 이 때에도 제대로된 비교가 불가능 합니다.

또한 만약에 한국에 위치한 서버가 미국에 위치한 DB에 "2022-09-21T12:00:00"을 저장해야 한다면? DB에는 미국시 기준으로 변환되어 저장되어야 하겠지만, 이 때도 변환이 제대로 되는게 당연히 불가능하므로. 나중에 데이터를 다시 꺼내왔을 때 시간이 매우 꼬이게 될 가능성이 매우 높습니다.

결론은, 외부의 존재와 이야기할 때는 내가 어떤 타임존에 위치해 있는지, 즉 내가 응답한 시간이 어떤 타임존 기준인건지 알려주는게 정말 당연한 겁니다.

가령 "내 서버는 항상 미국에 위치해 있으니, 너희들은 내가 타임존 명시를 안해주더라도 당연히 미국 시간으로 가정하고 쓸 수 있지 않아?" 라는 의견이 있을 수 있습니다.

그런데 이때 미국을 포함한 여러 나라들은 서머타임이라고 해서 매년 특정 기간동안 표준 시간을 앞당겨 쓰는 규칙을 따릅니다. 클라이언트가 서머타임까지 고려해서 시차를 계산하는 로직을 작성하는 것 보단, 서버에서 타임존을 명시하는 것이 더 좋은 방향입니다.

서머타임이 없는 나라라고 해도 마찬가지입니다. 클라이언트에서 본인이 요청하는 서버 별로 "이 서버가 어떤 타임존에 위치해 있는가?"를 관리하는 것 보단, 서버에서 타임존을 명시하는 것이 더 좋은 방향입니다.

몇십년 동안 고생하여 국제 표준이 만들어진 데에는 그럴만한 이유가 있을 것이라고 생각하고, 따르시는 것을 권장드리고 싶습니다. 혹시나 조직 내에서 타임존 명시가 이루어지지 않고 있다면, 직접 개선 의견을 내보는 것은 어떨까요?

여담

UTC와 GMT의 차이가 무엇인가요?

둘이 사실상 똑같은 시간을 나타내지만, 계산 방법이 다릅니다.

GMT는 경도 0인 그리니치 천문대를 기준으로 하는 태양시에요. 다만 지구의 자전속도의 변화로 GMT의 오차에 대한 우려가 나왔고, 과학적으로 더 정확한 기준 시간대가 필요해졌어요.

그래서 세슘 원자의 진동수로 계산하는 UTC가 생겨나게 되었습니다. 그리고 1972년부터는 GMT 대신 UTC를 표준으로 지정했다고 합니다.

UTC 표현에 사용되는 Z는 무엇을 의미하나요?

1950년부터 GMT을 나타내는 letter suffix로 Z를 사용했다고 합니다. 따라서 UTC를 나타내는 데에도 Z가 그대로 사용되는 듯 하네요.

그리고 NATO phonetic alphabet 에서 Z가 Zulu라고 읽히기 때문에, UTC와 GMT를 Zulu time 이라고도 부른다고 합니다.