정수 시간이 아닌 UTC 차이들
· 약 3분
세계 인구의 약 오분의 일이 UTC로부터 정수 시간이 아닌 차이 위에서 살아갑니다. 그렇지 않다고 여긴 소프트웨어는 그들에게 조금 틀리는 것이 아니라 30분이나 45분 틀리고, 그편이 더 나쁩니다.
한 시간 간격의 스물네 시간대라는 머릿속 그림은 값비싸게 틀립니다. 십억을 훌쩍 넘는 사람들에 대해 당당하게 30분이나 45분 어긋난 코드를 낳기 때문입니다. 한 시간 통째로 틀리면 적어도 오류처럼 보입니다. 45분 틀리면 오타처럼 보이고, 그대로 출시됩니다.
전체 목록
:30 차이
| 차이 | 어디 |
|---|---|
| UTC-09:30 | 마르키즈 제도 |
| UTC-03:30 | 뉴펀들랜드 래브라도주 |
| UTC+03:30 | 이란 |
| UTC+04:30 | 아프가니스탄 |
| UTC+05:30 | 인도, 스리랑카 |
| UTC+06:30 | 미얀마, 코코스 제도 |
| UTC+09:30 | 오스트레일리아 중부 — 노던 준주, 사우스오스트레일리아주 |
| UTC+10:30 | 로드하우섬(표준시) |
:45 차이
| 차이 | 어디 |
|---|---|
| UTC+05:45 | 네팔 |
| UTC+08:45 | 웨스턴오스트레일리아 남동부(유클라, 비공식) |
| UTC+12:45 | 채텀 제도(표준시) |
인도만 해도 14억 명입니다. 이란, 아프가니스탄, 미얀마, 스리랑카, 네팔을 더하면 오스트레일리아나 캐나다를 세기도 전에 지구 인구의 오분의 일을 넘습니다.
또 다른 종류의 유별난 차이
정수 시간이 아닌 차이는 널리 알려진 별종입니다. 그만큼 중요한 것이 둘 더 있습니다.
폭은 24시간이 아니라 26시간입니다. 키리바시의 키리티마티섬은 UTC+14, 베이커섬과 하울랜드섬은 UTC-12입니다. 26시간의 폭이고, 곧 지구 어딘가에서 서로 다른 세 개의 달력 날짜가 동시에 쓰이는 순간이 있다는 뜻입니다. 이틀짜리 창이면 모든 시간대를 덮는다고 가정한 코드는 하루에 두 번 틀립니다.
서머타임이 언제나 한 시간인 것도 아닙니다. 상주 인구가 약 380명인 작은 오스트레일리아 섬 로드하우섬은 30분을 옮깁니다. 겨울에는 UTC+10:30, 여름에는 UTC+11:00입니다. 그렇게 하는 곳은 지구에서 여기뿐이며, 날짜 라이브러리에 대한 가장 좋은 시험 사례입니다. 60분 이동을 코드에 박아 둔 구현은 그곳에서만 틀리고 다른 어디서도 틀리지 않으니, 여러분이 쓰는 다른 모든 시험을 통과합니다.
무엇이 깨지는가
가장 가까운 시로 반올림하기. 가장 흔한 실패입니다. 차이를 정수 시간으로 계산하는 코드는 인도를 소리 없이 +5로 잘라 냅니다. 그 나라의 모든 사용자에게 30분 틀린 값입니다.
차이를 정수로 저장하기. 시간 수로 선언된 스키마 열은 카트만두를 표현하지 못합니다. 보통은 데이터가 들어간 뒤에 발견됩니다.
시 단위 열 위에 세운 격자 화면. 하루를 스물네 개의 같은 칸으로 펼치고 각 시간대의 현지 시각이 칸 경계에 맞아떨어진다고 가정한 달력이나 일정표는 삼십 분대와 사십오 분대를 잘못 놓습니다. 이 사이트 회의 조율기의 띠는 현지 시각이 아니라 순간을 열로 씁니다. 그래서 +05:45 줄은 UTC 줄이 04:00을 보이는 열에서 09:45를 보입니다. 더 말끔한 거짓 대신 그것이 사실이기 때문입니다.
삼십 분짜리 서머타임 변경을 가로지르는 기간 계산. 서머타임 전환이 정확히 3,600,000밀리초라고 가정하면 로드하우섬에서, 그리고 오직 거기서만 답이 틀립니다.
제대로 하는 법
고치는 방법은 거의 모든 시간대 결함을 고치는 방법과 같습니다. 차이를 직접 계산하지 마십시오. 플랫폼에 물으십시오.
현대의 실행 환경은 모두 IANA 데이터베이스를 품고 있으며, 어떤 시간대의 어떤 순간의 차이를 분 단위로 정확히 알려 줍니다. 카트만두와 로드하우도 포함해서입니다. 자바스크립트에서는 timeZoneName: 'longOffset'을 준 Intl.DateTimeFormat이거나, 그 시간대의 벽시계 읽기를 UTC와 견주는 방법입니다. 이 사이트의 계산은 뒤쪽을 씁니다. 1900년 이전 자료에 남은, 분보다 잘게 쪼개진 지방 평균시 차이에서도 정확하기 때문입니다.
그런 다음 세 가지 규칙을 지키십시오.
- 차이는 분입니다. 결코 시가 아닙니다. 변수 이름이
offsetHours라면 그 자체로 이미 결함입니다. - 카트만두와 로드하우로 시험하십시오. 다른 모든 것이 그냥 지나치게 두는 두 가정을 이 둘이 무너뜨립니다.
- 시간대를 반올림하지 마십시오. 화면이 어림값이어야 한다면 그렇다고 말하십시오. 배치를 쉽게 하려고 사용자의 시계를 소리 없이 30분 옮기지 마십시오.
풀어 본 예 — 45분이 격자에 하는 일
하루를 스물네 열로 펼치고 한 열을 한 시간으로 삼아 참가자들의 근무 시간을 칠하는 회의 조율기를 생각해 보십시오. 순진한 구현은 기준 줄을 시간대 차이만큼(시 단위로) 옮겨 각 줄을 계산합니다.
런던 대 뉴욕이면 들어맞습니다. 뉴욕 줄은 런던 줄을 오른쪽으로 다섯 칸 옮긴 것입니다. 런던 대 카트만두면 들어맞지 않습니다. 카트만두는 5시간 45분 앞서고, 이는 5.75칸입니다. 칸의 사분의 삼 같은 것은 없습니다. 구현은 반올림하고 — 대개 6으로 — 이제 그 줄의 모든 읽기가 15분 이릅니다.
오차는 검토를 살아남을 만큼 작고 문제가 될 만큼 큽니다. 격자가 카트만두에 대해 09:00이라고 알리는 09:00 회의는 그곳에서 실은 08:45이고, 들어오는 사람은 자기 하루에 십오 분 늦습니다.
고치는 길은 열을 시로 다루기를 그만두는 것입니다. 각 열을 _순간_으로 만들고, 그 순간에 각 시간대의 현지 벽시계가 무엇을 가리키는지 플랫폼에 물으십시오. 그러면 +05:45 줄은 UTC 줄이 04:00을 보이는 자리에서 09:45를 보입니다. 눈에 띄게 격자와 어긋나 있고, 그것이 정직한 그림입니다. 이 사이트의 회의 조율기가 바로 그렇게 하며, 카트만두 줄의 들쭉날쭉한 가장자리는 흠이 아니라 장점입니다.
역사 속 차이는 더 기묘합니다
표준화 이전의 차이는 지방 평균 태양시였고 초까지 정확했습니다. IANA 데이터베이스가 그것을 기록합니다.
네덜란드는 1909년부터 1937년까지 UTC+00:19:32.13이었습니다. 라이베리아는 1972년까지 UTC-00:44:30이었습니다. 실행 환경에 1920년 어느 날의 Europe/Amsterdam 차이를 물으면 초까지 포함한 정확한 값을 돌려줍니다.
그래서 이 사이트 아래의 차이 함수는 초로 계산하고, 분으로의 반올림은 표시 계층에서만 합니다. 분으로 저장하는 구현은 네덜란드 역사에서 32초를 소리 없이 잃습니다. 아무도 알아채지 못하겠지만, 그래도 틀린 값입니다.