사전 윤초
개념

윤초

gabury1

윤초는 세상이 함께 쓰는 시각에 1초를 넣거나 빼는 일입니다. 지구가 도는 속도는 조금씩 흔들립니다. 그래서 원자시계로 세는 시각과 지구 자전으로 재는 시각이 서서히 벌어집니다. 벌어진 만큼을 1초 단위로 메웁니다.

상세

벽시계가 아무리 정확해도 해가 뜨는 시각과는 조금씩 어긋납니다. 눈에 띄게 어긋나면 바늘을 돌려 맞춥니다. 윤초도 그 맞춤입니다.

성격이 다른 시간 척도가 나란히 굴러갑니다. 세계시(UT, Universal Time)는 지구 자전에 기반한 시간 척도를 통틀어 부르는 이름입니다. 그중 UT1 은 자전축에 대한 지구의 작은 움직임, 곧 극운동의 영향을 보정한 것입니다. 지구가 하루 자전에서 갖는 각위치에 곧바로 대응합니다. 국제원자시(TAI, International Atomic Time)는 협력 기관들이 대는 시계 자료를 바탕으로 만드는 원자시의 국제 기준 척도입니다. 1958년 1월 1일을 기점으로 끊김 없이 흐르는 연속 척도입니다.

협정 세계시(UTC, Coordinated Universal Time)는 이 둘 사이에 놓입니다. 진행 속도는 TAI 와 정확히 같습니다. 대신 TAI 와 정수 초만큼 차이가 납니다. ITU-R(International Telecommunication Union Radiocommunication Sector, 국제전기통신연합 무선통신부문) 권고 TF.460-6 은 UTC 척도가 UT1 과 대략 맞도록 초를 삽입하거나 삭제하는 방식으로 조정된다고 적습니다. 넣는 쪽이 양의 윤초이고 빼는 쪽이 음의 윤초입니다.

이름 무엇인가 허용 오차
UT1 지구 자전의 각위치에 대응하는 시간 척도 —
TAI 1958년 1월 1일이 기점인 연속 원자 척도 —
UTC TAI 와 진행 속도가 같고 정수 초만큼 다른 척도 UT1 에서 벗어나는 정도가 ±0.9초를 넘지 않아야 합니다
DUT1 시보와 함께 뿌리는 예보된 UT1 - UTC 차 크기가 0.8초를 넘지 않아야 합니다. UTC 에 DUT1 을 더한 값의 편차는 ±0.1초를 넘지 않아야 합니다
DTAI 시보와 함께 뿌리는 TAI - UTC 차 —

윤초를 넣는 자리도 권고가 다룹니다. 권고는 윤초를 UTC 어느 달의 마지막 초로 두도록 권합니다. 12월 말과 6월 말이 1순위이고 3월 말과 9월 말이 2순위입니다. 실제로 1972년에 윤초가 도입된 뒤로 쓰인 날짜는 6월과 12월뿐입니다.

초 마커가 지나가는 순서
양의 윤초 23h 59m 60s 로 시작해 다음 달 1일 0h 0m 0s 에 끝납니다
음의 윤초 23h 59m 58s 다음 1초 뒤가 곧바로 다음 달 1일 0h 0m 0s 입니다

넣을지 말지를 정하고 알리는 일은 IERS(International Earth Rotation and Reference Systems Service, 국제 지구자전·기준계 사업)의 몫입니다. 권고는 그 공고를 최소 여덟 주 전에 내라고 적습니다. IERS 는 UT1 - UTC 가 0.9초에 가까워질 것으로 예보되면 윤초를 적용합니다.

flowchart TD
    A["지구 자전 관측"] --> B["UT1 - UTC 예보"]
    B -->|0.9초에 가까워진다| C["IERS 가 삽입을 결정"]
    B -->|여유가 있다| D["없음을 확인"]
    C --> E["최소 여덟 주 전 공고"]
    E --> F["6월 말 또는 12월 말에 1초"]

배경

1967년 제13차 국제도량형총회(CGPM)가 초를 새로 정의했습니다. ITU-R 권고는 표준 주파수와 시보를 그 정의를 따르는 초에 맞춰 내보내야 한다고 적습니다. 이제 초의 길이는 지구 자전과 무관하게 고정됐습니다. 그런데 지구 자전 속도에는 여러 불규칙한 변동이 있습니다. 그래서 원자시계로 세는 시각과 자전으로 재는 시각이 계속 벌어집니다. IERS 는 벌어지는 이유를 둘로 나눕니다. 하나는 초의 값을 1820년 평균 태양일의 1/86400 로 고른 처음의 선택입니다. 다른 하나는 지구 자전이 전반적으로 더뎌지는 것입니다.

두 척도를 그대로 두면 시보가 하늘과 어긋납니다. 자전 속도의 불규칙한 변동이 잇따라 확인되면서 1972년에 기준 시간 척도가 UT1 에서 UTC 로 바뀌었습니다. 두 척도의 차인 UT1 - UTC 를 0.9초 안에 붙들어 두려고, 필요할 때마다 UTC 에 1초를 적용하기로 했습니다. 그 1초에 붙은 이름이 윤초입니다. IERS 는 2000년까지는 평균 1~2년에 한 번 윤초를 더해야 했고 그 뒤로는 평균 3~4년 간격이라고 적습니다. 지구 자전 속도가 빨라진 것을 그 이유로 듭니다.

0.9초라는 최대 허용값은 손질이 예고돼 있습니다. 2022년 제27차 국제도량형총회의 결의 4 는 UT1 - UTC 차의 최대 허용값을 2035년까지, 또는 그 전에 늘리기로 결정했습니다. 결의문은 두 가지를 근거로 듭니다. 윤초가 만드는 불연속이 위성항법(GNSS, Global Navigation Satellite System)·통신·전력 전송을 포함한 핵심 디지털 기반시설에 심각한 오작동을 일으킬 위험이 있다는 것입니다. 그리고 디지털 망과 위성항법 사업자들이 윤초를 넣는 서로 다른 방법을 만들어 써 왔고, 그 방법들이 합의된 어떤 표준도 따르지 않는다는 것입니다. 결의문은 이어 CIPM(International Committee for Weights and Measures, 국제도량형위원회)이 ITU 등과 협의해 새 최대값을 제안하고, 2035년까지 그것을 시행할 계획을 마련하고, 2026년 제28차 총회에서 합의할 결의안을 작성하도록 요청했습니다. 새 최대값은 UTC 의 연속성을 최소 한 세기 보장하는 값이어야 한다고 적습니다. 음의 윤초를 두고는 말이 갈립니다. IERS 는 이론상 음의 윤초가 가능하지만 지금까지의 윤초는 전부 양의 윤초였고, 지구 자전에 대해 아는 바로는 음의 윤초를 쓸 일이 생길 것 같지 않다고 적습니다. 결의 4 는 반대로 최근 자전 속도 관측이 첫 음의 윤초가 필요해질 가능성을 가리킨다고 적고, 그 삽입은 예견된 적도 시험된 적도 없다고 덧붙입니다.

예시

IERS Bulletin C

윤초는 Bulletin C 라는 공고문으로 세상에 나옵니다. 2016년 7월 6일 파리에서 나온 Bulletin C 52 의 본문입니다.

A positive leap second will be introduced at the end of December 2016.
The sequence of dates of the UTC second markers will be:

                        2016 December 31, 23h 59m 59s
                        2016 December 31, 23h 59m 60s
                        2017 January   1,  0h  0m  0s

같은 공고문이 UTC 와 TAI 의 차도 적습니다. 2015년 7월 1일 0h UTC 부터 2017년 1월 1일 0h UTC 까지는 UTC-TAI = -36s 이고, 2017년 1월 1일 0h UTC 부터는 UTC-TAI = -37s 입니다. Bulletin C 는 여섯 달마다 나갑니다. UTC 의 시각 계단을 공고하거나, 다음 가능한 날짜에 계단이 없음을 확인합니다. 2026년 7월 6일에 나온 Bulletin C 72 가 뒤쪽입니다. NO leap second will be introduced at the end of December 2026 이라 적고, UTC-TAI 는 2017년 1월 1일 0h UTC 부터 별도 공지가 있을 때까지 -37s 로 남는다고 적습니다.

NTP 의 Leap Indicator

NTP(Network Time Protocol, 네트워크 시간 프로토콜) 4판을 규정한 RFC 5905 는 패킷 머리에 Leap Indicator 라는 2비트 정수를 둡니다. 이번 달 마지막 분에 삽입되거나 삭제될 윤초를 미리 경고하는 자리입니다.

| Value | Meaning                                |
| 0     | no warning                             |
| 1     | last minute of the day has 61 seconds  |
| 2     | last minute of the day has 59 seconds  |
| 3     | unknown (clock unsynchronized)         |

값 1 이 양의 윤초, 값 2 가 음의 윤초입니다. 시각을 받는 쪽은 이 두 비트만 보고 그날 마지막 분의 길이를 압니다.

TZif 의 leap-second record

시간대 정보 포맷 TZif(Time Zone Information Format)를 규정한 RFC 8536 은 파일 안에 leap-second record 를 둡니다. 8옥텟 또는 12옥텟짜리 레코드가 발생 시각 순으로 엄격히 오름차순 정렬돼 들어갑니다.

Version 1 Data Block:
+---------------+---------------+
|  occur (4)    |  corr (4)     |
+---------------+---------------+

version 2+ Data Block:
+---------------+---------------+---------------+
|  occur (8)                    |  corr (4)     |
+---------------+---------------+---------------+

occur 는 윤초 보정이 일어나는 시각이고, corr 는 그 시각부터 적용되는 보정값입니다. 첫 레코드의 corr 는 1 또는 -1 이어야 합니다. 이웃한 레코드의 corr 는 정확히 1 만큼 달라야 합니다. 뒤 레코드의 occur 는 앞 값보다 최소 2419199 커야 합니다. 28일치 초에서 음의 윤초 1초를 뺀 값입니다.

POSIX 의 Seconds Since the Epoch

POSIX(Portable Operating System Interface)는 유닉스 시간을 정의하면서 윤초를 아예 세지 않습니다.

As represented in seconds since the Epoch, each and every day shall be
accounted for by exactly 86400 seconds.

The relationship between the actual time of day and the current value
for seconds since the Epoch is unspecified.

하루는 무조건 86400초로 셈합니다. 그리고 그 값과 실제 하루 중 시각의 관계는 명세가 정하지 않는다고 못 박습니다. 그 값을 실제 시각에 맞추려고 어떻게 바꿀지는 구현이 정할 몫으로 남습니다.

실패

윤초가 깨뜨리는 것은 1초의 크기가 아닙니다. 시각이 한 방향으로만 흐른다는 가정입니다.

리눅스 커널의 윤초 hrtimer 라이브락

리눅스 커널의 ntp 서브시스템은 한동안 윤초 조정을 촉발하는 데 hrtimer 를 썼습니다. 그 구현에 라이브락이 생길 수 있었습니다. 깨지는 조건은 두 CPU 가 잠금 둘을 엇갈려 잡는 것입니다. 한쪽에서 do_adjtimex() 가 ntp_lock 을 잡은 채 윤초 타이머를 재무장합니다. 그 경로가 ktime_get() 을 지나며 xtime_lock 의 시퀀스를 읽기 시작합니다. 같은 때 다른 CPU 의 타이머 인터럽트가 xtime_lock 을 쓰기 잠금으로 잡고 update_wall_time() 을 돌립니다. 그 안의 ntp_tick_length() 가 ntp_lock 을 기다립니다.

sequenceDiagram
    participant CPU0
    participant ntp_lock
    participant xtime_lock
    participant CPU1
    CPU0->>ntp_lock: do_adjtimex 가 잡는다
    CPU0->>xtime_lock: 타이머 재무장 중 시퀀스를 읽는다
    CPU1->>xtime_lock: 타이머 인터럽트가 쓰기 잠금
    CPU1->>ntp_lock: ntp_tick_length 가 기다린다
    Note over CPU0,CPU1: 서로가 서로를 기다린다

고친 방법은 hrtimer 로 윤초를 주입하지 않는 쪽으로 되돌리고 윤초 처리를 second_overflow() 함수에서 하는 것이었습니다. 대신 내주는 것이 있습니다. 고해상도 타이머를 지원하는 시스템에서 윤초 처리가 윤초 그 순간이 아니라 뒤따르는 HZ 틱 경계에서 일어납니다. 커밋은 그 지연을 HZ 값에 따라 약 1~10ms 로 적습니다. 이전 방식에서는 그보다 이를 수도 있었습니다. 커밋 작성자의 x86_64 lapic 테스트에서는 약 34us 였습니다.

Cloudflare RRDNS 의 패닉

2017년 1월 1일 UTC 자정, Cloudflare 의 자체 소프트웨어 RRDNS 안에서 값 하나가 음수가 됐습니다. 아무리 작아져도 0 에 머물러야 하는 값이었습니다. 조금 뒤 이 음수가 RRDNS 를 패닉에 빠뜨렸습니다.

깨지는 조건은 이렇습니다. RRDNS 는 내부 DNS(Domain Name System, 도메인 이름 체계) 리졸버들이 얼마나 잘 응답하는지를 추적해 가중 선택을 합니다. 윤초 동안 일부 조회가 자료구조에 음수를 기록했습니다. 그 음수가 나중에 가중 선택 코드에 들어가 패닉을 냈습니다. 음수는 윤초와 평활화가 겹쳐 생겼습니다. 패닉 자체는 Go 언어의 recover 로 잡혔습니다. 그러고도 결국 나타난 결과는 일부 조회의 실패였습니다. 영향 범위는 CNAME(Canonical Name) DNS 레코드를 쓰는 고객으로 한정됐고, 102개 데이터센터 가운데 적은 수의 장비에만 나타났습니다. 정점에서 Cloudflare 로 오는 DNS 질의의 약 0.2%, 전체 HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜) 요청의 1% 미만이 오류를 만났습니다.

Cloudflare 는 뿌리 원인을 코드가 아니라 믿음으로 적었습니다. 시간은 거꾸로 갈 수 없다는 믿음입니다. RRDNS 는 Go 로 쓰였고 시각을 Go 의 time.Now() 로 얻습니다. 이 함수는 단조성을 보장하지 않습니다. Cloudflare 는 당시 Go 가 단조 시계를 제공하지 않는다고 적었습니다.

윤초 문지르기

윤초를 시계 계단으로 그대로 적용하면 위 두 가지 같은 자리가 생깁니다. 그래서 계단을 아예 없애는 쪽을 고르기도 합니다. Google 은 2008년부터 윤초를 클럭 스텝으로 적용하지 않고 윤초 앞뒤 시간에 걸쳐 그 1초를 문질러 왔습니다. 이 문지르기는 모든 Google 서비스에 적용됩니다.

Google 이 권하는 표준 방식은 정오부터 정오까지 24시간 선형 스미어입니다. 왜 그 모양인지를 문서가 값으로 적습니다. 시간이 길면 주파수 변화가 작게 유지되고, 이 스미어의 변화량은 약 11.6ppm(parts per million, 백만분율)입니다. 이 값은 대부분 기계의 수정 발진기가 갖는 제조 오차와 열 오차 안에 들고 NTP 의 최대 슬루율 500ppm 보다 한참 아래입니다. 스미어를 윤초에서 시작하거나 끝내지 않고 윤초를 한가운데 두면 최대 오프셋이 가장 작아집니다. 코사인 스미어와 견주면 선형 스미어는 계산이 단순하고 최대 주파수 변화가 작습니다. Google 은 전에 20시간 스미어를 쓰다가 더 널리 쓰이는 정오-정오 구간에 맞춰 바꿨습니다. AWS(Amazon Web Services)도 이 스미어를 씁니다. Amazon Time Sync Service 는 UTC 에 더해지는 윤초를 자동으로 문지릅니다.

문지르기에도 내주는 것이 있습니다. 2022년 결의 4 는 사업자들이 만들어 쓰는 이런 방법들이 합의된 어떤 표준도 따르지 않는다고 적습니다. 스미어를 쓰는 기계와 계단을 쓰는 기계는 같은 윤초를 서로 다른 방식으로 넘깁니다.

관련 항목

이것을 계산하는 데 쓰이는 시간 척도

협정 세계시 · 국제원자시 · UT1 · DUT1 · DTAI · GPS 시간

이것을 정하고 알리는 기구

IERS · BIPM · CGPM · ITU-R · ITU · CIPM

이 결정을 담는 공고문

Bulletin C · leap-seconds.list · TF.460-6(Standard-frequency and time-signal emissions, 표준주파수·시보 권고)

이것을 다루는 동기화 기술

NTP · PTP · Leap Indicator · RFC 5905 · TZif · RFC 8536(The Time Zone Information Format, TZif 규격) · 시간대 데이터베이스 · 시간 동기화

프로그램이 이 초를 처리하는 지점

POSIX · 유닉스 시간 · ISO 8601 · clock_gettime · adjtimex · 2038 문제 · 단조 시계

이것에서 자주 나는 오류·장애

라이브락 · 클럭 스텝 · 시계 되돌림

이 장애에 관여하는 참여자

Cloudflare · RRDNS · Go · 리눅스

이것을 문질러 흡수하는 방식과 그 구현체

윤초 문지르기 · Google · AWS · Amazon Time Sync Service

다른 이름: leap second