본문 바로가기

프로그래밍 강좌/C++

[C++] 시스템 시간 날짜 얻어오기, SYSTEMTIME, GetLocalTime, GetSystemTime byte 모호한 기호입니다 chrono steady_clock system_clock time_t 현재시간 알아내기

코딩을 하다보면 시스템 시간과 날짜가 필요한 경우가 많습니다.

보통 로깅을 하기 위해서죠. 다행히 Windows API에서 시스템 시간과 날짜를 가져오는 interface를 제공합니다.

 

SYSTEMTIME은 아래와 같이 정의되어 있어요

typedef struct _SYSTEMTIME {
    WORD wYear;
    WORD wMonth;
    WORD wDayOfWeek;
    WORD wDay;
    WORD wHour;
    WORD wMinute;
    WORD wSecond;
    WORD wMilliseconds;
}SYSTEMTIME, *PSYSTEMTIME;
 

SYSTEMTIME을 사용하기 위해서는 #include <windows.h>를 해 줘야 해요.

 

1. GetSystemTime()

GetSystemTime은 UTC 시간을 가져옵니다.

UTC 시간은, 원자시계를 기준으로 한 표준시로써, 1972년 1월 1일부터 시행된 국제 표준시 입니다.

한국 시간으로는 KST(Korean Standard Time) UTC + 9:00 이 됩니다. UTC 시간에 9시간을 더하라.

라는 뜻이죠.

 

2. GetLocalTime()

GetLocalTime()은 현재 PC에 세팅되어 있는 시간을 가져옵니다.

우리는 GetLocalTime을 가져오는 것이 로깅 시간과 맞기 때문에 많이 사용됩니다.

 

SYSTEMTIME을 사용하기 위해 windows.h 을 추가했고,

WORD -> std::string 을 하기 위해(to_string()) string.h 을 추가했어요.

#include <iostream>
#include <windows.h>
#include <string>

enum Week
{
    Sunday,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday
};

int main()
{
    SYSTEMTIME st;
    GetLocalTime(&st);
	std::string strYear = std::to_string(st.wYear);
    std::string strMonth = std::to_string(st.wMonth);
    std::string strDay = std::to_string(st.wDay);

    std::cout << "현재 날짜:"<< strYear <<"년 "<< strMonth<<"월 "<< strDay<<"일 ";

    switch (st.wDayOfWeek)
    {
    case Sunday:
        std::cout << "일요일" << std::endl;
        break;
    case Monday:
        std::cout << "월요일" << std::endl;
        break;
    case Tuesday:
        std::cout << "화요일" << std::endl;
        break;
    case Wednesday:
        std::cout << "수요일" << std::endl;
        break;
    case Thursday:
        std::cout << "목요일" << std::endl;
        break;
    case Friday:
        std::cout << "금요일" << std::endl;
        break;
    case Saturday:
        std::cout << "토요일" << std::endl;
        break;
    }

    std::string strHour = std::to_string(st.wHour);
    std::string strMinute = std::to_string(st.wMinute);
    std::string strSecond = std::to_string(st.wSecond);

    std::cout << "현재 시간:" << strHour << ":" << strMinute << ":" << strSecond << std::endl;

    return 0;
}
 

enum 대신 enum class 를 사용하는 것을 권장하나 여기에서는 간단한 예제이니 쉽게 하려고 enum을 사용했어요.

 

실행 결과, 아래와 같이 현재 시간과 날짜를 출력하실 수 있습니다.

혹시 windows.h를 추가했을 때 "byte": 모호한 기호입니다.

에러가 발생하게 되면 C++17에서 추가된 std::byte와 windows.h의 byte와 정의 중복으로 발생한 것으로

프로젝트 속성 >> c/c++전처리기 정의 부분에 _HAS_STD_BYTE=0 을 추가하시면 됩니다.

띄어쓰기 조심하셔야 합니다.

 

이번에는 현재 시간을 알아내는 방법에 대해 알아보겠습니다.

현재 시간을 알아내는 방법은 크게 두가지가 있습니다.

(1) time_t 사용하는 방법

(2) chrono 사용하는 방법

 

하나씩 알아보겠습니다.

 

time_t 사용하는 방법

c언어에서는 time.h에, c++ 언어에서는 ctimetypedef를 통해 정의되어 있어요.

즉, #include <ctime>을 해주셔야 해요. 유닉스와 POSIX 시스템에서는 time_t 를 정수 혹은 부동소수점으로

정의하고 있어요.

이 때 값은 1970년 1월 1일 자정(UTC)에서부터 현재까지 흐른 초수를 의미합니다.

현재 많은 경우 time_t 형을 32비트 정수 형으로 잡고 있는데, 2038년이 되면 32비트 형에서 오버플로우가 발생하여 64비트가 생겨났어요. 2038년 이전까지만 사용하실 꺼면, time_t 를 사용하셔도 되지만 그 이후까지 사용하실꺼면, __time64_t를 사용하시면 됩니다.

 // 'time()' 은 시스템의 현재 시간을 'time_t' type으로 반환해요
std::time_t now1 = std::time(nullptr);
tm tm_1;
// localtime은 'time_t' 값을 달력 시간으로 변환하고
// 멤버가 있는 'tm' 구조체에 대한 포인터를 반환합니다.
localtime_s(&tm_1, &now1);
std::cout << "현재 날짜:" << tm_1.tm_mday << "/" << (tm_1.tm_mon + 1) << "/" << (tm_1.tm_year + 1900) << std::endl;
std::cout << "현재 시간:" << tm_1.tm_hour << ":" << tm_1.tm_min << ":" << tm_1.tm_sec << std::endl;
std::cout << "현재 요일:" << tm_1.tm_wday << std::endl; // 일요일: 0 ~ 토요일: 6
std::cout << "올해 몇번째 날:" << tm_1.tm_yday << std::endl; // 1/1 : 0, 1/2 : 1, ...
std::cout << "서머타임 적용 여부:" << tm_1.tm_isdst << std::endl; // 0이면 서머타임 없음

 __time64_t now2 = _time64(nullptr);   
tm tm_2;
gmtime_s(&tm_2, &now2);
std::cout << "세계 표준 날짜:" << tm_2.tm_mday << "/" << (tm_2.tm_mon + 1) << "/" << (tm_2.tm_year + 1900) << std::endl;
std::cout << "세계 표준 시간:" << tm_2.tm_hour << ":" << tm_2.tm_min << ":" << tm_2.tm_sec << std::endl;

char cStrfTime[64];
strftime(cStrfTime, 64, "%Y년 %m월 %d일 %H시 %M분 %S초\n", &tm_2);
printf(cStrfTime);
 

위 코드 실행 결과는 아래와 같아요.

일부러 세계시간과 우리나라 시간의 날짜가 변동되도록 해서 12시 이후에 돌려본건데.

우리나라가 세계 표준시보다 9시간 빠르죠? 64비트 버전에서도 같은 방법으로 localtime_s를 사용하면

우리나라 local time을 얻어올 수 있어요.

아참. struct tm의 연도에는 +1900을 달에는 +1을 해줘야 해요. tm 구조체 변수 목록은 아래와 같아요

변수
의미
실행 시점의 값
(localtime_s)
실행 시점의 값
(gmtime_s)
tm_year
년(1900년 이후 경과)
123
123
tm_mon
월(0~11)
2
2
tm_mday
일(1~31)
10
9
tm_hour
시(24시)
0
15
tm_min
10
10
tm_sec
36
36
tm_wday
요일(0~6)
5
4
tm_yday
연도의 경과 일수
68
67
tm_isdst
서머 타임
0
0

 

strftime의 포맷 목록은 아래와 같아요. (대소문자를 주의하세요!)

 
포맷
의미
실행 시점의 값
(gmtime_s)
%Y
연도
2023
%m
월(01~12)
03
%B
영어 월(풀네임)
March
%b, %h
영어 월(줄임말)
Mar
%A
영어 요일(풀네임)
Thursday
%a
영어 요일(줄임말)
Thu
%d
일(앞에 0 붙음)
09
%e
일(앞에 0 안붙음)
9
%H
시(24시)
15
%l
시(12시)
3
%M
10
%S
36
%p
AM 또는 PM
PM
%j
연도의 일
068
%y
연도 마지막 2글자
23
chrono 사용하는 방법

chrono는 C++11부터 표준으로 사용되기 시작했어요. chrono 라이브러리에는 기본적으로

system_clocksteady_clock 두 개의 시간 측정 클래스가 존재해요.

1. system_clock

전통적인 유닉스 타임으로 1970년 1월 1일 목요일

0시 0분 0초 이후로 흘러간 시간을 나타내요.

2. steady_clock

OS가 마지막 부팅 이후로 흘러간 시간을 나타내요.

 

현재 시간을 가져올 때에는 system_clock을 사용하는 것이 맞지만 함수의 실행 시간을 측정하기 위해서는 steady_clock을 사용해야 합니다.

이유는, system_clock과 같은 경우 OS 시간 동기화 등에 의해 시간 측정 중에 시간 값이 변할 수 있기 때문인데

steady_clock은 monotonic하게 증가하기 때문에 그럴 가능성이 없습니다.

만약 OS 시간을 과거로 되돌린다면??

system_clock은 음수 값이 나올 수 있다는 얘기입니다.

 

auto now = std::chrono::system_clock::now();
std::time_t end_time = std::chrono::system_clock::to_time_t(now);
char buf[256];
ctime_s(buf, sizeof(buf), &end_time);
std::cout << "현재 시간:" << buf << std::endl;
 

위의 글을 쓰면서 시간이 지나서 현재 시간은, 아래와 같네요.

오늘의 꿀팁!!

chrono를 사용하여 함수 시간 측정 등 초시계를 사용할 때에는 steady_clock을 사용하자!!

함수 시간 측정하는 방법은 아래 글에서 확인하세요

https://m.blog.naver.com/dorergiverny/223052685676

 

[C++] 함수 실행 시간 측정 방법 - chrono 총정리 duration_cast system_clock getTickCount

지난번에 현재 시간 얻는 방법에 대해 언급하면서 chrono에 대해 잠시 알아봤습니다. https://m.blog.naver...

blog.naver.com