C ++ std :: chrono :: time_point를 long 및 back으로 변환하는 방법


83

나는 변환 할 필요 std::chrono::time_point로하고,에서 long유형 (정수 64 비트). 나는 일을 시작하고 있습니다 std::chrono...

내 코드는 다음과 같습니다.

int main ()
{
     std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

    auto epoch = now.time_since_epoch();
    auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
    long duration = value.count();


    std::chrono::duration<long> dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

이 코드는 컴파일되지만 성공하지는 않습니다.

마지막 dt과 다른 이유는 무엇 now입니까?

그 코드에 무엇이 빠졌습니까?


1
나는 chrono 라이브러리에 너무 익숙하지 않지만 사용해야한다고 생각 std::chrono::duration<long,std::milli> dur하며 그 후에도 반올림 오류가 발생할 수 있습니다 ( std::chrono::system_clock아마도 밀리 초보다 높은 해상도 를 가짐 ).
MikeMB 2015

@MikeMB 합리적으로 새로운 하드웨어의 모든 클럭은 어쨌든 마이크로 초 / 마이크로 초 미만의 정밀도를 가져야합니다. The Three Clocks 제목 기사를 참조하십시오 . 실제로 창은 일반적으로 더 높은 정밀도 system_clock(약 100 배 더 큼)를 갖지만 이조 차도 일반적으로 마이크로 초 미만입니다.
Werlious

답변:


164
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();

다음을위한 좋은 장소입니다 auto.

auto now = std::chrono::system_clock::now();

millisecond정확한 트래픽을 원하기 때문에 다음에서 은밀하게 진행하는 것이 좋습니다 time_point.

auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

now_mstime_point기반으로 system_clock하지만 정밀도 milliseconds대신 정밀도를 사용합니다 system_clock.

auto epoch = now_ms.time_since_epoch();

epoch이제 유형이 std::chrono::milliseconds있습니다. 그리고 다음 문장은 본질적으로 no-op이됩니다 (간단히 복사하고 변환하지 않음).

auto value = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);

여기:

long duration = value.count();

귀하와 내 코드 모두 에서 에포크 이후의 duration수를 보유합니다.millisecondssystem_clock .

이:

std::chrono::duration<long> dur(duration);

, 및 정밀도로 duration표현 된을 만듭니다 . 이것은 효과적으로 은 S 에 보류를 에 . 논리 오류입니다. 올바른 코드는 다음과 같습니다.longsecondsreinterpret_castmillisecondsvalueseconds

std::chrono::milliseconds dur(duration);

이 줄 :

std::chrono::time_point<std::chrono::system_clock> dt(dur);

의 기본 정밀도 (일반적으로 밀리 초보다 미세함)에 정밀도를 유지하는 기능을 사용하여을 time_point기반으로를 만듭니다 . 그러나 런타임 값은 정수 밀리 초가 유지됨을 올바르게 반영합니다 (유형에 대한 수정을 가정 ).system_clocksystem_clockdur

수정을해도이 테스트는 (거의 항상) 실패합니다.

if (dt != now)

때문에이 dt의 정수를 보유하고 milliseconds있지만, now(A)보다 틱 미세한의 정수 보유 millisecond(예 : microseconds또는 nanoseconds). 따라서 system_clock::now()정수 를 반환 한 드문 경우에만 milliseconds테스트가 통과됩니다.

그러나 대신 다음을 수행 할 수 있습니다.

if (dt != now_ms)

이제 예상 한 결과를 안정적으로 얻을 수 있습니다.

함께 모아서:

int main ()
{
    auto now = std::chrono::system_clock::now();
    auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    std::chrono::milliseconds dur(duration);

    std::chrono::time_point<std::chrono::system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

개인적으로 나는 모든 std::chrono지나치게 장황한 것을 발견 하므로 다음과 같이 코딩합니다.

int main ()
{
    using namespace std::chrono;
    auto now = system_clock::now();
    auto now_ms = time_point_cast<milliseconds>(now);

    auto value = now_ms.time_since_epoch();
    long duration = value.count();

    milliseconds dur(duration);

    time_point<system_clock> dt(dur);

    if (dt != now_ms)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

안정적으로 출력됩니다.

Success.

마지막으로 임시 time_point유형을 제거하여 및 적분 유형 간의 코드 변환을 최소화하는 것이 좋습니다 . 이러한 변환은 위험하므로 베어 정수 유형을 조작하는 코드를 적게 작성할수록 좋습니다.

int main ()
{
    using namespace std::chrono;
    // Get current time with precision of milliseconds
    auto now = time_point_cast<milliseconds>(system_clock::now());
    // sys_milliseconds is type time_point<system_clock, milliseconds>
    using sys_milliseconds = decltype(now);
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    sys_milliseconds dt{milliseconds{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

위의 주요 위험이되고 있지 해석 integral_duration으로 millisecondsA와 방식 뒷면에 time_point. 이러한 위험을 완화하는 한 가지 가능한 방법은 다음과 같이 작성하는 것입니다.

    sys_milliseconds dt{sys_milliseconds::duration{integral_duration}};

이렇게하면 sys_milliseconds나가는 도중과 다시 들어오는 두 곳에서 사용하는 것만으로도 위험을 줄일 수 있습니다 .

그리고 하나 더 예 : 귀하에게 어떤 기간 나타내는 정수로 변환 할하자 말 system_clock지원 (마이크로, 10 마이크로 또는 나노 초)를. 그러면 위와 같이 밀리 초를 지정하는 것에 대해 걱정할 필요가 없습니다. 코드는 다음과 같이 단순화됩니다.

int main ()
{
    using namespace std::chrono;
    // Get current time with native precision
    auto now = system_clock::now();
    // Convert time_point to signed integral type
    auto integral_duration = now.time_since_epoch().count();
    // Convert signed integral type to time_point
    system_clock::time_point dt{system_clock::duration{integral_duration}};
    // test
    if (dt != now)
        std::cout << "Failure." << std::endl;
    else
        std::cout << "Success." << std::endl;
}

이것은 작동하지만 한 플랫폼에서 변환의 절반 (적분으로)을 실행하고 다른 플랫폼에서 나머지 절반 (적분에서 입력)을 실행 system_clock::duration하면 두 변환에 대해 다른 정밀도를 가질 위험 이 있습니다.


1
@BrentNash : 조심하세요. ;-) 나는 Cppcon 2015 ( cppcon.org ) 에서 이것 에 대해 이야기 할 것입니다 : howardhinnant.github.io/date_v2.html . 주제는 time_point_cast<milliseconds>(now)위의 대답에서 와 매우 밀접한 관련이 있습니다. 기간 만 코스 : time_point_cast<days>(now).
Howard Hinnant

마지막 댓글의 오타 : 코스가 아닌 거친. 그래도 좋은 대답.
Dirk Eddelbuettel

2
영어의 문제는 C ++ 컴파일러로 구문 분석 할 수없고 컴파일러가 더 나은 맞춤법 검사기를 만든다는 것입니다. :-)
Howard Hinnant

4
모든 곳에서 '자동'을 사용하지 않았다면 탭이 조금 더 나았을 것이라고 생각하지만 이것은 매우 유용합니다. 다른 곳을 보지 않고도 어떤 유형이 조작되고 있는지보고 싶어하는 나 같은 게으른 사람들을위한 것입니다. 감사합니다 @HowardHinnant
MarkoPaulo

7

또한 시점에서 ms 수를 얻는 방법에는 두 가지가 있습니다. 어느 것이 더 나은지 잘 모르겠습니다. 벤치마킹을했고 둘 다 동일한 성능을 가지고 있으므로 선호도의 문제라고 생각합니다. 아마도 Howard는 다음과 같이 차임 할 수 있습니다.

auto now = system_clock::now();

//Cast the time point to ms, then get its duration, then get the duration's count.
auto ms = time_point_cast<milliseconds>(now).time_since_epoch().count();

//Get the time point's duration, then cast to ms, then get its count.
auto ms = duration_cast<milliseconds>(tpBid.time_since_epoch()).count();

첫 번째는 왼쪽에서 오른쪽으로가는 내 마음 속에서 더 명확하게 읽습니다.


1

한 줄로 :

long value_ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now()).time_since_epoch()).count();

0

time_point객체 는 다른 time_point또는duration 객체 객체 합니다.

당신은 당신을 변환해야합니다 longA를 duration다음 코드는 제대로 작동합니다, 지정된 단위.


예제를 게시 할 수 있습니까?
Mendes

제공된 두 링크 모두 하단에 "예제"섹션이 있습니다.
Mr. Llama

나는 그것을 컴파일 만들었지 만, 몇 가지 논리 오류가 .. I've는 원래 코드 ... 편집 해
멘데스

1
예를 포함하면 답변에 도움이 될 것입니다. 링크가 죽거나 변경됩니다. 즉, 왜 이것이 반대 투표인지 잘 모르겠습니다.
TankorSmash
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.