IT박스

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

itboxs 2020. 11. 27. 07:55
반응형

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


나는 변환 할 필요 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입니까?

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


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_msA는 time_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;
}

The main danger above is not interpreting integral_duration as milliseconds on the way back to a time_point. One possible way to mitigate that risk is to write:

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

This reduces risk down to just making sure you use sys_milliseconds on the way out, and in the two places on the way back in.

And one more example: Let's say you want to convert to and from an integral which represents whatever duration system_clock supports (microseconds, 10th of microseconds or nanoseconds). Then you don't have to worry about specifying milliseconds as above. The code simplifies to:

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

This works, but if you run half the conversion (out to integral) on one platform and the other half (in from integral) on another platform, you run the risk that system_clock::duration will have different precisions for the two conversions.


I would also note there are two ways to get the number of ms in the time point. I'm not sure which one is better, I've benchmarked them and they both have the same performance, so I guess it's a matter of preference. Perhaps Howard could chime in:

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();

The first one reads more clearly in my mind going from left to right.


time_point objects only support arithmetic with other time_point or duration objects.

You'll need to convert your long to a duration of specified units, then your code should work correctly.


as a single line:

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();

참고URL : https://stackoverflow.com/questions/31255486/c-how-do-i-convert-a-stdchronotime-point-to-long-and-back

반응형