[2026] C++ Chrono Literals | 시간 리터럴 가이드
이 글의 핵심
C++14 chrono 리터럴(1s, 500ms, 2h 등)로 duration을 읽기 쉽게 쓰는 방법. std::chrono_literals, 단위 연산과 실전 예제를 다룹니다.
들어가며
C++14의 chrono 리터럴은 시간 값을 간결하고 읽기 쉽게 표현할 수 있게 해줍니다. std::chrono::milliseconds(500) 대신 500ms로 작성할 수 있습니다.
실무에서 마주한 현실
개발을 배울 때는 모든 게 깔끔하고 이론적입니다. 하지만 실무는 다릅니다. 레거시 코드와 씨름하고, 급한 일정에 쫓기고, 예상치 못한 버그와 마주합니다. 이 글에서 다루는 내용도 처음엔 이론으로 배웠지만, 실제 프로젝트에 적용하면서 “아, 이래서 이렇게 설계하는구나” 하고 깨달은 것들입니다. 특히 기억에 남는 건 첫 프로젝트에서 겪은 시행착오입니다. 책에서 배운 대로 했는데 왜 안 되는지 몰라 며칠을 헤맸죠. 결국 선배 개발자의 코드 리뷰를 통해 문제를 발견했고, 그 과정에서 많은 걸 배웠습니다. 이 글에서는 이론뿐 아니라 실전에서 마주칠 수 있는 함정들과 해결 방법을 함께 다루겠습니다.
1. chrono 리터럴 기본
리터럴 종류
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <chrono>
using namespace std::chrono_literals;
int main() {
// 시간 리터럴
auto ns = 100ns; // nanoseconds (나노초)
auto us = 100us; // microseconds (마이크로초)
auto ms = 100ms; // milliseconds (밀리초)
auto s = 5s; // seconds (초)
auto min = 10min; // minutes (분)
auto h = 2h; // hours (시간)
std::cout << "5초: " << s.count() << "s" << std::endl;
std::cout << "10분: " << min.count() << "min" << std::endl;
std::cout << "2시간: " << h.count() << "h" << std::endl;
}
리터럴 타입
| 리터럴 | 타입 | 설명 |
|---|---|---|
100ns | std::chrono::nanoseconds | 나노초 (10⁻⁹초) |
100us | std::chrono::microseconds | 마이크로초 (10⁻⁶초) |
100ms | std::chrono::milliseconds | 밀리초 (10⁻³초) |
5s | std::chrono::seconds | 초 |
10min | std::chrono::minutes | 분 |
2h | std::chrono::hours | 시간 |
| 핵심 개념: |
- namespace:
std::chrono_literals필수 - 타입 안전: 컴파일 타임에 타입 체크
- 가독성: 코드가 명확하고 간결함
2. 시간 연산
기본 연산
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <chrono>
using namespace std::chrono_literals;
int main() {
// 덧셈
auto total = 1h + 30min + 45s;
// 뺄셈
auto diff = 2h - 30min;
// 곱셈
auto doubled = 5s * 2;
// 나눗셈
auto half = 10min / 2;
// 비교
if (500ms < 1s) {
std::cout << "500ms는 1초보다 짧습니다" << std::endl;
}
}
단위 변환
#include <iostream>
#include <chrono>
using namespace std::chrono_literals;
int main() {
auto total = 1h + 30min + 45s;
// 초로 변환
auto totalSeconds = std::chrono::duration_cast<std::chrono::seconds>(total);
std::cout << "총 " << totalSeconds.count() << "초" << std::endl;
// 출력: 총 5445초
// 밀리초로 변환
auto totalMs = std::chrono::duration_cast<std::chrono::milliseconds>(total);
std::cout << "총 " << totalMs.count() << "ms" << std::endl;
// 출력: 총 5445000ms
// 분으로 변환 (소수점 버림)
auto totalMin = std::chrono::duration_cast<std::chrono::minutes>(total);
std::cout << "총 " << totalMin.count() << "분" << std::endl;
// 출력: 총 90분
}
3. 실전 예제
예제 1: sleep
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
int main() {
std::cout << "시작" << std::endl;
// 기존 방식 (복잡)
// std::this_thread::sleep_for(std::chrono::seconds(2));
// 리터럴 사용 (간결)
std::this_thread::sleep_for(2s);
std::cout << "2초 후" << std::endl;
// 밀리초 단위
std::this_thread::sleep_for(500ms);
std::cout << "0.5초 후" << std::endl;
}
예제 2: 타임아웃
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
using namespace std::chrono_literals;
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::this_thread::sleep_for(1s);
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
}
cv.notify_one();
}
int main() {
std::thread t(worker);
std::unique_lock<std::mutex> lock(mtx);
// 500ms 대기
if (cv.wait_for(lock, 500ms, []{ return ready; })) {
std::cout << "준비 완료" << std::endl;
} else {
std::cout << "타임아웃 (500ms)" << std::endl;
}
// 2초 대기
if (cv.wait_for(lock, 2s, []{ return ready; })) {
std::cout << "준비 완료" << std::endl;
}
t.join();
}
예제 3: 타이머 클래스
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <chrono>
#include <thread>
using namespace std::chrono_literals;
class Timer {
std::chrono::steady_clock::time_point start;
public:
Timer() : start(std::chrono::steady_clock::now()) {}
// 경과 시간 확인
template<typename Duration>
bool elapsed(Duration timeout) const {
auto now = std::chrono::steady_clock::now();
return now - start >= timeout;
}
// 경과 시간 반환
auto getElapsed() const {
auto now = std::chrono::steady_clock::now();
return now - start;
}
// 리셋
void reset() {
start = std::chrono::steady_clock::now();
}
};
int main() {
Timer timer;
int count = 0;
// 5초 동안 작업
while (!timer.elapsed(5s)) {
std::this_thread::sleep_for(100ms);
count++;
if (count % 10 == 0) {
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(
timer.getElapsed()
);
std::cout << elapsed.count() << "초 경과..." << std::endl;
}
}
std::cout << "5초 경과, 총 " << count << "번 실행" << std::endl;
}
4. C++20 날짜 리터럴
날짜 리터럴 사용
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <chrono>
using namespace std::chrono;
using namespace std::chrono_literals;
int main() {
// 날짜 리터럴 (C++20)
auto year = 2026y;
auto day = 29d;
// 날짜 생성
auto date = 2026y / March / 29d;
std::cout << date << std::endl;
// 2026-03-29
// 시간과 날짜 결합
auto datetime = sys_days{2026y / March / 29d} + 14h + 30min;
}
날짜 연산
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <chrono>
using namespace std::chrono;
using namespace std::chrono_literals;
int main() {
auto today = 2026y / March / 29d;
// 날짜 덧셈
auto nextWeek = sys_days{today} + days{7};
auto nextMonth = sys_days{today} + months{1};
// 날짜 차이
auto date1 = sys_days{2026y / March / 1d};
auto date2 = sys_days{2026y / March / 29d};
auto diff = date2 - date1;
std::cout << "차이: " << diff.count() << "일" << std::endl;
// 차이: 28일
}
5. 자주 발생하는 문제
문제 1: namespace 누락
아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <chrono>
int main() {
// ❌ namespace 없음
// auto sec = 5s; // 컴파일 에러
// ✅ namespace 사용
using namespace std::chrono_literals;
auto sec = 5s;
// ✅ 또는 명시적 호출
auto sec2 = std::chrono_literals::operator""s(5);
}
에러 메시지:
error: unable to find numeric literal operator 'operator""s'
문제 2: 타입 추론
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <chrono>
using namespace std::chrono_literals;
int main() {
// auto: 정확한 타입 추론
auto ms = 100ms; // std::chrono::milliseconds
// 명시적 타입
std::chrono::milliseconds ms2 = 100ms;
// 암묵적 변환
std::chrono::seconds sec = 1000ms; // 1초
// ❌ 정밀도 손실
// std::chrono::seconds sec2 = 1500ms; // 컴파일 에러 (1.5초)
// ✅ duration_cast 사용
auto sec3 = std::chrono::duration_cast<std::chrono::seconds>(1500ms);
std::cout << sec3.count() << "초" << std::endl; // 1초 (버림)
}
문제 3: 오버플로우
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <chrono>
#include <iostream>
using namespace std::chrono_literals;
int main() {
// ❌ 큰 값 주의 (오버플로우 가능)
// auto days = 365 * 24h; // int 오버플로우
// ✅ 명시적 타입 사용
auto hours = std::chrono::hours(365 * 24);
// ✅ 또는 리터럴 먼저 사용
auto oneDay = 24h;
auto year = oneDay * 365;
auto totalHours = std::chrono::duration_cast<std::chrono::hours>(year);
std::cout << "1년: " << totalHours.count() << "시간" << std::endl;
}
문제 4: 혼합 연산
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <chrono>
#include <iostream>
using namespace std::chrono_literals;
int main() {
// 다른 단위 연산 (자동 변환)
auto total = 1h + 30min + 45s;
// 가장 작은 단위로 자동 변환됨 (초)
std::cout << "타입: " << typeid(total).name() << std::endl;
// 명시적 변환
auto totalMs = std::chrono::duration_cast<std::chrono::milliseconds>(total);
std::cout << totalMs.count() << "ms" << std::endl;
// 비교 연산 (자동 변환)
if (500ms < 1s) {
std::cout << "500ms는 1초보다 짧습니다" << std::endl;
}
}
6. 가독성 향상 패턴
기존 방식 vs 리터럴
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <thread>
#include <chrono>
using namespace std::chrono_literals;
int main() {
// ❌ 기존 방식 (읽기 어려움)
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::this_thread::sleep_for(std::chrono::seconds(2));
std::this_thread::sleep_for(std::chrono::minutes(5));
// ✅ 리터럴 사용 (간결하고 명확)
std::this_thread::sleep_for(500ms);
std::this_thread::sleep_for(2s);
std::this_thread::sleep_for(5min);
// ❌ 복잡한 계산
auto timeout = std::chrono::seconds(60 * 5);
// ✅ 명확한 의도
auto timeout2 = 5min;
// ✅ 복잡한 시간 표현
auto duration = 1h + 30min + 45s;
}
실전 활용
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
#include <iostream>
#include <chrono>
#include <thread>
// 필요한 모듈 import
using namespace std::chrono_literals;
// 재시도 로직
template<typename Func>
bool retryWithTimeout(Func func, std::chrono::milliseconds timeout) {
auto start = std::chrono::steady_clock::now();
while (true) {
if (func()) {
return true;
}
auto elapsed = std::chrono::steady_clock::now() - start;
if (elapsed >= timeout) {
return false;
}
std::this_thread::sleep_for(100ms);
}
}
int main() {
int attempt = 0;
bool success = retryWithTimeout([&]() {
attempt++;
std::cout << "시도 " << attempt << std::endl;
return attempt >= 3; // 3번째에 성공
}, 5s);
if (success) {
std::cout << "성공!" << std::endl;
} else {
std::cout << "타임아웃" << std::endl;
}
}
정리
핵심 요약
- 리터럴 종류:
ns,us,ms,s,min,h - namespace:
std::chrono_literals필수 - 연산: 덧셈, 뺄셈, 곱셈, 나눗셈, 비교
- 변환:
duration_cast로 단위 변환 - C++20: 날짜 리터럴 (
y,d)
chrono 리터럴 장단점
| 장점 | 단점 |
|---|---|
| 가독성 향상 | namespace 선언 필요 |
| 타입 안전 | C++14 이상 필요 |
| 간결한 코드 | 헤더에서 using 주의 |
| 컴파일 타임 체크 | 큰 값 오버플로우 주의 |
실전 팁
- namespace 사용
- 함수 내부나 cpp 파일에서만
using namespace사용 - 헤더 파일에서는 명시적 호출 사용
- 함수 내부나 cpp 파일에서만
- 타입 변환
- 정밀도 손실 주의 (
1500ms→seconds) duration_cast로 명시적 변환
- 정밀도 손실 주의 (
- 성능
- 리터럴은 컴파일 타임에 처리됨
- 런타임 오버헤드 없음