[2026] C++ Chrono Literals | 시간 리터럴 가이드

[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;
}

리터럴 타입

리터럴타입설명
100nsstd::chrono::nanoseconds나노초 (10⁻⁹초)
100usstd::chrono::microseconds마이크로초 (10⁻⁶초)
100msstd::chrono::milliseconds밀리초 (10⁻³초)
5sstd::chrono::seconds
10minstd::chrono::minutes
2hstd::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;
    }
}

정리

핵심 요약

  1. 리터럴 종류: ns, us, ms, s, min, h
  2. namespace: std::chrono_literals 필수
  3. 연산: 덧셈, 뺄셈, 곱셈, 나눗셈, 비교
  4. 변환: duration_cast로 단위 변환
  5. C++20: 날짜 리터럴 (y, d)

chrono 리터럴 장단점

장점단점
가독성 향상namespace 선언 필요
타입 안전C++14 이상 필요
간결한 코드헤더에서 using 주의
컴파일 타임 체크큰 값 오버플로우 주의

실전 팁

  1. namespace 사용
    • 함수 내부나 cpp 파일에서만 using namespace 사용
    • 헤더 파일에서는 명시적 호출 사용
  2. 타입 변환
    • 정밀도 손실 주의 (1500msseconds)
    • duration_cast로 명시적 변환
  3. 성능
    • 리터럴은 컴파일 타임에 처리됨
    • 런타임 오버헤드 없음

다음 단계


관련 글

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3