PHP 및 mySQL : 2038 년 버그 : 무엇입니까? 그것을 해결하는 방법?


116

TIMESTAMP를 사용하여 날짜 + 시간을 저장하려고 생각했지만 2038 년 제한이 있다는 것을 읽었습니다. 대량으로 질문하는 대신 초보 사용자도 쉽게 이해할 수 있도록 작은 부분으로 나누는 것을 선호했습니다. 그래서 내 질문 (들) :

  1. 2038 년 문제는 정확히 무엇입니까?
  2. 왜 발생하고 발생하면 어떻게됩니까?
  3. 어떻게 해결합니까?
  4. 비슷한 문제를 일으키지 않는 사용에 대한 가능한 대안이 있습니까?
  5. TIMESTAMP를 사용하는 기존 애플리케이션에 대해 소위 문제가 실제로 발생하는 것을 방지하기 위해 무엇을 할 수 있습니까?

미리 감사드립니다.


1
아직 28 년이 남았습니다. 1982 년부터 컴퓨터 관련 기술을 사용하고 계십니까? 있을 것 같지 않게. 그러니 걱정하지 마세요. 2038 년이되면 더 이상 문제가되지 않을 것입니다.
— Gordon

24
고든, 나는 예측을하는 애플리케이션을 만든다. 나는 매달 얼마나 많은 돈을 저축하고 언제 백만장자가 될지 예측할 수 있습니다. 제 경우에는 28 년이 그다지 많지 않으며, 지금이 문제가있는 유일한 사람은 저뿐이 아닙니다 (타임 스탬프를 나타내는 64 비트 숫자를 사용하여 해결했습니다).
— Emil Vikström 2010 년

2
@Emil 지금 64 비트 정수를 사용하여 구체적인 문제에 대한 쉬운 해결책을 찾았습니다. 모든 사람에게 적용되지는 않지만 (또는 필요로하는) ​​유스 케이스를 위해 작동합니다. 요점은 OP에 예측과 같은 구체적인 문제가 없으면 흥미로운 주제 일 수 있지만 일반적인 수준에서이 문제를 해결하는 것은 PHP (태그에주의) 문제가 아니기 때문에 걱정할 필요가 없다는 것입니다. 내 2c.
— Gordon

1
2038 년까지 "YYYY-MM-DD HH : MM : SS : mmmm ..."문자열을 구문 분석하는 것이 가장 저렴한 작업이 될 것입니다. 2038 년까지 32 비트는 폐기 될 것입니다. 나는 그때 존재할 것이라는 것을 알고있는 유닉스 타임 스탬프가 의심스럽고 만약 그렇다면 우리의 256 비트 시스템은 4096 비트 시스템이 행복한 식사로 제공되는 시대를 훨씬 넘어서는 날짜를 처리 할 것입니다.
— Super Cat

8
9 년이 지난 지금 고든. TIMESTAMPS는 계속 사용됩니다. 우리는 28 년 전의 기술을 여전히 사용합니다. 월드 와이드 웹이라고합니다.
— sfscs 19

답변:


149

나는 이것을 커뮤니티 위키로 표시 했으므로 편하게 편집 할 수 있습니다.

2038 년 문제는 정확히 무엇입니까?

"2038 년 문제 (Y2K 문제와 유사하게 Unix Millennium Bug, Y2K38라고도 함)로 인해 일부 컴퓨터 소프트웨어가 2038 년 이전 또는 2038 년에 실패 할 수 있습니다.이 문제는 시스템 시간을 서명 된 32로 저장하는 모든 소프트웨어 및 시스템에 영향을줍니다. -비트 정수이고이 숫자를 1970 년 1 월 1 일 00:00:00 UTC 이후의 초 수로 해석합니다. "


왜 발생하고 발생하면 어떻게됩니까?

2038 년 1 월 19 일 화요일 03:14:07 UTC 이후의 시간 은 ' 순환 '되어 내부적으로 음수로 저장되며, 이러한 시스템은 2038 년이 아닌 1901 년 12 월 13 일의 시간으로 해석됩니다. UNIX 시대 (1970 년 1 월 1 일 00:00:00 GMT) 이후의 시간 (초)이 32 비트 부호있는 정수에 대한 컴퓨터의 최대 값을 초과했다는 사실.


어떻게 해결합니까?

  • 긴 데이터 유형 사용 (64 비트이면 충분 함)
  • MySQL (또는 MariaDB)의 경우 시간 정보가 필요하지 않으면 DATE열 유형을 사용하는 것이 좋습니다. 더 높은 정확도가 필요한 DATETIME경우 TIMESTAMP. 조심하십시오 DATETIME응용 프로그램이 사용 된 시간대 알고 있어야합니다, 그래서 열이 시간대에 대한 정보를 저장하지 않습니다.
  • Wikipedia에 설명 된 다른 가능한 솔루션
  • MySQL 개발자가 10 년 전에보고 된 이 버그 를 수정할 때까지 기다리십시오 .

비슷한 문제를 일으키지 않는 사용에 대한 가능한 대안이 있습니까?

데이터베이스에 날짜를 저장하기 위해 가능한 한 큰 유형을 사용하도록 시도하십시오. 64 비트이면 충분합니다. GNU C 및 POSIX / SuS 또는 sprintf('%u'...)PHP 또는 BCmath 확장 의 long long 유형입니다 .


아직 2038 년이 아니지만 잠재적으로 파괴되는 사용 사례에는 어떤 것이 있습니까?

따라서 MySQL DATETIME 의 범위는 1000-9999이지만 TIMESTAMP의 범위는 1970-2038입니다. 시스템에 생년월일, 미래의 미래 날짜 (예 : 30 년 모기지) 또는 이와 유사한 정보가 저장되어 있으면 이미이 버그가 발생합니다. 다시 말하지만 이것이 문제가 될 경우 TIMESTAMP를 사용하지 마십시오.


TIMESTAMP를 사용하는 기존 애플리케이션에 대해 소위 문제가 실제로 발생하는 것을 방지하기 위해 무엇을 할 수 있습니까?

웹이 아직 레거시 플랫폼이 아니기 때문에 예측하기는 어렵지만 2038 년에는 PHP 애플리케이션이 거의 없을 것입니다.

다음은 변환 TIMESTAMP할 데이터베이스 테이블 열을 변경하는 프로세스입니다 DATETIME. 임시 열을 만드는 것으로 시작합니다.

# rename the old TIMESTAMP field
ALTER TABLE `myTable` CHANGE `myTimestamp` `temp_myTimestamp` int(11) NOT NULL;

# create a new DATETIME column of the same name as your old column
ALTER TABLE `myTable` ADD `myTimestamp` DATETIME NOT NULL;

# update all rows by populating your new DATETIME field
UPDATE `myTable` SET `myTimestamp` = FROM_UNIXTIME(temp_myTimestamp);

# remove the temporary column
ALTER TABLE `myTable` DROP `temp_myTimestamp`

자원


2
대박. 나에게 당신의 대답은 가장 완벽합니다. 고맙습니다.
— Devner 2010 년

7
MySQL에서 향후 버전이 TIMESTAMP의 기본 스토리지 데이터 유형을 64 비트로 변경하면 코드를 DATETIME으로 변경할 필요가 없습니다. TIMESTAMP를 사용하지 못하게하는 것은 그 데이터 유형에 목적이 있기 때문에 옳은 일이라고 생각하지 않습니다.
— pixelfreak

1
MySQL의 서명 된 BIGINT 필드는 타임 스탬프를 저장하는 데 잘 작동하는 것처럼 보이며 MySQL 5.5에서 일부 로컬 테스트를 수행하여 작동하는지 확인했습니다. 과거의 날짜도 나타낼 수 있으므로 서명을 사용하는 것이 서명되지 않은 것보다 낫습니다. 타임 스탬프에 BIGINT를 사용하지 않는 이유가 있습니까?
— zuallauz

한 가지 주목할 점은 MySQL은 타임 스탬프 필드에 대해 현재 날짜 / 시간 (CURRENT_TIMESTAMP)으로 만 자동 설정됩니다. 이 기능이 결국 모든 날짜 유형으로 이식되기를 바랍니다.
— Ray

5
MySQL (및 MariaDB)이 64 비트 시스템에 타임 스탬프를 저장하기 위해 64 비트 정수를 사용하지 않는 것은 절대적으로 터무니없는 일입니다. 시간대에 대해 모르기 때문에 DATETIME을 사용 하는 것은 적절한 해결책 이 아닙니다 . 이것은 2005 년 에 보고 되었지만 여전히 수정 사항이 없습니다.
— 마이크

14

UNIX 타임 스탬프를 사용하여 날짜를 저장할 때 실제로는 1970-01-01 이후의 초 수를 유지하는 32 비트 정수를 사용합니다. Unix Time 참조

그 32 비트 숫자는 2038 년에 넘칠 것입니다. 이것이 2038 년 문제입니다.


이 문제를 해결하기 위해, 당신은 당신의 날짜 저장하는 데 32 개 비트를 UNIX 타임 스탬프를 사용해서는 안 - 수단, MySQL을 사용하는 경우, 당신은 사용하지 말아야 TIMESTAMP하지만 DATETIME(참조 10.3.1을 DATETIME, DATE, 및 TIMESTAMP 유형. )

이 DATETIME유형은 날짜 및 시간 정보를 모두 포함하는 값이 필요할 때 사용됩니다. 지원되는 범위는 '1000-01-01 00:00:00'~ '9999-12-31 23:59:59'입니다.

TIMESTAMP데이터 유형의 범위가 '1970-01-01 00:00:01'에 UTC '2038-01-19 03:14:07'UTC합니다.


(아마도) 이 문제는 사용하지 않는 것을 피하기 / 수정하는 응용 프로그램에 할 수있는 가장 좋은 방법 TIMESTAMP,하지만 DATETIME1970 년과 2038 사이에없는 날짜를 포함해야하는 열의.

하지만 한 가지 작은 메모 : 2038 년 이전에 신청서가 꽤 많이 다시 작성 될 가능성이 매우 높습니다 (통계적으로 말하면) ^^ 그러니 미래의 날짜를 다룰 필요가 없다면 , 현재 버전의 응용 프로그램에서 해당 문제를 처리 할 필요가 없습니다.


1
+1 정보. 여기서 시도는 처음부터 모범 사례를 적용하여 나중에 문제에 대해 걱정할 필요가 없도록하는 것입니다. 따라서 지금은 2038 년이 문제가 아닌 것 같지만 모범 사례를 따르고 처음부터 내가 만드는 모든 응용 프로그램에 대해 따르고 싶습니다. 이해가 되길 바랍니다.
— Devner 2010 년

예, 말이됩니다. 요점을 알겠습니다. 그러나 "모범 사례"는 "요구에 대한 답변"을 의미 할 수도 있습니다. 타임 스탬프가 충분하다는 것을 알고 있다면 datetime을 사용할 필요가 없습니다 (예를 들어 저장하기 위해 더 많은 메모리가 필요합니다. 수백만 개의 레코드가 있습니다) ;; 일부 열 (예 : 현재 날짜를 포함하는 열)에 타임 스탬프를 사용하고 다른 열 (예 : 과거 / 미래 날짜를 포함하는 열)에는 datetime을 사용하는 애플리케이션이 있습니다.
— Pascal MARTIN

귀하의 절차도 의미가 있으며 특히 저장 공간과 관련하여 잘 작동합니다. 괜찮다면 애플리케이션의 TIMESTAMP 열에 일반적으로 사용하는 구조와 길이를 물어봐도 될까요? 감사.
— Devner 2010 년

글쎄요, 제가 TIMESTAMP를 사용하고 싶을 때, 그것은 내 "날짜 / 시간"데이터가 1970 년에서 2038 년 사이에 적합하기 때문입니다. 그래서 저는 MySQL TIMESTAMP 데이터 유형을 사용합니다.
— Pascal MARTIN

정보 주셔서 감사합니다. 귀하의 답변에 따르면 열을 TIMESTAMP로 선언하는 것으로 충분하며 길이를 제공하지 않는 int 또는 var와 달리 길이를 제공 할 필요가 없음을 이해합니다. 내가 맞아?
— Devner 2010 년

7

구글에서 빠른 검색이 트릭을 할 것입니다 : 2038 년 문제

  1. 2038 년 문제 (Y2K 문제와 유사하게 Unix Millennium Bug, Y2K38라고도 함)로 인해 일부 컴퓨터 소프트웨어가 2038 년 이전 또는 이후에 실패 할 수 있습니다.
  2. 이 문제는 시스템 시간을 부호있는 32 비트 정수로 저장하는 모든 소프트웨어 및 시스템에 영향을 미치며이 숫자를 1970 년 1 월 1 일 00:00:00 UTC 이후의 초 수로 해석합니다. 이러한 방식으로 표현할 수있는 최신 시간 2038 년 1 월 19 일 화요일 03:14:07 UTC입니다.이 순간 이후의 시간은 "둘러싸고"내부적으로 음수로 저장됩니다.이 시스템은 2038 년이 아닌 1901 년의 날짜로 해석됩니다.
  3. 기존 CPU / OS 조합, 기존 파일 시스템 또는 기존 바이너리 데이터 형식에 대한이 문제를 쉽게 해결할 수있는 방법은 없습니다.

2

http://en.wikipedia.org/wiki/Year_2038_problem 에 대부분의 세부 정보가 있습니다.

요약해서 말하자면:

1) + 2) 문제는 많은 시스템이 1970 년 1 월 1 일 이후의 초 수와 동일한 32 비트 부호있는 정수로 날짜 정보를 저장한다는 것입니다. 이와 같이 저장 될 수있는 최신 날짜는 2038 년 1 월 19 일 화요일 03:14:07 UTC입니다.이 경우 int는 "둘러싸고"음수로 저장되며 1901 년 날짜로 해석됩니다. 정확히 무슨 일이 일어날 지, 시스템마다 다르지만 아마 그들 중 누구에게도 좋지 않을 것이라고 말하기에 충분합니다!

과거의 날짜 만 저장하는 시스템의 경우 잠시 걱정할 필요가 없습니다! 주요 문제는 미래의 날짜로 작동하는 시스템에 있습니다. 시스템이 28 년 후의 날짜로 작동해야한다면 지금 걱정해야합니다!

3) 사용 가능한 대체 날짜 형식 중 하나를 사용하거나 64 비트 시스템으로 이동하고 64 비트 정수를 사용합니다. 또는 데이터베이스의 경우 대체 타임 스탬프 형식을 사용합니다 (예 : MySQL의 경우 DATETIME 사용).

4) 3을보십시오!

5) 4 참조 !!! ;)


귀하의 포인트 4 및 5는 '참조로 전화'를 상기시킵니다. 그것은 내 얼굴에 미소를 지었다. 감사합니다. +1.
— Devner 2010 년

1

브라더스, PHP를 사용하여 타임 스탬프를 표시해야하는 경우 UNIX_TIMESTAMP 형식을 변경하지 않고 최고의 PHP 솔루션입니다.

custom_date () 함수를 사용하십시오. 그 안에 DateTime을 사용하십시오. 다음은 DateTime 솔루션 입니다.

데이터베이스의 타임 스탬프로 UNSIGNED BIGINT (8)가있는 한. PHP 5.2.0 ++이있는 한


-1

아무것도 업그레이드하고 싶지 않았기 때문에 PHP 대신이 작업을 수행하도록 백엔드 (MSSQL)에 요청했습니다!

$qry = "select DATEADD(month, 1, :date) next_date ";
$rs_tmp = $pdo->prepare($qry);
$rs_tmp->bindValue(":date", '2038/01/15');
$rs_tmp->execute();
$row_tmp = $rs_tmp->fetch(PDO::FETCH_ASSOC);

echo $row_tmp['next_date'];

효율적인 방법은 아니지만 작동합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.