【问题标题】:Can we take a `std::chrono::milliseconds` variable from a range of the same type?我们可以从相同类型的范围中获取一个`std::chrono::milliseconds`变量吗?
【发布时间】:2017-10-19 08:04:10
【问题描述】:

我已经构建了一个函数,该函数将特定日期作为输入并以std::chrono::milliseconds 格式返回该日期。

milliseconds lowerRangeBound = TimeStamp(mm, dd, HH, MM, SS, yyyy);

例如,

milliseconds a = TimeStamp(8/*month*/, 23/*day*/, 14/*hours*/, 46/*minutes*/, 32/*seconds*/, 2017/*year*/);

以转换后的字符串格式返回:2017.08.23-14.46.32

我现在想做但不工作的是给定两个日期 (milliseconds) 以在这两个日期定义的范围内随机取一个日期。例如,给定

milliseconds a = TimeStamp(8/*month*/, 23/*day*/, 13/*hours*/, 46/*minutes*/, 32/*seconds*/, 2017/*year*/);
milliseconds b = TimeStamp(10/*month*/, 23/*day*/, 13/*hours*/, 46/*minutes*/, 32/*seconds*/, 2017/*year*/);

预期的输出是milliseconds c,它的字符串格式是这样的日期,2017.09.13-12.56.12。请注意,所需的输出是milliseconds,提供字符串格式以便在readable format 中发言。

到目前为止,我尝试将每个 milliseconds 变量转换为 long 数字 (.count()) 并在 [a,b] 范围内获得 random long。但是,输出日期无关紧要:1977.12.06-16.27.02

您能帮帮我吗?

提前谢谢你。

编辑:下面的代码受到link的启发

milliseconds TimeStamp(int mm, int dd, int HH, int MM, int SS, int yyyy) {

    tm ttm = tm();
    ttm.tm_year = yyyy - 1900; // Year since 1900
    ttm.tm_mon = mm - 1; // Month since January 
    ttm.tm_mday = dd; // Day of the month [1-31]
    ttm.tm_hour = HH; // Hour of the day [00-23]
    ttm.tm_min = MM;
    ttm.tm_sec = SS;

    time_t ttime_t = mktime(&ttm);
    system_clock::time_point time_point_result = std::chrono::system_clock::from_time_t(ttime_t);
    milliseconds now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(time_point_result).time_since_epoch();
    return now_ms;
}

milliseconds getRandomTimestamp(int mm_1, int dd_1, int HH_1, int MM_1, int SS_1, int yyyy_1,
    int mm_2, int dd_2, int HH_2, int MM_2, int SS_2, int yyyy_2, int N) {

    milliseconds lowerRangeBound = fixedTimeStamp(mm_1, dd_1, HH_1, MM_1, SS_1, yyyy_1);
    milliseconds upperRangeBound = fixedTimeStamp(mm_2, dd_2, HH_2, MM_2, SS_2, yyyy_2);

    long lowerRange_ = lowerRangeBound.count();
    long upperRange_ = upperRangeBound.count();

    //long output = rand() % (upperRange_ - lowerRange_ + 1) + lowerRange_;
    // rand() replaced after @Jarod42's suggestion.
    std::default_random_engine generator;
    std::uniform_int_distribution<int> distribution(lowerRange_, upperRange_);
    long output = distribution(generator);        

    std::chrono::duration<long> dur(output);
    return dur;
}

【问题讨论】:

  • 什么你试过了吗?请向我们展示它的Minimal, Complete, and Verifiable Example,而不仅仅是描述它。
  • 题外话:myTimeStamp(8, 23, 13, 46, 32, 2017); 是一个可怕的、令人头疼的、容易出错的设计
  • rand() 可以替换为&lt;random&gt; 中的内容。
  • 如果millisecond 计数不能存储在long 中会怎样?请记住,long 不是固定大小的整数类型,它可以是 32 位或 64 位长。
  • 实际上更糟的是,您的std::uniform_int_distribution 使用int,我从未见过64 位。在您的getRandomTimestamp 函数中,将long 类型更改为auto,并使用例如std::uniform_int_distribution&lt;decltype(lowerRange_)&gt; 代替。另外,return milliseconds(output)

标签: c++ chrono


【解决方案1】:

这可能是因为混合问题,您对数学感到困惑。

我建议您以毫秒为单位编写“随机时间戳”例程。

您可以在单独的步骤中执行从/到时间戳的转换。

我会这样写例程:

#include<random>
#include<chrono>
#include<cassert>
#include<iostream>

template<class Eng>
std::chrono::milliseconds getRandomTimestamp(Eng& eng, 
                                             std::chrono::milliseconds low, 
                                             std::chrono::milliseconds high) 
{
    // deduce the actual integer type. 
    // Otherwise we'll have to guess what T is when using
    // uniform_int_distribution<T>
    using count_type = decltype(low.count());

    // from this we can deduce the correct integer distribution
    using dist_type = std::uniform_int_distribution<count_type>;

    // create the distribution generator
    auto dist = dist_type(low.count(), high.count());

    // and apply it to the random generator, returning
    // milliseconds somewhere between low and high
    return std::chrono::milliseconds(dist(eng));    
}


int main()
{
    using namespace std::literals;

    std::random_device dev;
    std::default_random_engine eng(dev());

    auto t1 = 10'000'000ms;
    auto t2 = 11'000'000ms;
    auto t3 = getRandomTimestamp(eng, t1, t2);

    assert(t1 <= t3);
    assert(t3 <= t2);

    std::cout << t1.count() << std::endl;
    std::cout << t2.count() << std::endl;
    std::cout << t3.count() << std::endl;
}

【讨论】:

  • 感谢您的关注!
【解决方案2】:

如果您利用Howard Hinnant's free, open-source header-only date/time library,您可以让这一切变得更容易。语法简洁易读。例如,您可以使用date::sys_time&lt;std::chrono::milliseconds&gt; 创建任意精度的chrono::time_points(例如milliseconds)。

由于您的问题涉及time_points 而不是durationss,因此从类型安全的角度来看,这是更好的方法。这是getRandomTimestamp的一种写法:

#include "date/date.h"
#include <iostream>
#include <random>

date::sys_time<std::chrono::milliseconds>
getRandomTimestamp(date::sys_time<std::chrono::milliseconds> lowerBound,
                   date::sys_time<std::chrono::milliseconds> upperBound)
{
    static std::default_random_engine generator;
    using namespace std::chrono;
    std::uniform_int_distribution<milliseconds::rep> distribution{
        lowerBound.time_since_epoch().count(),
        upperBound.time_since_epoch().count()};
    return date::sys_time<milliseconds>{milliseconds{distribution(generator)}};
}

现在你唯一的问题是如何创建那些time_points!事实证明这是微不足道的:

int
main()
{
    using namespace date::literals;
    using namespace std::chrono_literals;
    auto t1 = date::sys_days{2017_y/8/23} + 13h + 46min + 32s;
    auto t2 = date::sys_days{2017_y/10/23} + 13h + 46min + 32s;
    auto t3 = getRandomTimestamp(t1, t2);
    // ...
}

date::sys_days 上方只是另一个chrono::time_point,但精度为days 而不是milliseconds(也可以拼写为date::sys_time&lt;date::days&gt;)。而2017_y/8/23date::year_month_day 类型的文字,表示2017.08.23。

我利用了 C++14 的计时文字。如果您使用 C++11,则需要使用 hours{13} 代替 13h

最后,您可以非常轻松地以多种格式格式化和流式传输t3,例如:

std::cout << date::format("%Y.%m.%d-%T", t3) << '\n';

这只是为我输出:

2017.09.04-17:14:04.220

如果您有运行时整数值而不是文字作为输入,这也很容易处理:

using namespace date;
auto t1 = sys_days{year{y}/m/d} + hours{h} + ...

如果您需要从t3 中获取任何字段值,那也很容易,例如:

sys_days sd = floor<days>(t3);
time_of_day<milliseconds> tod(t3-sd);
year_month_day ymd = sd;

ymd 具有年、月和日的 getter,tod 具有小时、分钟、秒和毫秒的 getter(后者拼写为 subseconds)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多