업로드 없음, 100% 로컬, 계정 없음

아티클

ISO 8601 기간: P1DT2H는 무엇을 의미하는가

YouTube API 응답은 어떤 영상의 길이를 PT4M13S로 표시한다. 캘린더 초대장에는 P15DT5H0M20S라는 값이 담겨 있다. 어느 디렉터리 서버는 계정에 20260424174227.0Z라는 타임스탬프를 붙이는데, 관련 있어 보이지만 사실은 완전히 다른 것이다. 이 압축된 문자열들에는 알아둘 만한 규칙이 있는데, 잘못 읽으면 분이 개월로 뒤바뀌기 때문이다. 이 글에서는 ISO 8601 기간 포맷을 살펴본다: 각 글자가 무엇을 의미하는지, 이 포맷이 어디에 등장하는지, 그리고 가장 큰 함정, 즉 이렇게 쓴 기간이 항상 고정된 시간의 양은 아니라는 점이다.

P, T, 그리고 각 글자의 의미

ISO 8601 기간은 P(period)로 시작한다. 그다음에 날짜 구성 요소가 오는데, 각각 숫자 뒤에 단위 글자가 붙는다: Y는 년, M은 월, W는 주, D는 일이다. T는 날짜 부분과 시간 부분을 구분한다: H는 시, M은 분, S는 초다. 모든 구성 요소는 선택 사항이며 필요한 것만 쓰면 된다. PT15M은 15분, P1DT2H는 1일과 2시간, P3W는 3주다. T는 장식이 아니다: M은 T 앞에서는 월, 뒤에서는 분을 의미하므로 P1M은 한 달이고 PT1M은 1분이다. 마지막에 오는 구성 요소에는 PT0.5S처럼 소수점 이하의 값을 붙일 수 있다(0.5초). 그리고 단위는 자동으로 올림되지 않는다: PT90M은 한 시간 반을 나타내는 완전히 유효한 표기다.

ISO 8601 기간 P3Y6M4DT12H30M5S의 구조: P는 기간의 시작, Y M D는 날짜 단위, T는 시간 부분으로의 전환, H M S는 시간 단위

실제로 이 포맷을 마주치는 곳

이 표기법은 생각보다 어디에나 있다. YouTube Data API는 모든 영상 길이를 ISO 8601 기간(PT4M13S)으로 보고한다. HTML은 time 요소의 datetime 속성에서 기간 표기를 받아들인다. 캘린더 초대장도 이를 사용한다: iCalendar 표준(RFC 5545)은 일정 길이를 PT1H0M0S처럼 표기하지만, 문법에서 년과 월은 제외한다. XML Schema의 xs:duration은 전체 형식을 다루며, 음의 기간을 위한 앞쪽 마이너스 기호까지 허용한다. 표준 라이브러리는 이를 직접 파싱한다: java.time은 Period.parse와 Duration.parse로 P와 T 문자열을 읽어 들이며, 다른 많은 언어에도 같은 구분이 존재한다. 기계가 읽을 수 있는 일정, 피드, API를 만든다면 이 포맷이 '얼마나 오래'를 나타내는 공통 언어다.

P1M이 고정된 초 수가 아닌 이유

PT15M은 항상 900초다. P1M은 그렇지 않다: 한 달은 시작 시점에 따라 28일, 29일, 30일, 31일 중 하나이므로 P1M은 날짜에 고정되어야 비로소 구체적인 값이 된다. P1D조차 24시간이 보장되지 않는다. 유럽연합에서는 2026년 3월 29일 일요일에 시계를 앞당기므로 그날의 달력상 하루는 23시간이 되며, 같은 토요일 저녁에 P1D(달력상의 하루)를 더하는 것과 PT24H(정확히 24시간)를 더하는 것은 서로 다른 시점에 도달한다. 그래서 java.time에는 달력 단위를 위한 Period와 정확한 초를 위한 Duration이라는 두 가지 타입이 있으며, 날짜 라이브러리는 기간을 변환하기 전에 기준 날짜를 요구한다. Y, M, W, D 구성 요소는 달력 연산으로, H, M, S만 고정된 시간량으로 다뤄야 한다.

기간이 아니다: 20260424174227.0Z

20260424174227.0Z 같은 문자열은 같은 계열처럼 보일 수 있지만, 이것은 기간이 아니라 타임스탬프이며 ISO 8601도 아니다. 이것은 ASN.1에서 비롯된 형식인 GeneralizedTime으로, LDAP 디렉터리와 X.509 인증서에서 쓰는 표기법이다. 고정 폭 필드로 읽으면 된다: 연도 2026, 월 04, 일 24, 그다음 17:42:27, 선택적 소수부(.0), 그리고 UTC를 나타내는 Z다. 이것은 Active Directory의 whenCreated, whenChanged 속성이나 LDAP 내보내기, 인증서 안에서 만나게 된다. RFC 5280은 2050년 이후의 유효 기간에 GeneralizedTime을 요구한다. ISO 8601의 압축된 형식과 구별하는 결정적 단서는 T가 없다는 점이다: ISO라면 같은 시각을 20260424T174227Z로 표기했을 것이다.

GeneralizedTime 문자열 20260424174227.0Z를 필드별로 해독하면 2026년 4월 24일 17:42:27 UTC가 된다

명세를 읽지 않고 해독하기

일회성 문자열이라면 우리 ISO 기간 변환기가 P/T 기간을 구성 요소와 총 초로 분해하고, 입력한 숫자로 문자열을 다시 만들어 준다. 기간 문자열이 아니라 두 시각(예: 22:00부터 06:30까지 이어지는 근무)이 있다면, 시간 간격 계산기가 밤을 넘기는 구간까지 포함해 경과 시간을 계산해 준다. 둘 다 브라우저 안에서만 실행되며 입력한 내용은 기기 밖으로 나가지 않는다. 도구 없이 빠르게 읽고 싶다면 두 가지 습관이면 대부분 해결된다: T를 찾아 M이 월인지 분인지 확인하고, T 왼쪽의 모든 것은 고정된 초가 아니라 달력 연산이라는 점을 기억하는 것이다.

이 아티클의 도구

자주 묻는 질문

PT1M과 P1M은 같은가?

아니다. 글자 M은 T 구분자를 기준으로 의미가 달라진다: P1M은 한 달, PT1M은 1분이다. 이것은 이 포맷에서 가장 흔한 오독이며, 이 때문에 API 버그가 배포된 적도 있다. 헷갈리면 먼저 T를 찾아라: T 앞의 모든 것은 년, 월, 주, 일 단위로 세고, T 뒤의 모든 것은 시, 분, 초 단위로 센다. 올바르게 작성된 기간에는 T 앞에 시간 단위가, T 뒤에 날짜 단위가 오는 일이 없다.

90분을 ISO 8601 기간으로 쓰려면?

PT90M과 PT1H30M 모두 유효하며 같은 시간 길이를 나타낸다. ISO 8601은 구성 요소를 관례적인 범위 안으로 강제하지 않으므로 59를 넘는 분이나 23을 넘는 시도 문제없다. 파서는 두 표기를 모두 받아들이며, 시스템이 어느 쪽을 내놓을지는 정규화 여부에 달려 있다. 사람이 읽을 기간을 생성한다면 PT1H30M이 더 친절하고, 코드에서 기간을 비교한다면 문자열이 아니라 총 초로 비교해야 한다. 서로 다른 두 문자열이 같은 의미를 가질 수 있기 때문이다.

기간(duration)과 구간(interval)의 차이는?

기간은 달력상의 위치 없이 얼마나 오래인지만 말한다: P3D는 어디서 시작하든 3일이다. ISO 8601 구간은 슬래시를 사용해 기간을 실제 날짜에 고정한다: 2026-07-04T00:00:00Z/P3D는 2026년 7월 4일부터 시작하는 3일을 의미하며, 2026-07-04/2026-07-07이라는 시작/종료 쌍도 같은 구간을 나타낸다. R 접두사를 쓰는 반복 구간도 있다: R5/2026-07-04T00:00:00Z/P1D는 그 시작일부터 매일 다섯 번 반복됨을 의미한다. 구간은 달력 단위의 모호함을 해소한다. 날짜에 고정된 P1M은 항상 정해진 하나의 길이를 가지기 때문이다.

출처