Unix C 시간(time) 함수 개념잡기
출처 : http://www.winapi.co.kr/, Win32 Api 연구 사이트
작성: 몽키몽키 (cache798@naver.com)
시간 함수
컴퓨터안에는 시계가 내장되어 있어 항상 정확한 시간을 유지하고 있는데 프로그램에서 시간을 필요로 할 경우 시간 함수로 이 값을 조사할 수 있다. 또한 조사한 시간을 목적에 맞게 조정하거나 변환 및 포맷팅할 수도 있다. 모든 시간 함수의 원형은 time.h 헤더 파일에 선언되어 있으므로 시간 관련 함수를 사용하려면 반드시 time.h를 인클루드해야 한다. 시간과 관련된 가장 기본적인 함수는 현재 시간을 구하는 time 함수이다.
time_t time( time_t *timer );
char *ctime( const time_t *timer );
time 함수는 1970년 1월 1일 자정 이후 경과한 초를 조사하는데 리턴 타입인 time_t형은 시스템에 따라 달라지며 윈도우즈에서는 4바이트 정수(typedef long time_t;)로 정의되어 있다. time 함수는 time_t형의 포인터를 인수로 받아 이 인수에 조사된 시간을 채워 주기도 하고 같은 값을 리턴하기도 한다. 둘 중 아무값이나 사용해도 상관없으며 리턴값만 사용할 경우는 인수로 NULL을 전달할 수도 있다. 다음 두 코드는 동일하다.
time_t now now=time(NULL); | time_t now time(&now); |
이 함수는 최대 2038년 1월 18일까지의 날짜를 표현할 수 있으며 64비트 버전인 _time64 함수는 3000년 12월 31일까지 표현 가능하다. 이 함수가 조사하는 시간은 초단위이기 때문에 이 값으로부터 우리가 일상적으로 사용하는 시간을 바로 구하기는 무척 어렵다. 또한 세계 표준시인 UTC 포맷으로 되어 있어 우리나라 시간과 일치하지도 않는다.
ctime 함수는 time_t형의 경과초를 출력하기 편리한 문자열 형태로 바꾸며 UTC로 된 시간을 지역 설정에 맞게 조정해 주기도 한다. 지역 설정이란 각 국가의 경도에 따른 세계 표준시와의 차이점과 일광 절약 시간(Daylight Saving time;흔히 Summer Time이라고 한다)의 운영 여부 등에 따라 달라지는데 우리나라의 경우 세계 표준시보다 9시간 더 빠르다.
변환된 문자열은 26문자 길이로 되어 있으며 끝에 개행 문자가 있어 printf 등의 함수로 곧바로 출력할 수 있다. ctime이 변환 결과를 저장하기 위해 사용하는 버퍼는 라이브러리에서 미리 할당해 놓은 정적 메모리 영역이며 이 영역은 asctime, gmtime, localtime 등의 함수들이 공유한다. 따라서 상기 함수 중 하나를 호출하면 다른 함수가 작성한 문자열은 파괴되므로 변환한 문자열을 계속 사용하려면 사본을 복사해 두어야 한다.
시간 관련 함수들이 버퍼를 공유하는 이런 설계는 이후 멀티 스레드에서 문제거리가 된다. C 라이브러리 함수를 만들 때는 멀티 스레드라는 것이 없었기 때문에 이런 점을 미처 고려하지 못했다. 다음 예제는 현재 시간을 time 함수로 조사한 후 ctime 함수로 문자열로 변환하고 그 결과를 printf로 출력한다.
예 제 : time |
void main()
{
time_t t;
time(&t);
printf("현재 시간은 %s입니다.\n",ctime(&t));;
}
실행 결과는 다음과 같다.
현재 시간은 SunJul 06 03:35:27 2008
입니다.
초단위로 된 시간을 문자열 형태로 변환하므로 읽기는 편하지만 영문으로 출력되는데다 개행 코드가 작성되어 있어 다른 문자열 중간에 삽입하려면 개행 코드를 지운 후 사용해야 하는 번거로움이 있다. 다음 두 함수는 날짜와 시간을 문자열 형태로 바로 구하는 좀 더 간단한 함수이다.
char *_strdate(char *datestr);
char *_strtime(char *timestr);
_strdate는 날짜를 MM/DD/YY 포맷으로 구해 datestr 버퍼에 복사하며 _strtime은 시간을 HH:MM:SS 포맷으로 구해 timestr 버퍼에 복사하는데 이 함수가 구해주는 시간은 24시간제이다. 두 함수로 전달되는 버퍼는 널 문자까지 고려하여 최소한 9바이트 이상이어야 한다. 다음 예제는 이 두 함수로 날짜와 시간을 구해 출력해 본 것이다.
예 제 : strdate |
void main()
{
char Date[10];
char Time[10];
_strdate(Date);
_strtime(Time);
printf("날짜 : %s, 시간 : %s\n",Date,Time);
}
실행 결과는 "날짜 : 09/06/04, 시간 : 16:35:42" 이렇다. 문자열 버퍼에 원하는 정보를 바로 조사해 채워주므로 출력하기에 편리하기는 하지만 날짜 포맷의 년도가 제일 뒤쪽에 있는 형식이라 우리나라의 날짜 표기법과는 조금 틀리다.
시간 구조체
time 함수를 사용하면 현재 시간을 쉽게 구할 수 있고 ctime을 사용하면 이 시간을 문자열로도 바꿀 수 있지만 포맷팅을 마음대로 할 수 없어 무척 불편하다. 시간 포맷을 자유롭게 변경하고 싶다면 경과초 형태로 되어 있는 값에서 각각의 시간 요소를 분리해야 한다. 다음 함수들은 time_t 형의 값을 tm 구조체로 변환한다.
struct tm *gmtime(const time_t *timer);
struct tm *localtime(const time_t *timer);
time_t mktime(struct tm *timeptr);
gmtime, localtime 함수는 둘 다 time_t 형의 값을 tm 구조체로 변환하는데 gmtime은 세계 표준시로 변환하며 localtime은 지역시간으로 변환한다. 세계 표준시는 잘 사용되지 않으므로 localtime 함수가 훨씬 더 자주 사용된다. 이 두 함수도 라이브러리에 정적으로 할당되어 있는 tm 구조체를 사용하므로 한 함수가 구해 놓은 정보는 다른 함수를 호출하면 파괴된다. mktime 함수는 반대의 변환을 하는데 tm 구조체를 time_t 형으로 바꾼다. tm 구조체는 time.h 헤더 파일에 다음과 같이 선언되어 있다.
struct tm {
int tm_sec; /* seconds after the minute - [0,59] */
int tm_min; /* minutes after the hour - [0,59] */
int tm_hour; /* hours since midnight - [0,23] */
int tm_mday; /* day of the month - [1,31] */
int tm_mon; /* months since January - [0,11] */
int tm_year; /* years since 1900 */
int tm_wday; /* days since Sunday - [0,6] */
int tm_yday; /* days since January 1 - [0,365] */
int tm_isdst; /* daylight savings time flag */
};
날짜와 시간을 구성하는 여러 가지 멤버들이 포함되어 있으며 주석도 비교적 상세하게 작성되어 있다. 각 멤버의 이름이 무척 쉽게 작성되어 있어 따로 외울 필요까지는 없지만 멤버마다 베이스가 제각각이므로 쓸 때는 조금 주의해야 한다.
멤버 | 설명 |
tm_sec | 초(0~59) |
tm_min | 분(0~59) |
tm_hour | 시간(0~23) |
tm_mday | 날짜(1~31) |
tm_mon | 월(0~11) |
tm_year | 1990년 이후 경과 년수 |
tm_wday | 요일(0~6). 0이 일요일 |
tm_yday | 년중 날짜(0~365) |
tm_isdst | 일광 절약 시간과의 차 |
다음 예제는 시간을 조사한 후 tm 구조체로 바꾸고 이 구조체의 멤버를 포맷팅하여 출력한다.
예 제 : tm |
void main()
{
time_t t;
tm *pt;
time(&t);
pt=localtime(&t);
printf("현재 시간 %d년 %d월 %d일 %d시 %d분 %d초입니다.\n",
pt->tm_year+1900,pt->tm_mon+1,pt->tm_mday,
pt->tm_hour,pt->tm_min,pt->tm_sec);;
}
시간과 날짜를 구성하는 각 요소가 멤버로 분리되어 있으므로 원하는 대로 포맷팅해서 출력할 수 있다. 실행 결과는 다음과 같다.
현재 시간 2008년 7월 6일 4시 12분 56초입니다.
시간 요소 사이에 한글을 넣을 수도 있고 시간 요소의 출력 순서를 마음대로 조정할 수 있어서 훨씬 더 자유롭고 깔끔한 출력을 할 수 있다. asctime 함수는 tm 구조체를 문자열로 바꾸는데 ctime 함수와 마찬가지로 출력 결과가 영어로 되어 있어 한글 환경에는 실용성이 없고 개행 문자도 포함되어 있다.
char *asctime(const struct tm *timeptr);
size_t strftime(char *strDest, size_t maxsize, const char *format, const struct tm *timeptr);
strftime 함수는 시간을 다양한 방식으로 포맷팅하는데 첫 번째 인수로 버퍼, 두 번째 인수로 버퍼의 길이, 세 번째 인수로 포맷팅 방식, 네 번째 인수로 tm 구조체를 준다. 세 번째 인수에 포맷팅 서식을 어떻게 지정하는가에 따라 시간을 다양한 형식의 문자열로 바꿀 수 있다.
예 제 : strftime |
void main()
{
time_t t;
char Format[128];
time(&t);
strftime(Format,128,"%Y %B %d %A %I:%M:%S %p",localtime(&t));
puts(Format);
}
실행 결과는 다음과 같다. 출력된 결과를 보면 각 서식의 의미를 알 수 있는데 %Y는 년도, %B는 달의 영문 이름, %d는 날짜이다.
2004 September 06 Monday 04:32:52 PM
레퍼런스에서 이 함수를 찾아 보면 %로 시작되는 여러 가지 복잡한 서식을 볼 수 있는데 년도를 두 자리로 또는 네 자리로 출력할 수 있고 월의 이름을 길게(January, February) 또는 짧게(Jan, Feb) 출력할 수 있으며 시간도 12시간제/24시간제로 출력할 수 있다. 충분한 포맷팅 서식이 마련되어 있는 것은 사실이지만 모두 영문으로 출력되기 때문에 우리 나라 실정에는 별 도움이 안된다.
기타 시간 함수
시간은 여러 모로 쓸 데가 많은 정보이다. 다음 함수는 프로그램이 실행을 시작한 후의 경과된 시간(Process Time)을 조사한다.
clock_t clock( void );
clock_t 타입은 long형으로 정의되어 있으며 이 함수가 조사한 값을 CLOCKS_PER_SEC으로 나누면 프로그램 실행 후의 경과 초를 알 수 있다. 이 값은 시스템에 따라 다른데 윈도우즈에서는 1000으로 정의되어 있다.
typedef long clock_t;
#define CLOCKS_PER_SEC 1000
실행 후의 경과 시간 자체는 별로 쓸 데가 없지만 두 작업 시점간의 시간을 계산하거나 일정한 시간만큼 특정 작업을 계속하고 싶을 때 clock 함수가 조사하는 시간이 기준점으로 사용될 수 있다. 다음 예제는 3초간 어떤 작업을 반복적으로 수행한다.
예 제 : clock |
{
clock_t t1,t2;
int count=0;
t1=clock();
for (;;) {
printf("기다리십시오. %d\n",count++);
t2=clock();
if (t2-t1 > 3*CLOCKS_PER_SEC) {
break;
}
}
printf("끝났습니다.\n");
}
t1에 최초 시간을 조사해 놓고 루프를 돌면서 t2를 다시 구해 이 두 시간끼리의 차가 3000이 될 때를 3초로 계산할 수 있다. delay도 정확한 시간을 지연시키기는 하지만 기다리는동안 다른 일을 할 수 없다는 점이 다르다. 시스템 속도에 상관없이 일정 시간동안 어떤 작업을 하고 싶다면 clock 함수로 구한 시간을 이용하면 된다. 다음 함수는 두 시간값의 차를 구해준다.
double difftime(time_t timer1, time_t timer0);
조사된 두 개의 시간을 인수로 전달하면 두 시간의 차이를 리턴하는데 다음 예제는 다소 복잡한 수학 계산 10만번을 하는데 걸린 시간을 측정한다.
예 제 : difftime |
#include <math.h>
void main()
{
int i;
time_t t1,t2;
time(&t1);
for (i=0;i<100000;i++) {
printf("결과 = %f\n",sin(i*3.1416/180) * cos(i*3.1416/180));
}
time(&t2);
printf("총 %.2f초가 걸렸습니다.",difftime(t2,t1));
}
실수형을 리턴하는 것으로 되어 있지만 계산 결과가 초단위로 되어 있기 때문에 정밀한 시간 계산이나 코드의 성능 측정 등에 쓰기에는 무리가 있다.
'UNIX_LINUX_C_C++' 카테고리의 다른 글
메시지 큐 사용법 (2) | 2011.11.12 |
---|---|
UNIX Time Stamp (0) | 2011.11.09 |
TCP/IP 에서 Blocking socket vs. Nonblocking socket (0) | 2011.11.08 |
BeeJ`s Guide to Network Programming (0) | 2011.10.17 |
XTerm을 이용한 오라클 10g 깔기 PHP+APACHE+ORACLE (0) | 2011.10.16 |