[iOS/Safari] new Date() Invalid date Error (NaN)

흔한 감자·2023년 9월 20일
0
post-thumbnail

날짜가 이상허다 이상해

2020-01-01 00:00:00 날짜를 new Date() 할당했을 뿐인데 갑자기 모든 데이터가 NaN으로 발생하는 이슈현상이 발생합니다. 참고로 해당 이슈는 최신 16 버전 이상의 iOS/Safari 에서는 발생하지 않습니다.

왜 그럴까?

1. 구글링해서 원인 찾아보기

  • 스택오브 플로우 글에 의하면 사파리에서 정확한 ISO 8601 format만 지원되기 때문에 발생하는 오류라고 되어있습니다.
  • ISO 8601 format은 2000-01-01T03:00:01:00Z 형태처럼 T 구분자와 Z와 같은 타임존이 완벽에 하게 붙어있는 문자열형태를 말합니다.

해당글 포함 여러 글들을 읽었지만 RFC3339, RFC2822 등의 키워드들도 등장해서 정확히 어떤 형태의 날짜 format들이 지원된다는지 파악하기 어려워 공식 문서에서 찾아봤습니다.

2. 공식문서 읽어보기

  • Date -MDN의 일부를 발췌한 내용입니다.
    • 자바스크립트에서는 ISO 8601 날짜 확장 형식을 기반으로 한 특정 형식만을 정식으로 지원
      • YYYY-MM-DDTHH:mm:ss.sssZ이 공식적인 형식임
    • 브라우저별 지원하는 날짜 형식이 상이함
      • 대부분의 브로아주에서 RFC 2822 형식의 날짜 포멧을 지원하지만, 지원하지 않는 브라우저가 존재하지 않을 수 있으므로 크로스 브라우징 테스트가 필요
    • 타임존 없이 날짜만 있는 경우 UTC 시간으로 해석되고, 타임존 없이 날짜-시간만 있는 경우 로컬시간으로 해석됨
      • ISO 8601 표준에 따르면 날짜만 있는 경우에도 로컬 시간으로 해석되어야 함
      • 표준과 맞지 않는 문제가 개선되어야 하지만 그 동안 개발해온 웹 사이트들이 문제가 생길 수 있기 떄문에 현실적으로 자바스크립트를 수정하는게 불가능함
        (Fixing JavaScript Date – Web Compatibility and Reality)

참고로 MDN 한글 문서에는 많은 내용이 누락되어 있어 영어 버전의 MDN을 읽어보시는 것을 추천드립니다.

해결하기

1. yyyy/MM/dd 형태로 바꾸기

  • iOS/Safari와 Chrome에서 정상 출력되지만, 모든 브라우저에서 호환되는지 확인 필요함
    const convertDate = '2011-04-12 10:00:00'.replace(/-/g, "/");
    const date = new Date(convertDate);

2. 날짜-시간 구분자 T 넣기

  • 모든 브라우저에서 호환되는 방법

    const convertDate = '2011-04-12 10:00:00'.replace(" ", "T");
    const date = new Date(convertDate);
  • 좀더 나아가 정규 표현식으로 패턴 매칭해보기

    function convertStringToDate(originDate: string){
      const regex = new RegExp(/(\d{4}-\d{2}-\d{2})\s(\d{2}:\d{2}:\d{2})/)
    
      if (regex.test(originDate)) {
        const convertDate = originDate.replace(" ", "T");
        return new Date(convertDate);      
      } esle {
        return new Date(originDate)
      }
    }
    

3. 라이브러리 사용

  • moment.js, data-fns, dayjs 등과 같은 라이브러 사용
  • 3가지 라이브러리 간단비교
    • moment: 가장 많이 사용되는 라이브러리. 가장 무겁고 트리쉐이킹도 지원하지 않음.
    • dayjs: 미치게 가벼운 라이브러리.
    • date-fns: dayjs보다는 무겁지만, 트리쉐이킹 지원됨. Functional 형태로 사용할 수 있음
  • 만약, 사용하는 기능이 많지 않다면 date-fns의 번들링 후 크기가 dayjs 보다 더 적을 수 있음

회고

처음 해당 이슈를 접하고 구글링을 통해 얻은 해답인 "yyyy/MM/dd" 형태로 변환하는 것을 적용하였습니다. 하지만, 이 블로그를 작성하면서 공식 문서를 읽어보고 생각해보니 잠재적으로 이슈가 있을만한 해결책이였다는 생각이 들었습니다. 해결책을 찾아나가는 과정에서 공식 문서를 읽어보는 것은 필수라는 것을 깨달았습니다.
그리고, 생각보다 날짜 라이브러리들의 번들 크기가 크지 않아 잘 만들어진 날짜 라이브러리 사용하는 것도 나쁘지 않은 선택이라는 생각이 들어습니다.

profile
프론트엔드 개발자

0개의 댓글