http://allenjeon.tistory.com/235
타임스탬프(Timestamp) 프로그래밍 기초
v1.0 2008/12/06 Copyleft by 전경헌@사이냅소프트
이 문서는 타임스탬프의 개념과 C,Python,Php에서 사용하는 방법에 대한 간략한 자료임.
유닉스/리눅스의 타임스탬프
유닉스/리눅스계열에서 사용되는 타임스탬프는 1970년1월1일 0시0분0초부터 몇초가 지났는 지를 나타내는 정수이다. 유닉스가 1970년대 초에 개발되었기 때문에 최대한 많은 숫자를 타임스탬프로 사용하기 위하여 기준일자(epoch)를 70년1월1일로 정한 것 같다. 이 타임스탬프는 지구자전축의 움직임을 고려하는 윤초(Leap Second)까지 반영하여 아주 엄격하게 정의한 숫자가 아니라 단순히 하루를 86400초로 계산하여 순차적으로 증가시킨 것이다. 윤년(Leap Year)은 들어봤겠지만 윤초(Leap Second)라고 들어본 적이 있는가? 윤초가 궁금하면 위키피디아의 윤초설명을 참조하기 바란다.
타임스탬프에 대한 감각을 익히기 위하여 몇가지 숫자를 살펴보자. 초단위로 수를 세고 있기 때문에 숫자가 매우 크다.
0 -> Thu 1970-01-01 09:00:00 KST
100000000 -> Sat 1973-03-03 18:46:40 KST
1000000000 -> Sun 2001-09-09 10:46:40 KST
1111111111 -> Fri 2005-03-18 10:58:31 KST
1234567890 -> Sat 2009-02-14 08:31:30 KST
정의상 타임스탬프값이 0일때는 1970-01-01 00:00:00 이어야 할텐데 위의 시간을 보면 9시이다. 이는 잘못된 결과가 아니고, 뒤에 KST라는 문자열에서 한국시간임을 지정하고 있기 때문이다. 대한민국은 표준시보다 9시간이 빠르기 때문에 표준시로는 1970년1월1일 자정이다.
1111111111 같은 특이한 타임스탬프는 이미 지나갔고, 근래에 다다르게 될 재미있는 타임스탬프는 1234567890가 있는데, 우리시간으로 2009년2월14일에 오전 8시31분30초이고, 국제 표준시로는 2009년2월13일 밤 11시31분30초이다.
C언어에서 사용되는 타임스탬프
타임스탬프는 C 프로그래밍시에 time.h 안에 time_t 형태로 표현되나 내부적으로는 운영체제의 종류에 따라 보통 4바이트(32비트)나 8바이트(64비트) 정수형태로 표현되고 32비트로 표현하는 경우 2038년1월19일 03:14:07에 32비트 부호있는 정수형의 최대값에 도달하게 되어 그 시간이후로는 날자와 시간이 잘못 계산되어 문제를 발생시킬 수 있다. 이를 지난 2000년에 있었던 Y2K문제에 빗대어 Y2K38문제라고 부른다.
C-프로그래밍에서 타임스탬프는 time() 함수를 이용하여 얻어낼 수 있다.
#include <stdio.h>
#include <time.h>
int main(void)
{
time_t now;
now = time(NULL);
printf("%ld\n", now);
return 0;
}
유닉스/리눅스 타임스탬프를 문자열로 바꾸기 위해서는 ctime()을 이용하거나
gmtime(), localtime()를 써서 tm 구조체로 바꾼 뒤에 strftime() 함수를 이용할 수 있다.
#include <time.h>
char *ctime(const time_t *timep);
struct tm *gmtime(const time_t *timep);
struct tm *localtime(const time_t *timep);
아래 예제에서 gmtime()은 국제표준시로, localtime()은 지역표준시로 변환한다.
#include <stdio.h>
#include <time.h>
int main(void)
{
time_t now;
now = 1234567890;
ts = localtime(&now); // 지역표준시로 변환한다 (대한민국은 KST)
//ts = gmtime(&now); // 국제표준시 GMT로 변환한다
strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", ts);
printf("%ld -> %s\n", now, buf);
return 0;
}
tm 구조체를 타임스탬프로 변경하기 위해서는 mktime() 함수를 이용한다.
#include <time.h>
time_t mktime(struct tm *tm);
타임스탬프와 크게 관련된 주제는 아니지만, 유닉스/리눅스 서버의 시간이 잘못되어있으면
데이타베이스나 웹서버등이 잘못 작동할 수 있으므로 가능한 시간을 맞춰놓을 필요가 있다.
아래는 유닉스/리눅스의 rdate 명령어를 이용하여 시간을 맞추는 예제이다.
인터넷에 연결된 time.bora.net 서버의 시간을 얻어와 출력한다.
# rdate -p time.bora.net
현재 컴퓨터의 시간을 출력한다.
# date
time.bora.net의 시간으로 현재 컴퓨터의 시간을 일치시킨다.
# rdate -s time.bora.net
내 경우는 cron에 rdate를 등록하여 일주일에 한번씩 자동으로 시간을 맞추고 있다.
MySQL에서 사용되는 타임스탬프
웹개발에서 가장 많이 사용되는 데이타베이스 중의 하나인 MySQL은 유닉스 형태의 타임스탬프를 지원하는 함수들을 가지고 있다. MySQL에 TIMESTAMP()라는 함수가 있는 데 이는 문자열을 datetime 값으로 변경하는 함수이고, 유닉스 타임스탬프를 문자열로 변경하기 위해서 from_unixtime() 함수를 이용하고, 문자열이나 날자형을 유닉스 타임스탬프로 변경하기위해서는 unix_timestamp() 함수를 이용한다. 함수명이 좀 길고, 언더바(_)의 위치가 조금 애매하지만 의미는 명확하다.
TIMESTAMP() 함수는 이름만 타임스탬프이지 반환값은 타임스탬프가 아니라 datetime 값이다.
mysql> SELECT TIMESTAMP('2008-12-31');
-> '2008-12-31 00:00:00'
아래는 unix_timestamp() 함수를 이용하여 타임스탬프값을 가져오는 예이다. 인수가 없으면 현재일시의 타임스탬프를 가져온다.
mysql> SELECT UNIX_TIMESTAMP();
-> 1228552236
mysql> SELECT UNIX_TIMESTAMP('2008-12-06 00:00:00');
-> 1228489200
타임스탬프값을 문자열로 변환하기 위해서는 from_unixtime() 함수를 이용한다. 파라미터로 unix_timestamp()값을 사용하면 되고, 반환되는 형식은 문맥에 따라 문자열(YYYY-MM-DD HH:MM:SS)이나 정수값(YYYYMMDDHHMMSS)으로 자동변환되어 결정된다.
mysql> select from_unixtime(1234567890);
-> '2009-02-14 08:31:30'
mysql> select from_unixtime(1234567890) + 0;
-> 20090214083130.000000
MySQL의 Now() 함수는 from_unixtime( unix_timestamp() )와 같은 내용이다.
mysql> SELECT NOW();
-> '2008-12-06 17:40:55'
mysql> SELECT NOW() + 0;
-> 20081206174055
개인적으로 데이타베이스에서 날자와시간을 사용할때 타임스탬프나 datetime을 쓰기보다는 문자열 CHAR(14) 'YYYYMMDDHHMMSS' 이나 CHAR(19) 'YYYY-MM-DD HH:MM:SS'를 사용하는 것을 선호한다.
Python에서 사용되는 타임스탬프
파이썬은 유닉스/리눅스의 time.h 함수에 대응하는 동일한 형태의 모듈을 가지고 있다. 모듈의 이름은 time이며 사용법은 C 언어 함수와 대동소이하다. 차이가 있다고 하면 파이썬에서는 C언어와 달리 time() 함수의 리턴값이 정수가 아닌 실수로 반환된다는 것이다. 소수점이하의 타임스탬프값은 시스템에 따라서 안 나올 수 있다고 한다.
>>> import time
>>> time.time()
1228546179.4690001
>>> time.gmtime(0)
(1970, 1, 1, 0, 0, 0, 3, 1, 0)
>>> time.localtime(0)
(1970, 1, 1, 9, 0, 0, 3, 1, 0)
>>> time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(1234567890))
'Fri, 13 Feb 2009 23:31:30 +0000'
>>> time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime(1234567890))
'Sat, 14 Feb 2009 08:31:30 +0000'
위에서 기준일자는 역시 1970년1월1일임을 알 수 있고, localtime이 9시간 빠른 우리나라에서 수행한 것임도 알 수 있다.
파이썬에서 사용할 수 있는 또하나의 타임스탬프가 있다. 바로 그레고리안 달력의 1년1월1일을 1로 하는 정수인데, 하루가 지날때마다 1씩 증가하고 이를 ordinal이라 한다. ordinal을 사용하기 위해서는 datetime 모듈의 fromordinal, toordinal 함수를 사용한다.
>>> from datetime import date
>>> date.today().toordinal()
733382
>>> date.fromordinal(1)
datetime.date(1, 1, 1)
>>> date.fromordinal(100000)
datetime.date(274, 10, 16)
>>> date.fromordinal(666666)
datetime.date(1826, 4, 9)
>>> date.fromordinal(777777)
datetime.date(2130, 6, 25)
유닉스/리눅스 타임스탬프가 1970년1월1일부터 초를 세는 것이고 하루는 86400초이므로,
datetime의 ordinal 과 타임스탬프사이에는 아래의 관계가 성립한다.
(Gregorian_ordinal - 719163) * 86400 == Unix_TimeStamp
위에서, 719163은 1970년1월1일의 ordinal 이다.
>>> from datetime import date
>>> date(1970,1,1).toordinal()
719163
>>> import time
>>> time.gmtime( (date(1970,1,3).toordinal() - 719163) * 86400 )
(1970, 1, 3, 0, 0, 0, 5, 3, 0)
Php에서 사용되는 타임스탬프
Php에서 현재의 타임스탬프를 얻어오기 위해서 time()함수를 사용할 수 있다.
그러나 보통 Php에서 날자는 date()라는 막강한 함수를 이용한다.
time() 함수는 date("U")와 같다.
date() 함수는 포맷인자를 이용하여 날자와 관련된 거의 모든 표현을 할 수 있다.
자세한 설명은 PHP date() 함수 매뉴얼을 참조하기 바란다.
<?php
$tmstmp = time();
print $tmstmp." -> ".date("Y-m-d H:i:s", $tmstmp)."<br>";
print date("U")."<br>";
print date("Y-m-d H:i:s",1234567890)."<br>";
?>
Php프로그램의 수행결과는 아래와 같다.
1228548141 -> 2008-12-06 16:22:21
1228548141
2009-02-14 08:31:30