브라우저의 콘솔에서 new Date()
를 입력하면 사용자의 시간대에 맞게 날짜가 나오는 것을 볼 수 있다.
만약 서버에서 타임존이 없이, 2024-01-29
라는 값을 내려줬을 때, 나라마다 모두 29일을 new Date('2024-01-29')
만으로 바로 표시할 수 있을까?
서버에서 내려주는 값이 '2024-01-29' 같이 시간이나 UTC 값이 없이 그냥 kst 기준의 시간만 내려주는 api가 있었다. 그 때, 내 컴퓨터로 볼 때는 별다른 이상이 없었고, qa 시에도 문제 없이 넘어갔다. 그런데 나중에 미국에서는 29일이 아닌 28일로 보인다는 이슈가 들어왔다.
그래서 찾아본 결과 시간까지 붙이지 않은 날짜 값을 new Date()
하면 해당 날짜를 UTC의 날짜로 보고 locale 기준으로 변환하여 보여준다는 것을 알 수 있었다.
위를 입력했을 때 반환값이 2024년 1월 29일 9시이다. 즉, 입력 된 날짜를 UTC 날짜로 보고 +09:00:00 을 한 값을 반환한 것이다.
미국 날짜로 보기 위해서는 크롬 개발자도구에서 cmd + shift + p 를 누른 다음 Sensors를 들어가서 설정을 바꾸면 된다.
이렇게 설정을 바꾸고 나면 new Date('2024-01-29')
시 1월 28일 16시로 나오는걸 볼 수 있는데, 미국 샌프란시스코에서는 28일로 찍힐 것이다.
그러면 어느 나라든 2024-01-29 로 찍히려면 어떻게 해야할까?
new Date('2024-01-29 00:00:00')
처럼 뒤에 시간까지 붙여주게 되면 그대로 나오게 된다.
어느 나라든 동일한 일자로 나오게 하려면 위 방법을 쓰면 된다.
위에서는 특이한 상황이었다. 서버에서 KST 기준으로 DB에 저장해놓고 있었기 때문에 UTC 기준으로 조회하기가 쉽지 않았고, 안 좋은 방법인걸 알지만 채택한 방법이다.
그러면 보통은 어떻게 하는게 좋을까?
사용자에게는 자신의 local Time으로 보이는게 사용자 경험이 좋을 것이다. UTC 기준으로 보이게 해놓고 설명에 위 시간은 UTC 기준으로 나타내어져 있습니다. 라고 적어놓으면 UTC가 뭔지 모르는 사용자들도 많을 것이고, 알더라도 매번 계산하기 귀찮을 것이다.
그래서 프론트에서는 사용자의 local time으로, 서버와의 통신은 UTC로 하는게 좋다.
서버와 날짜에 대한 값을 통신할 때 url에 있는 query string을 그대로 보내줄 때가 있고, form 형식에 넣은 날짜라 body에 넣어 보낼 때가 있을텐데 두가지 방법에서 다르게 보내는 방식이 좋지 않을까한다. 또는 둘다 timezone을 같이 보내는 것도 방법일 것 같다.
url의 query string에 서버와 주로 주고 받는 2024-01-29T00:00:00.000Z
의 형식과 같이 들어가 있으면 미관상(?) 좋지 않기 때문에, 2024-01-29
만 보내고 사용자의 timezone을 custom Header
에 넣어 보내는 것이다. deprecated 된 방식이지만 우리는 'X-Time-Zone이라는 커스텀 헤더에 사용자의 timezone을 넣어 보내는 방식을 사용하고 있다. 사용자의 timezone은
Intl.DateTimeFormat().resolvedOptions().timeZone
` 로 얻을 수 있다.
그러면 서버에서 해당 timeZone을 활용해 UTC로 시간을 변경해서 사용하는 것이다.
body에 시간을 담아 보낼 때는 그냥 UTC 시간으로 변경해서 보내면 될 것이다. new Date().toISOString()
을 하면 된다. 또는 Dayjs
같은 라이브러리의 도움을 받아서 더 다양한 방식으로 변환한 다음 보내보자.