asctime, asctime_s
asctime, asctime_s
struct tm에 담긴 달력 시간을 사람이 읽을 수 있는 문자열로 바꾸고 싶을 때 쓰는 함수가 asctime이에요. 다만 정적 버퍼를 쓰고 스레드에 안전하지 않아서, C23부터는 폐기됐어요. <time.h>에 정의돼 있어요.
출처: cppreference
본문
asctime()은 주어진 달력 시간 tm을 다음과 같은 고정된 25자 형태의 문자열로 변환해요.
Www Mmm dd hh:mm:ss yyyy\n
각 부분의 의미는 이러해요.
Www— 요일을 영어 3글자로 (time_ptr->tm_wday),Mon,Tue,Wed,Thu,Fri,Sat,Sun중 하나.Mmm— 달을 영어 3글자로 (time_ptr->tm_mon),Jan~Dec중 하나.dd— 일을 2자리로 (time_ptr->tm_mday),sprintf의%2d처럼.hh— 시를 2자리로 (time_ptr->tm_hour),%.2d처럼.mm— 분을 2자리로 (time_ptr->tm_min),%.2d처럼.ss— 초를 2자리로 (time_ptr->tm_sec),%.2d처럼.yyyy— 연도를 4자리로 (time_ptr->tm_year + 1900),%4d처럼.
주의할 점이 몇 가지 있어요.
*time_ptr의 어떤 멤버라도 정상 범위를 벗어나면 동작은 정의되지 않아요(undefined behavior).time_ptr->tm_year가 가리키는 달력 연도가 4자리를 넘거나 1000년 미만이어도 동작은 정의되지 않아요.- 이 함수는 지역화(localization)를 지원하지 않고, 끝에 붙는 개행 문자를 뗄 수도 없어요.
- 정적 저장소를 수정하므로 스레드에 안전하지 않아요.
- C23부터는 폐기(deprecated)되어 새 코드에서 쓰면 안 돼요.
char* asctime( const struct tm* time_ptr ); // (1) until C23
[[deprecated]] char* asctime( const struct tm* time_ptr ); // (1) since C23
errno_t asctime_s( char* buf, rsize_t bufsz, const struct tm* time_ptr ); // (2) since C11
(2)번 asctime_s는 (1)과 같지만, 결과를 사용자가 제공한 버퍼 buf에 쓰고 항상 null 종결을 보장해요. 다음 오류를 런타임에 감지하면 설치된 제약 처리 함수(constraint handler)를 호출해요.
buf또는time_ptr이 널 포인터bufsz가 26보다 작거나RSIZE_MAX보다 큼*time_ptr의 모든 멤버가 정상 범위 안에 있지 않음time_ptr->tm_year가 나타내는 연도가 0보다 작거나 9999보다 큼
대부분의 경계 검사 함수처럼, asctime_s는 구현이 __STDC_LIB_EXT1__을 정의하고 사용자가 <time.h>를 포함하기 전에 __STDC_WANT_LIB_EXT1__을 정수 상수 1로 정의했을 때만 쓸 수 있어요.
매개변수
| 매개변수 | 설명 |
|---|---|
time_ptr |
출력할 시간을 담은 tm 객체를 가리키는 포인터 |
buf |
최소 26바이트인 사용자 제공 버퍼를 가리키는 포인터 |
bufsz |
사용자 제공 버퍼의 크기 |
반환값
-
위에서 설명한 날짜·시간 문자열을 담은 정적 null 종결 문자열을 가리키는 포인터. 이 문자열은
asctime과ctime이 공유할 수 있고, 두 함수 중 하나가 호출될 때마다 덮어써질 수 있어요. -
성공 시 0, 실패 시 0이 아닌 값. 실패하면
buf[0]을 0으로 설정해요(buf가 널이거나bufsz가 0 또는RSIZE_MAX보다 큰 경우 제외).
주의
asctime은 정적 데이터를 가리키는 포인터를 돌려주고 스레드에 안전하지 않아요. POSIX도 이 함수를 쓸모없어졌다(obsolete)고 보고strftime사용을 권장해요. C 표준도strftime이 더 유연하고 로케일을 고려하므로asctime과asctime_s대신strftime을 권장해요.- POSIX는 정의되지 않은 동작을 "출력 문자열이 25자보다 길 때,
timeptr->tm_wday나timeptr->tm_mon이 기대 범위를 벗어났을 때,timeptr->tm_year가INT_MAX - 1990을 넘을 때"로 한정해요. - 일부 구현은
timeptr->tm_mday == 0을 "이전 달의 마지막 날"로 취급해요.
예시
localtime()으로 얻은 tm을 asctime으로 출력하는 흐름이에요. printf의 %s 형식 때문에 개행이 한 번 더 붙는다는 점을 주의하세요.
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <time.h>
int main(void)
{
struct tm tm = *localtime(&(time_t){time(NULL)});
printf("%s", asctime(&tm)); // note implicit trailing '\n'
#ifdef __STDC_LIB_EXT1__
char str[26];
asctime_s(str, sizeof str, &tm);
printf("%s", str);
#endif
}
가능한 출력(예시):
Tue May 26 21:51:50 2015
Tue May 26 21:51:50 2015
더 알아보기
time_t를 바로 문자열로 바꾸는 함수는ctime/ctime_s를 봐요.- 더 유연하고 로케일을 고려하는 형식 변환은
strftime을 봐요. - cppreference의 asctime 원문을 참고해요.