날짜 및 시간
GitLab v19.1디자인 가이드라인인 Pajamas에서는 다음과 같이 안내합니다: 사용자의 위치에 따라 로컬라이즈된 날짜/시간 형식을 표시하거나, ISO 8601 표준을 따르는 비로컬라이즈 형식을 사용할 수 있습니다. UI에 날짜를 포맷할 때는 localeDateFormat 싱글톤을 사용하세요.
포맷 지정#
디자인 가이드라인인 Pajamas에서는 다음과 같이 안내합니다:
사용자의 위치에 따라 로컬라이즈된 날짜/시간 형식을 표시하거나, ISO 8601 표준을 따르는 비로컬라이즈 형식을 사용할 수 있습니다.
UI에 날짜를 포맷할 때는 localeDateFormat 싱글톤을 사용하세요. 이 싱글톤은 사용자의 로케일 설정에 따라 날짜를 로컬라이즈합니다.
로케일을 가져오는 로직은 app/assets/javascripts/locale/index.js의 getPreferredLocales 함수에 있습니다.
날짜를 로컬라이즈 방식으로 포맷하지 않는 formatDate 및 dateFormat 날짜 유틸리티 함수는 사용하지 마세요.
// good
const formattedDate = localeDateFormat.asDate.format(date);
// bad
const formattedDate = formatDate(date);
const formattedDate = dateFormat(date);
주의 사항#
날짜를 다룰 때 예상치 못한 동작이 발생할 수 있습니다.
Date-only 버그#
Date 생성자에 yyyy-mm-dd 형식의 문자열을 전달할 때 버그가 발생합니다.
MDN Date 페이지에 따르면:
타임존 오프셋이 없을 경우, date-only 형식은 UTC 시간으로, date-time 형식은 로컬 시간으로 해석됩니다. 이는 ISO 8601과 일치하지 않았지만 웹 호환성 때문에 변경할 수 없었던 오래된 스펙 오류 때문입니다.
new Date('2020-02-02')를 실행하면 로컬 시간으로 Sun Feb 02 2020 00:00:00와 같은 날짜가 생성될 것으로 예상할 수 있습니다.
그러나 이 date-only 버그로 인해 new Date('2020-02-02')는 UTC로 해석됩니다.
예를 들어, 타임존이 UTC-8이라면 UTC 기준 날짜 객체(Sun Feb 02 2020 00:00:00 UTC)가 생성된 후 로컬 UTC-8 타임존(Sat Feb 01 2020 16:00:00 GMT-0800 (Pacific Standard Time))으로 변환됩니다.
UTC보다 느린 타임존에서는 파싱된 날짜가 하루 뒤처지게 되어 예상치 못한 버그가 발생할 수 있습니다.
date-only 문자열을 동일한 날짜를 유지하면서 변환하는 몇 가지 방법이 있습니다:
-
이 버그를 피하기 위해 특별히 만들어진
newDate함수를 사용하세요. 이 함수는Date생성자를 감싸는 래퍼입니다. -
문자열에 시간 구성 요소를 포함하세요.
-
(year, month, day)생성자를 사용하세요.
이상적으로는 Date 객체를 생성할 때 newDate 함수를 사용하여 이 버그를 걱정하지 않아도 됩니다.
// good
// use the newDate function
import { newDate } from '~/lib/utils/datetime_utility';
newDate('2020-02-02') // Sun Feb 02 2020 00:00:00 GMT-0800 (Pacific Standard Time)
// add a time component
new Date('2020-02-02T00:00') // Sun Feb 02 2020 00:00:00 GMT-0800 (Pacific Standard Time)
// use the (year, month, day) constructor - month is 0-indexed (another source of possible bugs, yay!)
new Date(2020, 1, 2) // Sun Feb 02 2020 00:00:00 GMT-0800 (Pacific Standard Time)
// bad
// date-only string
new Date('2020-02-02') // Sat Feb 01 2020 16:00:00 GMT-0800 (Pacific Standard Time)
// using the static parse method with a date-only string
new Date(Date.parse('2020-02-02')) // Sat Feb 01 2020 16:00:00 GMT-0800 (Pacific Standard Time)
// using the static UTC method
new Date(Date.UTC(2020, 1, 2)) // Sat Feb 01 2020 16:00:00 GMT-0800 (Pacific Standard Time)
Date picker#
GlDatepicker 컴포넌트는 로컬 시간 자정의 Date 객체를 반환합니다.
이로 인해 UTC보다 앞선 타임존에서 GraphQL 뮤테이션과 같은 경우에 문제가 발생할 수 있습니다.
예를 들어, UTC+8에서:
-
date picker에서
2020-02-02를 선택합니다. -
반환된
Date객체는 로컬 시간 기준Sun Feb 02 2020 00:00:00 GMT+0800 (China Standard Time)입니다. -
GraphQL로 전송되면 UTC 문자열
2020-02-01T16:00:00.000Z로 변환되어 하루 뒤처집니다.
날짜를 보존하려면 toISODateFormat을 사용하여 Date 객체를 date-only 문자열로 변환하세요:
const dateString = toISODateFormat(dateObject); // "2020-02-02"
테스트#
수동 테스트#
머지 리퀘스트를 검토할 때와 같이 날짜에 대한 수동 테스트를 수행할 때는 잠재적인 버그를 찾기 위해 UTC-8, UTC, UTC+8과 같이 UTC보다 느린 타임존과 빠른 타임존 모두에서 테스트하세요.
macOS에서 타임존을 변경하려면:
-
시스템 설정 > 일반 > 날짜 및 시간으로 이동하세요.
-
현재 위치를 사용하여 자동으로 시간대 설정 체크박스를 해제하세요.
-
가장 가까운 도시를 Sacramento, London, Beijing과 같이 다른 타임존의 도시로 변경하세요.
Jest#
Jest 테스트는 결정론적 실행을 위해 2020-07-06의 모의 날짜로 실행되며, useFakeDate 함수를 사용하여 재정의할 수 있습니다.
이에 대한 로직은 spec/frontend/__helpers__/fake_date/fake_date.js에 있습니다.