2038년 문제

1 개요

Year_2038_problem.gif
유닉스 시간에 32비트 정수형을 쓰는 모든 컴퓨터의 시계가 UTC 0 기준으로 2038년 1월 19일 3시 14분 7초[1](대한민국 표준시 UTC+9 기준으로 2038년 1월 19일 12시 14분 7초)가 지나는 순간 음수값이 적용돼 1901년 12월 13일 20시 45분 52초나, 자동적으로 오류를 감지하고 초기값인 0, 즉 1970년 1월 1일 0시 0분 0초로 돌아가게 되는 버그를 칭한다. 영어로는 Year 2038 problem, Unix Millennium bug 등으로 표기한다.

원인은 프로그래머라면 알고 있는, 그리고 알아야만 하는 오버플로 현상 때문이다.

2 시간을 역행한다

컴퓨터에서 사람들이 쓰는 태양력 시간을 계산하는 방법은 여러가지가 있는데, 가장 많이 쓰는 방법이 유닉스 운영체제에서 채용한 유닉스 시간이다. 여기서 쓴 방식이 32비트 크기의 정수형으로 시간을 나타내는 변수를 선언하고 초당 1씩 증가하도록 처리했다. 이로 인해 값이 32비트 크기의 표현한계인 2,147,483,647까지 증가하면 더 이상 증가할 수 없게 된다. 컴퓨터에서 이런 오버플로가 발생할 경우 해당범위의 최소값으로 돌아가는 식으로 처리된다. 간단하게 값(x)의 범위가 0≤x≤99 일 때 99 다음의 수는 100이 아니라 0이 되는 식이다.

이로 인해 2038년 1월 19일 3시 14분 7초가 지나면 유닉스 시간이 맨 처음으로 돌아가게 되고, 그로 인해 컴퓨터의 각종 연산에 문제를 줄 수 있다. 과장일 수 있지만 Y2K 문제에서 언급된 문제들이 발생할 수 있다. Y2K는 사람이 헷갈리는 거지만 이건 기계가 헷갈리는 거니까 진짜로.

시간을 나타내는 변수를 32비트 크기가 아니라 64비트 크기의 정수형으로 바꾸면 되지만 말처럼 쉬운 게 아니란 점이 골칫거리. 시간을 표현하는 변수의 형식을 그냥 막 바꿔버리면 기존에 구현한 알고리즘들도 꼬이고 각종 호환성 크리가 터질 수 있기 때문.

정수형을 부호 없는 정수형(Unsigned Integer)으로 바꾸면 2106년까지 늦출 수 있다. 음수 부분이 없이 0부터 시작하므로 4,294,967,295까지 증가하기 때문. 물론 이렇게 하면 음수부분의 시간이 없어지므로 Unix Time 0에 해당하는 1970-01-01 이전의 시간을 셀 수 없으므로 이 역시 문제가 있는 건 마찬가지.

만약 16비트를 쓴다면 9시간 6분 8초, 8비트라면 4분 16초밖에 못 셀 것이다. 물론 주요 시스템 중 8비트나 16비트를 쓰는 것은 거의 없고, 그나마 이쪽이 주력인 MCU임베디드 시스템가 있긴 하나 8비트 16비트 급에선 외부 RTC를 두는 게 일반적이므로 별 문제 없다.

3 해결책

컴퓨터 업계쪽 사람들은 의외로 느긋하게 생각하고 있는데, 지금부터 프로그램을 짤 때 유닉스 시간에 64비트 정수형을 쓰면 되기 때문. 유닉스 시간을 설계하던 당시에도 이 문제를 알고 있었지만 "후손들이 그 전에 알아서 잘 해결할 거야"였다나 뭐라나... 하지만 이미 현실에선 문제가 발생하고 있다. 바로 미래를 다루는 구형 시스템들. 예를 들어 연금보험을 보정하지 않은 구형 시스템으로 2038년 문제를 처리할 경우, 1977년생이 만 61세부터 보험을 탈 수 있다고 가정하면 바로 2038년에 첫 연금을 수령하게 된다! 수령 예상액 등을 미리 계산해보면 이 사람은 태어나기도 전인 1970년에 연금을 수령하는 꼴이 된다. 물론 국내 시스템은 2038년 문제가 없다고 봐도 된다. 중국에선 국내 소프트웨어를 이용해 시스템을 구축하고 상용화하기 전에 테스트를 통해 2038년 문제를 감지하고 수정 버전을 요청한 적이 있다.

64비트 정수형도 숫자 표시에 한계가 있으므로 2922억 7702만 4641년 후에 문제가 발생하겠지만, 태양계 멸망이나 인류 멸망은 둘째치고 태양력을 그 때까지 쓰진 않을테니 문제없다. 밑에 나온 만화는 마야 달력2012년과 유닉스 시간을 빗댄 만화다.
파일:Attachment/2038년 문제/Calendar.jpg

수천 년 전... 마야 왕국에서...
- 2012년 12월 21일 이후 날짜를 새길 석판이 없어요.
- 괜찮아. 누가 그렇게 먼 미래 달력이 필요하겠어?
오늘날....
- 맙소사... 세상이 2012년 12월 21일에 멸망하려나 봐. 마야 달력 마지막날이야.
- 그래. 마야인들은 뛰어난 사람들이었지. 아마 맞을거야.

몇 년 전...
- 컴퓨터에서 시간을 어떻게 표기할까?
- 64비트 정수를 쓰자. 누가 그렇게 먼 미래까지 기록하겠어?
292,277,024,641년 후...
- 젠장... 세상이 292,277,026,596년 12월 4일에 멸망하려나 봐. 유닉스 날짜 마지막날이야.
- 그래. 엔지니어들은 뛰어난 사람들이었지. 아마 맞을거야.

4 기타

  • 아주 예전에 만들어진 게임들을 하다보면 만렙 찍고나서 다시 0렙이나 1렙 또는 기괴한 렙이 나오는 현상이 있었는데, 이 문제와 같은 원인에서 발생하는 것이었다. 극단적인 예로, 8비트에서 127 다음에 -128로, 혹은 255 다음에 0으로 넘어가는 문제가 있다. 스타크래프트의 유닛 킬 수가 255를 안 넘는 것도 유닛 킬 수 값을 8비트로 지정해서 일어나는 것.
  • 메이플스토리에서 한때 아이템 창과 창고에 각각 21억 4748만 3647메소씩, 최대 42억 9496만 7294메소를 가질 수 있었다. 하지만 패치로 100억으로 늘어났다. 그리고 이 때까지 메이플의 보스 몬스터들의 최대 체력값이 21억 4748만 3647이어서 자쿰은 팔과 본체, 혼테일은 머리, 팔, 꼬리 등의 몸 부분, 핑크빈은 석상과 분신, 시그너스는 기사단장들과 신수[2] 등으로 보스 몬스터 판정이 나는 몬스터들이 따로 있었다. 하지만 하드 매그너스 때에 와서야 최대 체력값이 풀렸고, 덕분에 언리미티드 이후 대다수의 보스몹들의 피통은 단일 피통으로도 21억을 훌쩍 넘어가게 됐다.[3]
  • MySQL에서 지원하는 TIMESTAMP 형엔 이 버그가 남아 있다. 거기에 DATETIME 등 다른 날짜 형식으로 바꿔도 10000년 이후는 표시할 수 없다. 이 한계는 다른 SQL도 마찬가지라, 이 문제를 해결하려면 입력받은 날짜와 64비트 정수 사이를 변환하는 기능을 구현해야 한다. 다행히 대부분의 SQL에선 64비트 정수를 날짜로 변환하는 기능을 제공하고 있다.
  • iPhone은 반대의 문제를 갖고 있다. 64비트 프로세서를 사용한 iPhone 5s 이후 iPhone의 시간을 1970년 1월 1일로 수동으로 설정하고 재부팅하면 벽돌이 되는 버그다.
  • 2033년 문제와는 상관 없다. 이는 음력 윤달에 관한 문제.

5 관련 문서

  1. 초기값인 1970년 1월 1일 0시 0분 기준으로 68년 35일 3시간 14분 7초.
  2. 그리고 그걸로도 모자랐는지 시그너스 기본 피통 21억에 회복하는 패턴으로 어거지로 피통을 늘렸다.
  3. 그런데 카오스 핑크빈의 경우 피통이 늘어났지만 격파 방법은 이 피통을 14번 까는 것으로 이전과 동일하다.