C++ duration | "시간 간격" 가이드

C++ duration | "시간 간격" 가이드

이 글의 핵심

C++ duration에 대한 실전 가이드입니다.

들어가며

**std::chrono::duration**은 시간 간격을 표현하는 타입입니다. 타입 안전하고, 단위 변환이 명확하며, 시간 연산을 지원합니다.


1. duration 기본

기본 사용

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    
    // 시간 간격 생성: duration 타입
    // std::chrono::seconds: 초 단위 duration
    seconds sec(10);  // 10초
    // std::chrono::milliseconds: 밀리초 단위 duration
    milliseconds ms(10000);  // 10000밀리초 = 10초
    // std::chrono::minutes: 분 단위 duration
    minutes min(1);  // 1분 = 60초
    // std::chrono::hours: 시간 단위 duration
    hours hr(1);  // 1시간 = 60분 = 3600초
    
    // 값 얻기: count() 메서드로 숫자 값 추출
    std::cout << "초: " << sec.count() << std::endl;  // 10
    std::cout << "밀리초: " << ms.count() << std::endl;  // 10000
    
    return 0;
}

표준 duration 타입

#include <chrono>

// C++11 표준 단위
std::chrono::hours h(1);
std::chrono::minutes m(60);
std::chrono::seconds s(3600);
std::chrono::milliseconds ms(3600000);
std::chrono::microseconds us(3600000000);
std::chrono::nanoseconds ns(3600000000000);

// 모두 1시간을 표현

2. 시간 변환

암시적 변환 (상위 → 하위)

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    
    seconds s(10);  // 10초
    
    // ✅ 상위 → 하위 (암시적 변환 가능)
    // 큰 단위 → 작은 단위: 정보 손실 없음
    // seconds → milliseconds: 10초 = 10000밀리초
    milliseconds ms = s;  // 10000ms (자동 변환)
    // seconds → microseconds: 10초 = 10000000마이크로초
    microseconds us = s;  // 10000000us (자동 변환)
    
    std::cout << "밀리초: " << ms.count() << std::endl;  // 10000
    std::cout << "마이크로초: " << us.count() << std::endl;  // 10000000
    
    return 0;
}

명시적 변환 (하위 → 상위)

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    
    milliseconds ms(1500);  // 1500밀리초 = 1.5초
    
    // ❌ 하위 → 상위 (암시적 불가)
    // 작은 단위 → 큰 단위: 정보 손실 가능 (소수점 버림)
    // seconds s = ms;  // 컴파일 에러: 명시적 변환 필요
    
    // ✅ duration_cast (명시적 변환)
    // duration_cast<seconds>: 밀리초를 초로 변환
    // 1500ms → 1s (500ms 버림, 절삭)
    seconds s = duration_cast<seconds>(ms);  // 1s (절삭)
    
    std::cout << "초: " << s.count() << std::endl;  // 1
    
    return 0;
}

C++17 반올림 함수

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    
    milliseconds ms(1500);  // 1500밀리초 = 1.5초
    
    // duration_cast: 절삭 (소수점 버림)
    // 1.5초 → 1초 (0.5초 버림)
    auto s1 = duration_cast<seconds>(ms);
    std::cout << "절삭: " << s1.count() << "s" << std::endl;  // 1s
    
    // round: 반올림 (C++17)
    // 1.5초 → 2초 (0.5 이상이므로 올림)
    auto s2 = round<seconds>(ms);
    std::cout << "반올림: " << s2.count() << "s" << std::endl;  // 2s
    
    // ceil: 올림 (C++17)
    // 1.5초 → 2초 (무조건 올림)
    auto s3 = ceil<seconds>(ms);
    std::cout << "올림: " << s3.count() << "s" << std::endl;  // 2s
    
    // floor: 내림 (C++17)
    // 1.5초 → 1초 (무조건 내림, duration_cast와 동일)
    auto s4 = floor<seconds>(ms);
    std::cout << "내림: " << s4.count() << "s" << std::endl;  // 1s
    
    return 0;
}

3. 시간 연산

산술 연산

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    
    seconds s1(10);
    seconds s2(5);
    
    // 덧셈
    auto sum = s1 + s2;
    std::cout << "합: " << sum.count() << "s" << std::endl;  // 15s
    
    // 뺄셈
    auto diff = s1 - s2;
    std::cout << "차: " << diff.count() << "s" << std::endl;  // 5s
    
    // 곱셈
    auto mul = s1 * 2;
    std::cout << "곱: " << mul.count() << "s" << std::endl;  // 20s
    
    // 나눗셈
    auto div = s1 / 2;
    std::cout << "나눔: " << div.count() << "s" << std::endl;  // 5s
    
    // 나머지
    auto mod = s1 % s2;
    std::cout << "나머지: " << mod.count() << "s" << std::endl;  // 0s
    
    return 0;
}

비교 연산

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    
    seconds s1(10);
    seconds s2(5);
    milliseconds ms(10000);
    
    std::cout << std::boolalpha;
    std::cout << "s1 > s2: " << (s1 > s2) << std::endl;  // true
    std::cout << "s1 == ms: " << (s1 == ms) << std::endl;  // true (단위 다름)
    
    return 0;
}

4. duration 리터럴 (C++14)

리터럴 사용

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;
    
    // 리터럴로 duration 생성
    auto d1 = 10s;      // seconds
    auto d2 = 500ms;    // milliseconds
    auto d3 = 100us;    // microseconds
    auto d4 = 100ns;    // nanoseconds
    auto d5 = 1min;     // minutes
    auto d6 = 2h;       // hours
    
    // 조합
    auto total = 1h + 30min + 45s + 500ms;
    
    auto total_ms = std::chrono::duration_cast<std::chrono::milliseconds>(total);
    std::cout << "총 시간: " << total_ms.count() << "ms" << std::endl;  // 5445500ms
    
    return 0;
}

5. 자주 발생하는 문제

문제 1: 정밀도 손실

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    
    milliseconds ms(1500);
    
    // ❌ duration_cast: 절삭 (500ms 손실)
    seconds s1 = duration_cast<seconds>(ms);
    std::cout << "절삭: " << s1.count() << "s" << std::endl;  // 1s
    
    // ✅ round: 반올림
    seconds s2 = round<seconds>(ms);
    std::cout << "반올림: " << s2.count() << "s" << std::endl;  // 2s
    
    return 0;
}

문제 2: 타입 불일치

#include <chrono>
#include <iostream>

void waitFor(std::chrono::seconds s) {
    std::cout << s.count() << "초 대기" << std::endl;
}

int main() {
    // ❌ 타입 불일치
    // waitFor(10);  // 컴파일 에러
    
    // ✅ 명시적 생성
    waitFor(std::chrono::seconds(10));
    
    // ✅ 리터럴 (C++14)
    using namespace std::chrono_literals;
    waitFor(10s);
    
    return 0;
}

문제 3: 음수 duration

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    
    seconds s1(5);
    seconds s2(10);
    
    // 음수 duration
    auto diff = s1 - s2;  // -5s
    
    std::cout << "차이: " << diff.count() << "s" << std::endl;  // -5
    
    // 절대값
    auto abs_diff = (diff < seconds::zero()) ? -diff : diff;
    std::cout << "절대값: " << abs_diff.count() << "s" << std::endl;  // 5
    
    return 0;
}

문제 4: 0 duration

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    
    // 0 duration
    seconds s = seconds::zero();
    milliseconds ms = milliseconds::zero();
    
    std::cout << std::boolalpha;
    std::cout << "s == 0: " << (s == seconds::zero()) << std::endl;  // true
    
    return 0;
}

6. 실전 예제: 타이머 유틸리티

#include <chrono>
#include <thread>
#include <iostream>

class Timer {
    using Clock = std::chrono::steady_clock;
    using TimePoint = std::chrono::time_point<Clock>;
    
    TimePoint start;
    
public:
    Timer() : start(Clock::now()) {}
    
    // 경과 시간 (밀리초)
    long long elapsedMs() const {
        auto now = Clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
        return duration.count();
    }
    
    // 경과 시간 (마이크로초)
    long long elapsedUs() const {
        auto now = Clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>(now - start);
        return duration.count();
    }
    
    // 재시작
    void reset() {
        start = Clock::now();
    }
};

int main() {
    Timer timer;
    
    // 작업 1
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "작업 1 완료: " << timer.elapsedMs() << "ms" << std::endl;
    
    // 작업 2
    std::this_thread::sleep_for(std::chrono::milliseconds(200));
    std::cout << "작업 2 완료: " << timer.elapsedMs() << "ms" << std::endl;
    
    // 재시작
    timer.reset();
    
    // 작업 3
    std::this_thread::sleep_for(std::chrono::milliseconds(150));
    std::cout << "작업 3 완료: " << timer.elapsedMs() << "ms" << std::endl;
    
    return 0;
}

출력:

작업 1 완료: 100ms
작업 2 완료: 300ms
작업 3 완료: 150ms

정리

핵심 요약

  1. duration: 시간 간격 표현
  2. count(): 값 얻기
  3. 상위→하위: 암시적 변환
  4. 하위→상위: duration_cast 필요
  5. 연산: +, -, *, /, % 지원
  6. 리터럴: 10s, 500ms (C++14)

duration 변환 규칙

변환방법예시
상위 → 하위암시적milliseconds ms = seconds(10);
하위 → 상위duration_castseconds s = duration_cast<seconds>(ms);
반올림round (C++17)seconds s = round<seconds>(ms);
올림ceil (C++17)seconds s = ceil<seconds>(ms);
내림floor (C++17)seconds s = floor<seconds>(ms);

실전 팁

사용 원칙:

  • 상위→하위는 암시적
  • 하위→상위는 duration_cast
  • 반올림은 round (C++17)
  • 리터럴 사용 (10s, 500ms)

성능:

  • duration_cast는 컴파일 타임
  • 연산은 정수 연산과 동일
  • 타입 안전으로 버그 방지
  • 리터럴로 가독성 향상

주의사항:

  • duration_cast는 절삭 (정밀도 손실)
  • 음수 duration 가능
  • zero(), min(), max() 특수 값
  • 단위 불일치 주의

다음 단계

  • C++ Time Point
  • C++ Chrono
  • C++ Timer Utilities

관련 글

  • C++ Chrono 상세 가이드 |
  • C++ Chrono 완벽 가이드 |
  • C++ Chrono Literals |
  • C++ ratio |
  • C++ steady_clock |