7 분 소요

개요

기존에는 날짜/시간 처리를 위해 C스타일의 time, difftime만 제공되었으나(C스타일 시간 유틸리티 참고),

C++11 부터 STL 에서는 좀더 다양한 정확도로 시간을 추적할 수 있는 chrono 라이브러리가 추가되었습니다.

<chrono> 헤더 파일을 포함해야 하며, std::chrono 네임스페이스를 사용합니다.

다음 예는 주어진 함수의 실행 시간을 측정하는 예입니다.

  1. Measure()함수는 전달된 함수를 실행하고 실행 시간을 측정합니다. 실행시킬 함수에 인자를 전달하기 위해 가변 템플릿을 사용합니다.
  2. system_clock::now()를 이용하여 time_point를 구합니다.
  3. 구해진 time_pointmicrosecond 타입으로 저장합니다.
  4. time_point간의 차를 duration으로 변환합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template<typename Func, typename... Params>
std::chrono::microseconds Measure(Func func, Params&&... params) {
    // func 실행전 time_point 측정
    std::chrono::system_clock::time_point start{std::chrono::system_clock::now()};    

    // func 실행
    func(std::forward<Params>(params)...);

    // func 실행 후 time_point 측정
    std::chrono::system_clock::time_point end{std::chrono::system_clock::now()};

    // 두 time_point 간의 차
    std::chrono::microseconds val{std::chrono::duration_cast<std::chrono::microseconds>(end - start)};

    return val;
}
void MyFunc() {}
std::chrono::microseconds duration{Measure(MyFunc)};

std::cout << "MyFunc() : " << duration.count() << std::endl;

Clock

항목 내용
system_clock (C++11~) 시스템 시계입니다.
steady_clock (C++11~) 조정되지 않는 시계입니다.
high_resolution_clock (C++11~) 사용 가능한 가장 짧은 틱 주기를 갖는 시계입니다.
is_clock (C++20~)
is_clock_v (C++20~)
Clock인지 검사합니다.
utc_clock (C++20~) 1970년 1월 1일 00:00:00 UTC부터 흐른 시간을 측정하는 시계입니다.
tai_clock (C++20~) International Atomic Time을 위한 시계로서, 1958년 1월 1일 00:00:00부터 흐른 시간을 측정하는 시계입니다.
gps_clock (C++20~) Global Positioning System을 위한 시계로서, 1980년 1월 6일 00:00:00 UTC부터 흐른 시간을 측정하는 시계입니다.
file_clock (C++20~) 파일 시간을 위한 시계입니다.
local_t (C++20~) 지역 시간을 표현하기 위한 시계입니다.

system_clock은 다음의 멤버 함수가 있습니다.

항목 내용
now() (C++11~) 현재 time_point를 UTC 시간대로 리턴합니다.
to_time_t() (C++11~) time_t타입으로 변환합니다.
from_time_t() (C++11~) time_t타입에서 가져옵니다.

Time Point

시작 시간 이후 경과된 값입니다.

항목 내용
time_point (C++11~) 특정 시점을 나타냅니다.
clock_time_conversion (C++11~) (작성중)
clock_cast (C++11~) (작성중)

time_point는 다음의 멤버 함수가 있습니다.

항목 내용
time_since_epoch() (C++11~) (작성중)
min() (C++11~) (작성중)
max() (C++11~) (작성중)
time_point_cast() (작성중)
+, - (C++11~) (작성중)
++, -- (C++11~)
(작성중)
+=, -= (C++11~) (작성중)
+=, -=, *=, /=, %= (C++11~) (작성중)
+, -, *, /, % (C++11~) (작성중)
== (C++11~)
!= (C++11~C++20)
(작성중)
<, <=, >, >= (C++11~)
<=> (C++20~)
(작성중)

Duration

항목 내용
duration (C++11~) 기간입니다. 두 Time Point의 차입니다.

duration은 다음의 멤버 함수가 있습니다.

항목 내용
= (C++11~) (작성중)
count() (C++11~) (작성중)
zero() (C++11~) (작성중)
min() (C++11~) (작성중)
max() (C++11~) (작성중)
duration_cast() (C++11~) (작성중)
from_stream() (C++20~) 스트림으로부터 duration을 구합니다.
+, - (C++11~) (작성중)
++, -- (C++11~)
(작성중)
+=, -=, *=, /=, %= (C++11~) (작성중)
+, -, *, /, % (C++11~) (작성중)
== (C++11~)
!= (C++11~C++20)
(작성중)
<, <=, >, >= (C++11~)
<=> (C++20~)
(작성중)
<< (C++20~) (작성중)

다음과 같이 타입이 재정의 되어 있습니다.(int뒤 XX는 최소 필요 비트수입니다.)

항목 내용
nanoseconds (C++11~) duration<int64, std::nano>
microseconds (C++11~) duration<int54, std::micro>
milliseconds (C++11~) duration<int44, std::milli>
seconds (C++11~) duration<int35>
minutes (C++11~) duration<int29, std::ratio<60>>
hours (C++11~) duration<int23, std::ratio<3600>>
days (C++20~) duration<int25, std::ratio<86400>>
weeks (C++20~) duration<int22, std::ratio<604800>>
month (C++20~) duration<int20, std::ratio<2629746>>
years (C++20~) duration<int17, std::ratio<31556952>>

다음의 유틸리티가 제공됩니다.

항목 내용
treat_as_floating_point (C++11~) (작성중)
treat_as_floating_point (C++11~) (작성중)
duration_values (C++11~) (작성중)

(C++17~) floor(), ceil(), round(), abs()

항목 내용
floor() (C++17~) time_pointduration을 내림합니다.
ceil() (C++17~) time_pointduration올림합니다.
round() (C++17~) time_pointduration반올림합니다.
abs() (C++17~) duration의 절대값을 구합니다.

(C++20~) hh_mm_ss

항목 내용
hh_mm_ss (C++20~) 자정부터 지난 시간의 시/분/초입니다.
is_am() (C++20~)
is_pm() (C++20~)
make12() (C++20~)
make24() (C++20~)
12시간/24시간 서식을 적용합니다.

다음은 hh_mm_ss의 사용예입니다. 표준 사용자 정의 리터럴을 사용하기 위해 using namespace std::chrono를 사용했습니다.

1
2
3
4
5
6
7
8
9
10
11
using namespace std::chrono; // ""h, ""min, ""s사용을 위해 using namespace를 사용합니다. 
constexpr std::chrono::hh_mm_ss time{12h + 72min + 3s};

static_assert(time.hours() == 13h); // 12h에서 72min을 더해서 13h 12min이 되었습니다.
static_assert(time.minutes() == 12min);
static_assert(time.seconds() == 3s);

static_assert(std::chrono::is_am(13h) == false);
static_assert(std::chrono::is_pm(13h) == true);
static_assert(std::chrono::make12(13h) == 1h);
static_assert(std::chrono::make24(1h, true) == 13h); // pm 1h를 24시간 서식으로 변경하여 13h가 되었습니다. 

(C++20~) Calendar

auto date{year(2023)/month(12)/day(25)};와 같이 특정 년-월-일을 표현합니다.

항목 내용
last_spec (C++20~) 한달의 말일 또는 마지막 요일임을 나타냅니다. last가 미리 정의되어 있습니다.
day (C++20~) 일을 나타냅니다.
month (C++20~) 월을 나타냅니다. January, February, March, April, May, June, July, August, September, October, November, December가 미리 정의되어 있습니다.
year (C++20~) 년을 나타냅니다.
weekday (C++20~) 요일을 나타냅니다. Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Satureday가 미리 정의되어 있습니다.
weekday_indexed (C++20~) 특정월의 N번째 요일을 나타냅니다.
weekday_last (C++20~) 특정월의 마지막 요일을 나타냅니다.
month_day (C++20~) 월-일을 나타냅니다. 월일, 일월의 형태로 초기화할 수 있습니다.
month_day_last (C++20~) 월-마지막날을 나타냅니다.
month_weekday (C++20~) 월-요일을 나타냅니다.
month_weekday_last (C++20~) 월-마지막 요일를 나타냅니다.
year_month (C++20~) 년-월을 나타냅니다.
year_month_day (C++20~) 년-월-일을 나타냅니다. 년월일, 일월년, 월일년의 형태로 초기화할 수 있습니다.
year_month_day_last (C++20~) 년-월-마지막날을 나타냅니다.
year_month_weekday (C++20~) 년-월-요일을 나타냅니다.
year_month_weekday_last (C++20~) 년-월-마지막 요일을 나타냅니다.
operator / (C++20~) 년/월/일등의 형태의 표시를 지원합니다.

요일과 월은 다음과 같이 미리 정의되어 있습니다.

1
2
static_assert(std::chrono::Sunday == std::chrono::weekday(0)); // 각 요일은 미리 정의되었습니다.
static_assert(std::chrono::December == std::chrono::month(12)); // 각월은 미리 정의되었습니다.

다음과 같이year_month_day로 특정한 날을 표현할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
// 년, 월, 일을 전달합니다.
std::chrono::year_month_day yearMonthDay1{std::chrono::year{2023}, std::chrono::month{12}, std::chrono::day{25}};

// / 표기를 사용하여 년월일을 합성해서 사용할 수 있습니다.
std::chrono::year_month_day yearMonthDay2{std::chrono::year{2023}/std::chrono::month{12}/std::chrono::day{25}};
std::chrono::year_month_day yearMonthDay3{std::chrono::day{25}/std::chrono::month{12}/std::chrono::year{2023}};
std::chrono::year_month_day yearMonthDay4{std::chrono::month{12}/std::chrono::day{25}/std::chrono::year{2023}};

using namespace std::chrono; // 표준 사용자 정의 리터럴인 2023y, 25d를 사용하기 위해서 추가합니다.
std::chrono::year_month_day yearMonthDay5{2023y/std::chrono::December/25d};

(C++20~) operator ““y, operator ““d가 추가되어 year, day 표현이 간편해 졌습니다.

last_spec은 마지막 날이나 마지막 요일을 나타내는 타입이며, 미리 정의된 last 개체를 사용합니다.

1
2
3
// 2023년 12월의 마지막 날
std::chrono::year_month_day date{std::chrono::year{2023}/std::chrono::month{12}/std::chrono::last};
EXPECT_TRUE(date.day() == std::chrono::day{31});

다음 예는 year_month_day, year_month_weekday_last, year_month_weekday를 상호 변환하여 특정 요일에 해당하는 날짜나 특정일에 해당하는 요일을 구합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
    // 2023년 11월의 마지막 일요일
    std::chrono::year_month_weekday_last date1{std::chrono::year{2023}/std::chrono::month{11}/std::chrono::Sunday[std::chrono::last]}; 
    std::chrono::year_month_day date2{date1};
    EXPECT_TRUE(date2.day() == std::chrono::day{26}); // 2023년 11월의 마지막 일요일은 26일입니다.
}
{
    // 2023년 11월의 2번째 일요일
    std::chrono::year_month_weekday date1{std::chrono::year{2023}/std::chrono::month{11}/std::chrono::Sunday[2]}; 
    std::chrono::year_month_day date2{date1};
    EXPECT_TRUE(date2.day() == std::chrono::day{12}); // 2023년 11월의 두번째 일요일은 12일입니다.
}
{
    // 2번째 일요일
    std::chrono::weekday_indexed week{std::chrono::Sunday, 2};

    // 2023년 11월의 2번째 일요일
    std::chrono::year_month_weekday date1{std::chrono::year{2023}/std::chrono::month{11}/week}; 
    std::chrono::year_month_day date2{date1};
    EXPECT_TRUE(date2.day() == std::chrono::day{12}); // 2023년 11월의 두번째 일요일은 12일입니다.            
}
{
    // 2023년 11월 21일
    std::chrono::year_month_day date1{std::chrono::year{2023}/std::chrono::month{11}/std::chrono::day{21}};
    std::chrono::year_month_weekday date2{date1};
    EXPECT_TRUE(date2.weekday() == std::chrono::Tuesday); // 목요일입니다.
    EXPECT_TRUE(date2.weekday_indexed() == std::chrono::Tuesday[3]); // 3번째 목요일입니다.
}  

now()로부터 달력 날짜 초기화

now()nanoseconds단위로 현재 time_point구하는데요, 이를 floor()를 이용하여 days단위로 변경하면, year_month_day에 저장할 수 있습니다.

1
2
std::chrono::time_point now{std::chrono::system_clock::now()}; // now()는 nanoseconds 단위로 timpoint를 구합니다.
std::chrono::year_month_day date{std::chrono::floor<std::chrono::days>(now)}; // now를 days단위로 구하여 년-월-일 단위로 저장합니다.

local_days(), sys_days() 형변환 연산자

달력 날짜인 year_month_day, year_month_day_last, year_month_weekday, year_month_weekday_lastlocal_days()local_days() 형변환 연산자를 이용하여 time_point로 변환할 수 있습니다.

다음 예는 두개의 달력 날짜의 차이를 구하는 예입니다. 달력 날짜끼리 직접 -을 할 수 없기 때문에, time_point로 변환하여 차이를 구합니다. days기반 이기 때문에 5d가 출력됩니다.

1
2
3
4
5
6
7
8
9
// 2023년 12월 25일
std::chrono::year_month_day date1{std::chrono::year{2023}/std::chrono::month{12}/std::chrono::day{25}};

// 2023년 12월 20일
std::chrono::year_month_day date2{std::chrono::year{2023}/std::chrono::month{12}/std::chrono::day{20}};

std::chrono::days duration{std::chrono::sys_days(date1) - std::chrono::sys_days(date2)}; // 두 달력 날짜의 차이를 구하기 위해 time_point로 변환합니다.

std::cout << duration << std::endl; // 5d 

유효성 검사

ok() 멤버 함수로 유효성 검사를 할 수 있습니다. 윤년이 있더라도 잘 검사해 줍니다.

1
2
3
4
5
6
7
8
std::chrono::day day29{29};
EXPECT_TRUE(day29.ok() == true);

std::chrono::year_month_day date1{std::chrono::year{2023}/std::chrono::month{2}/day29};
EXPECT_TRUE(date1.ok() == false); // 2023/2/30은 유효하지 않습니다. 28일까지 있습니다.

std::chrono::year_month_day date2{std::chrono::year{2024}/std::chrono::month{2}/day29};
EXPECT_TRUE(date2.ok() == true); // 2023/2/29는 유효합니다. 29일까지 있습니다.

(C++20~) Time Zone

항목 내용
tzdb (C++20~) 시간대 데이터베이스 입니다.
tzdb_list (C++20~) tzdb 목록입니다.
get_tzdb() (C++20~)
get_tzdb_list() (C++20~)
reload_tzdb() (C++20~)
remote_version() (C++20~)
전역 시간대 데이터베이스를 관리합니다.
locate_zone() (C++20~) 주어진 이름의 time_zone을 구합니다.
current_zone() (C++20~) 현재 time_zone을 구합니다.
time_zone (C++20~) 시간대를 나타냅니다.
sys_info (C++20~) (작성중)
locale_info (C++20~) (작성중)
choose (C++20~) (작성중)
zoned_traits (C++20~) (작성중)
zoned_time (C++20~) 지정한 시간대의 시간을 나타냅니다.
leap_second (C++20~) (작성중)
leap_second_info (C++20~) (작성중)
get_leap_second_info (C++20~) (작성중)
time_zone_link (C++20~) (작성중)
nonexistent_local_time (C++20~) 지역 시간대를 구할 수 없습니다.
ambiguous_local_time (C++20~) 지역 시간대가 모호합니다.

now()는 UTC 시간대로 리턴하는데요, zoned_time를 이용하면, 특정 지역의 시간대로 변환할 수 있습니다.

다음은 now()를 이용하여 UTC 시간을 구한뒤, America/New_York, Asia/Shanghai, Asia/Seoul로 변환하여 format()으로 출력한 예입니다. 서식 지정은 chrono 서식 지정자를 참고하시기 바랍니다.(시간대 이름은 https://www.iana.org/time-zones을 참고하시길 바랍니다.)

1
2
3
4
5
6
7
8
9
10
11
auto utcTime{std::chrono::system_clock::now()};
std::cout << "utcTime : " << std::format("{:%Y/%m/%d %H:%M:%S}", utcTime) << std::endl; // 2023/12/17 13:25:45.131857000

std::chrono::zoned_time newyork{"America/New_York", utcTime};
std::cout << "localTime : " << std::format("{:%Y/%m/%d %H:%M:%S}", newyork) << std::endl; // 2023/12/17 08:25:45.131857000

std::chrono::zoned_time shanghai{"Asia/Shanghai", utcTime};
std::cout << "localTime : " << std::format("{:%Y/%m/%d %H:%M:%S}", shanghai) << std::endl; // 2023/12/17 21:25:45.131857000

std::chrono::zoned_time seoul{"Asia/Seoul", utcTime};
std::cout << "localTime : " << std::format("{:%Y/%m/%d %H:%M:%S}", seoul) << std::endl; // 2023/12/17 22:25:45.131857000

(C++20~) chrono 서식 지정자가 추가되었습니다.

(C++20~) parse()

(작성중)

스트림 개체로부터 크로노 개체를 생성합니다.

태그:

카테고리:

업데이트:

댓글남기기