[월간 다노 프론트 — 6호] Javascript에서 시간 핸들링하기
React Custom Hook으로 시간에 따라 다른 UI 보여주자
H님의 휴가로 잠시 맡게 된 마이다노
H님이 여행을 갔습니다. 설 연휴 즈음부터 2월 중순 동안 여행했기 때문에 그 동안 저는 다노샵과 더불어 마이다노 프론트 작업도 같이 했습니다. 기존에 제가 맡고 있는 다노샵도 잘하고 싶었고, 잠시동안 맡은 마이다노 쪽 업무도 잘해내고 싶었지만 사실상 다노샵쪽은 피쳐개발이 멈춰졌습니다.
흠이 되지 않기 위해 나름 열심히 작업했던 2월이었지만, H님은 제가 이 기간 동안 마이다노 업무를 한 것은 같은 프론트엔드 개발자로서 당연한 것이라 생각하여 고마워할 필요성을 못느낀다고… 그 말과 행동에 굉장히 깊은 실망과 상당한 분노를 느꼈습니다. 다음에 기회가 된다면 좋은 동료에 대하여
라는 주제로 글을 써봐야겠습니다 🤯
이번에 해야했던 일 — 시간대에 따라 다른 UI가 노출되도록 하기
마이다노 3월 클래스에서는 타임세일 프로모션을 진행했습니다. 슈퍼얼리버드, 얼리버드, 스페셜이라는 타임세일 구간이 있었고, 각 시간대에 맞춰서 그에 맞는 UI를 보여줘야 했습니다.
예를 들면, 2월 13일 11:00:00 KST ~ 2월 15일 14:00:00 KST 까지가 슈퍼얼리버드 할인 기간이라면 그에 맞는 UI 등을 노출하는 것입니다.
마이다노 프로덕트 유닛에 회의를 들어갔을 때 PM분께서는 제게 부담을 주지 않기 위해 시간대에 맞춰서 따로따로 배포를 해도 된다고 하셨지만… 사실 시간을 맞춰서 배포를 한다는 것이 더 어렵기 때문에 한 번에 배포해서 시간에 따라 UI가 달라지도록 구현하는 것이 더 효율적이라는 생각이 들어서 Javascript로 시간을 핸들하는 방식을 택했습니다.
프론트엔드단에서 Javascript로 시간을 핸들링하는 것이 어려운 이유
참고: Date 오브젝트(object)의 핵심 시간 값은 UTC이지만, 날짜와 시간 또는 컴포넌트들을 가져오기 위한 기본 메소드들은 모두 로컬 시간대(예. 호스트 시스템)와 오프셋 내에서 동작한다는 점을 유념해야합니다.
프론트엔드 개발자 입장에서 자바스크립트에서 시간을 핸들하기 어려운 이유는 바로 Date 오브젝트를 핸들할 때 로컬 시간에 영향을 받는다는 것입니다.
예를 들어 제 노트북의 시간이 한국시간 오전 10시이고, 바로 옆자리에 있는 제 친구의 노트북 시간은 조작해서 한국시간 오후 12시인 상태라고 가정해봅시다. 크롬 브라우저 콘솔탭에서 new Date()
를 입력하면 각자의 노트북에 설정된 시간(오전 10시, 오후 12시)로 서로 다르게 출력됩니다. 실제로 같은 한국에서 같은 시간대에 있는 상황임에도 불구하고 말이죠.
로컬 시간에 영향을 받지 않고 현재 시간이 항상 일정하려면 서버로부터 시간을 받는 방법 뿐입니다.
서버시간 받는 방법1 — 시간 알려주는 API가 없다면 XMLHttpRequest
서버에서 시간 관련 API가 없다면 XMLHttpRequest
를 통해 GMT 시간 정보를 받아오는 방법이 있습니다.
XMLHttpRequest
는 서버에 쉽게 요청을 보낼 수 있게 해주는 Web API- fetch, AJAX 콜을 사용하기 이전부터 사용했왔던 메소드
- AJAX도
XMLHttpRequest
를 이용하여 서버에 요청을 보내는 방식 - HTTP 이외에도 ftp 등 다른 프로토콜 요청도 할 수 있음
XMLHttpRequest
은 서버에 쉽게 요청을 보낼 수 있게 해주는 코어 개념이라는 생각이 들었습니다.
The HEAD method is identical to GET except that the server MUST NOT send a message body in the response (i.e., the response terminates at the end of the header section).HEAD 메소드는 서버가 response에 body를 보내지 말아야 한다는 점을 제외하고는 GET과 동일합니다. (즉, 헤더 섹션의 종료시점에 response가 종료됩니다.)출처: HEAD method Specification
XMLHttpRequest
를 이용해서 시간정보를 받아올 때는 HTTP HEAD method 특성을 이용하면 좋습니다. GET, POST 등의 method들이 있지만, HEAD 메소드는 기능상 GET 메소드와 동일하나 서버가 response에 body를 실어도 될 필요가 없다는 점이 다릅니다. 서버의 존재여부나 하이퍼텍스트 링크 테스트를 해보거나 response body가 필요 없는 경우에 사용합니다.
서버시간 받는 방법2 — 시간 알려주는 API가 있다면!
마이다노는 이미 시간을 받아오는 API가 존재합니다. 이 API를 호출하면 기존의 API call 보다 하나 더 많은 요청을 서버에 보내기 때문에 써야하나 고민을 했습니다. XMLHttpRequest
의 HEAD method를 사용하는게 서버 입장에서는 body를 줄 필요가 없기 때문에 훨씬 부담이 적지 않을까 생각했거든요.
하지만 동기적으로(Synchronous) XMLHttpRequest
를 하는 것은 deprecated되었기 때문에 앞으로도 사용할 수 있는 코드를 쓰려면 시간 API를 이용하는 편이 좋겠다생각했습니다.
보통 API 요청을 받아서 처리하는 것과 같은 원리로 진행을 합니다. 시간 정보를 달라고 서버에 GET 요청을 보내고, 서버에서 받은 response에서 시간 정보를 줍줍하여 시간을 핸들하면 됩니다.
그런데 자바스크립트를 프론트엔드에서 사용할 때에는 로컬시간에 영향을 받습니다. 핸들 하려는 자, ISO8601 표기법을 익혀야합니다!
⏰ 시간 표현의 방법(ISO8601 표기법)을 알아야 시간 핸들을 할 수 있습니다.
자바스크립트에서 시간 관련한 작업을 하면 new Date()
함수로 Date 객체를 생성해서 핸들하게 됩니다. new Date(매개변수)
의 매개변수로는 4가지를 사용할 수 있습니다.
1. 아무것도 안넣기(그러면 현재 로컬 날짜와 시간으로 Date객체 생성)
2. 유닉스 타임스탬프(예. 1584172380000)
3. ISO8601 형태에 따른 string 타입의 날짜(예. 2020–02–12T02:00:00Z)
4. new Date(연, 월, 일, 시, 분, 초, 밀리초)로 적기
만약 한국 시간으로 2020년 3월 14일 새벽 2시 53분
부터 무언갈 해보고 싶다고 가정해봅시다. 이 시간과 현재 시간을 비교해서 현재 시간이 더 클 경우에 무언가 바꿀 것들을 코드로 적으면 됩니다.
그런데 노트북 시간이 서울일 때와 미국 뉴올리언스 시간으로 조작했을 때에 똑같은 new Date("2020–03–14 02:53")
로 Date 객체를 생성했음에도 unix time stamp가 다르다는 것을 알 수 있습니다.
한국 시간으로 2020년 3월 14일 새벽 2시 53분
부터 프로모션을 시작하고 싶다면 여기서 이러시면 안됩니다 🙅🏻♀️
시간 표현의 방법을 알아보자
저는new Date()
의 매개변수에 넣을 매개변수로 ISO8601 표기형식의 string을 넣었습니다. unix time stamp도 좋겠지만, 코드를 읽을 때 가독성이 떨어질 수 밖에 없을 것 같았기 때문입니다.
사실 ISO9001 인증 같은건 들어봤어도 이번에 작업하면서 ISO8601은 처음 알았습니다. 시간 표기도 표준이 있겠거니 했지만, 큰 관심을 가진 적이 없었습니다. ISO8601는 날짜와 시간에 대한 국제표준이고, 다른 개발문서보다 wiki를 읽는 편이 빠르게 이해하는데 도움이 됐습니다.
👉 ISO8601 wiki : https://ko.wikipedia.org/wiki/ISO_8601
2020–03–14T02:53:00Z
이런 식의 표기가 ISO8601에 따른 표기방법이고, 이 string을 new Date(“2020-03-14T02:53:00Z”);
처럼 작성하면 로컬 시간을 조작해도 항상 같은 unix time stamp를 얻을 수 있습니다.
만약 한국시간인 것으로 표현하고 싶다면 아래와 같이 Z 대신 time offset 값을 넣어주면 됩니다.
new Date(“2020-03-14T02:53:00+09:00”);
이제는 로컬시간을 조작해도 항상 같은 time stamp를 얻을 수 있습니다.
그렇게 만든 React Custom hook ⚛️
대략 이런 흐름으로 현재 시간과 프로모션 시간 정보를 비교하여 그에 맞는 프로모션 데이터들을 return 해주는 React custom hook을 만들어서 필요한 페이지마다 hook을 호출해서 얻은 state로 ui를 교체했습니다 :)