问题 将std :: chrono :: system_clock :: time_point转换为struct timeval并返回


我正在编写一个需要访问旧C库的C ++代码,该库使用timeval作为当前时间的表示。

在旧包中获取我们使用的当前日期/时间:

struct timeval dateTime;
gettimeofday(&dateTime, NULL);

function(dateTime); // The function will do its task

现在我需要使用C ++ chrono,例如:

    system_clock::time_point now = system_clock::now();
    struct timeval dateTime;

    dateTime.tv_sec = ???? // Help appreaciated here
    dateTime.tv_usec = ???? // Help appreaciated here

    function(dateTime);

后来在代码中我需要回来的方式,建立一个 time_point 从返回的变量 struct timeval

    struct timeval dateTime;
    function(&dateTime);

    system_clock::time_point returnedDateTime = ?? // Help appreacited

我在使用C ++ 11。


9990
2017-09-09 23:39


起源



答案:


[编辑使用 time_val 而不是免费的vars]

假设你相信你的 system_clock 精确到毫秒,你可以这样:

  struct timeval dest;
  auto now=std::chrono::system_clock::now();
  auto millisecs=
    std::chrono::duration_cast<std::chrono::milliseconds>(
        now.time_since_epoch()
    );;
  dest.tv_sec=millisecs.count()/1000;
  dest.tv_usec=(millisecs.count()%1000)*1000;

  std::cout << "s:" << dest.tv_sec << " usec:" << dest.tv_usec << std::endl;

使用 std::chrono::microseconds 在 duration_cast 并相应地调整您的(div / mod)代码以获得更高的精度 - 注意您对所获得的值的准确性的信任程度。

转换回来是:

  timeval src;

  // again, trusting the value with only milliseconds accuracy
  using dest_timepoint_type=std::chrono::time_point<
    std::chrono::system_clock, std::chrono::milliseconds
  >;
  dest_timepoint_type converted{
    std::chrono::milliseconds{
      src.tv_sec*1000+src.tv_usec/1000
    }
  };

  // this is to make sure the converted timepoint is indistinguishable by one
  // issued by the system_clock
  std::chrono::system_clock::time_point recovered =
      std::chrono::time_point_cast<std::chrono::system_clock::duration>(converted)
  ;

6
2017-09-10 00:08



应该分配给 dateTime.tv_sec 和 dateTime.tv_usec 因为目标是最终有效 timeval 结构。 - Kyle Strand
@KyleStrand编辑 - Adrian Colomitchi
该 l 在 millisecs.count()/1000l; 和 dest.tv_usec=millisecs.count()%1000l;  当然不需要。一个小问题。 - chux
@chux好吧,调整好了 - Adrian Colomitchi


答案:


[编辑使用 time_val 而不是免费的vars]

假设你相信你的 system_clock 精确到毫秒,你可以这样:

  struct timeval dest;
  auto now=std::chrono::system_clock::now();
  auto millisecs=
    std::chrono::duration_cast<std::chrono::milliseconds>(
        now.time_since_epoch()
    );;
  dest.tv_sec=millisecs.count()/1000;
  dest.tv_usec=(millisecs.count()%1000)*1000;

  std::cout << "s:" << dest.tv_sec << " usec:" << dest.tv_usec << std::endl;

使用 std::chrono::microseconds 在 duration_cast 并相应地调整您的(div / mod)代码以获得更高的精度 - 注意您对所获得的值的准确性的信任程度。

转换回来是:

  timeval src;

  // again, trusting the value with only milliseconds accuracy
  using dest_timepoint_type=std::chrono::time_point<
    std::chrono::system_clock, std::chrono::milliseconds
  >;
  dest_timepoint_type converted{
    std::chrono::milliseconds{
      src.tv_sec*1000+src.tv_usec/1000
    }
  };

  // this is to make sure the converted timepoint is indistinguishable by one
  // issued by the system_clock
  std::chrono::system_clock::time_point recovered =
      std::chrono::time_point_cast<std::chrono::system_clock::duration>(converted)
  ;

6
2017-09-10 00:08



应该分配给 dateTime.tv_sec 和 dateTime.tv_usec 因为目标是最终有效 timeval 结构。 - Kyle Strand
@KyleStrand编辑 - Adrian Colomitchi
该 l 在 millisecs.count()/1000l; 和 dest.tv_usec=millisecs.count()%1000l;  当然不需要。一个小问题。 - chux
@chux好吧,调整好了 - Adrian Colomitchi


看到 std::chrono::system_clock::to_time_t(),转换 time_point 到了 time_t,成为你的 tv_sec。你没有得到 tv_usec,你可以设置0;或者你可以摆弄一些其他的东西,包括 duration_cast,为了从你的提取一秒钟的分数 time_point

from_time_t()反过来。


4
2017-09-09 23:44





以下是如何在不使用手动转换因子的情况下进行转换,或者根据未指定的舍入模式进行转换 time_t

timeval
to_timeval(std::chrono::system_clock::time_point tp)
{
    using namespace std::chrono;
    auto s = time_point_cast<seconds>(tp);
    if (s > tp)
        s = s - seconds{1};
    auto us = duration_cast<microseconds>(tp - s);
    timeval tv;
    tv.tv_sec = s.time_since_epoch().count();
    tv.tv_usec = us.count();
    return tv;
}

std::chrono::system_clock::time_point
to_time_point(timeval tv)
{
    using namespace std::chrono;
    return system_clock::time_point{seconds{tv.tv_sec} + microseconds{tv.tv_usec}};
}

to_timeval 小心翼翼地绕过 tp 向下(如果是负面)。 POSIX规范对此有点模糊,但我假设那样 timeval 表示在纪元之前的时间点为负 tv_sec 价值观,然后是积极的 tv_usec 值。然后找到它是一个简单的操作 microseconds 从上次开始 second

如果我对我的假设不正确(并且可以找到更精确的POSIX规范), <chrono> 有能力模拟其所做的任何事情。

假设上述约定,反向转换具有令人难以置信的可读性。它不需要评论。

这可以像这样测试:

timeval
make_timeval(time_t s, long us)
{
    timeval tv;
    tv.tv_sec = s;
    tv.tv_usec = us;
    return tv;
}

bool
operator==(timeval x, timeval y)
{
    return x.tv_sec == y.tv_sec && x.tv_usec == y.tv_usec;
}

int
main()
{
    using namespace std::chrono;
    assert(make_timeval(0, 0) == to_timeval(system_clock::time_point{}));
    assert(make_timeval(1, 0) == to_timeval(system_clock::time_point{seconds{1}}));
    assert(make_timeval(1, 400000) == to_timeval(system_clock::time_point{seconds{1} + microseconds{400000}}));
    assert(make_timeval(-1, 400000) == to_timeval(system_clock::time_point{seconds{-1} + microseconds{400000}}));

    assert(to_time_point(make_timeval(0, 0)) == system_clock::time_point{});
    assert(to_time_point(make_timeval(1, 0)) == system_clock::time_point{seconds{1}});
    assert(to_time_point(make_timeval(1, 400000)) == system_clock::time_point{seconds{1} + microseconds{400000}});
    assert(to_time_point(make_timeval(-1, 400000)) == system_clock::time_point{seconds{-1} + microseconds{400000}});
}

这一切都是基于对时代的假设 timeval 和 system_clock 是相同的。这没有指定,但对于所有现有实现都是如此。运气好的话,我们可以在不久的将来标准化现有的做法。

请注意,在POSIX中 timeval 用作两者 time_point 和a duration。所以 to_time_point 如果是,可能会导致运行时错误 timeval 目前代表一段时间。和 to_timeval 如果客户端将结果解释为持续时间,则可能导致运行时错误。


2
2017-09-10 02:39