프로그래밍 강좌/C++

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

소프트웨어엔지니어 2023. 7. 24. 10:42

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

보통 로깅을 하기 위해서죠. 다행히 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