简体   繁体   English

生成随机日期

[英]Generating a random date

I wrote this code snippet to generate random dates: 我写了这段代码片段来生成随机日期:

std::time_t curr_time = time(0);
std::time_t ten_years = 365 * 12 * 30 * 24 * 60;
std::time_t rand_date = curr_time - std::rand() % ten_years;
tm *ltm = std::localtime(&rand_date);
std::cout << ltm->tm_year + 1900 << " " << ltm->tm_mon + 1 << " " << ltm->tm_mday << std::endl;

However it always gives me the current date. 但是它总是给我当前的日期。 What am i doing wrong? 我究竟做错了什么?

std::rand() may return rather small values, 0..32767 is the minimum range, and does so on some popular 32-bit platforms (MSVC among them). std :: rand()可能返回相当小的值,0..32767是最小范围,并且在一些流行的32位平台(其中包括MSVC)中这样做。 With time_t in seconds this only gives you about eight hours of random noise. 使用time_t以秒为单位,这只会给你大约8小时的随机噪音。

Try combining the results from a pair of std::rand calls instead. 尝试组合来自一对std :: rand调用的结果。 Eg (std::time_t) std::rand() * RAND_MAX + std::rand() or switch to a better random number generator. 例如(std::time_t) std::rand() * RAND_MAX + std::rand()或切换到更好的随机数生成器。

I would suggest you don't modify a time_t directly, as the implementation is not specified by the standard. 我建议你不要直接修改time_t ,因为标准没有指定实现。 Better to convert it a la this question: How to add one day to a time obtained from time() 最好将它转换成这个问题: 如何将一天添加到从时间()获得的时间

I would suggest to do it differently, based on the CPP Reference: 基于CPP参考,我建议采用不同的方式:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <iostream>

using namespace std;

int main() {
    time_t timer;
    struct tm x_years;
    struct tm* current;
    int how_many_years = 10;
    srand (time(NULL));
    int randomYear = (rand()%how_many_years)+1;
    int randomMonth = (rand()%12)+1;
    int randomDays = (rand()%30)+1;


    time(&timer);  /* get current time; same as: timer = time(NULL)  */
    current = localtime(&timer);
    x_years.tm_hour = 0;
    x_years.tm_min = 0;
    x_years.tm_sec = 0;
    x_years.tm_year = current->tm_year - randomYear;
    x_years.tm_mon = (current->tm_mon - randomMonth) <= 0 ? current->tm_mon + (12-randomMonth) : current->tm_mon - randomMonth;
    x_years.tm_mday = (current->tm_mday - randomDays) <= 0 ? current->tm_mday + (30-randomDays) : current->tm_mday - randomDays;

    //returns seconds ever since the random generated date until now
    cout << "Years rolled back: " << randomYear << endl;
    cout << "Months rolled back: " << randomMonth << endl;
    cout << "Days rolled back: " << randomDays << endl;
    cout << endl;
    cout << "Current Year: " <<  current->tm_year+1900 << endl;
    cout << "Current Month: " <<  current->tm_mon << endl;
    cout << "Current Day: " <<  current->tm_mday << endl;
    cout << endl;
    cout << "Year: " <<  x_years.tm_year+1900 << endl;
    cout << "Month: " <<  x_years.tm_mon << endl;
    cout << "Day: " <<  x_years.tm_mday << endl;
}

EDIT 编辑

I have edited the code, and with it, you can even select how many years you want to go back. 我编辑了代码,有了它,你甚至可以选择你想要回去多少年。 Basically, you go back X years in the time, and you can get the date rollbacked in the x_years struct. 基本上,你回到X年的时间,你可以在x_years结构中回滚日期。

Hope this helped! 希望这有帮助!

The following solution uses C++11 with an internal uniform_int_distribution : 以下解决方案使用带有内部uniform_int_distribution C ++ 11:

// uniform_time_dist.h
#include <chrono>
#include <random>

template <class TimePoint>
class uniform_time_distribution{
public:
  uniform_time_distribution(TimePoint start, TimePoint end)
    : m_start(start), m_end(end),
    m_seconds(std::chrono::duration_cast<std::chrono::seconds>(end - start))
  {}

  template <class Generator>
  TimePoint operator()(Generator && g){
    std::uniform_int_distribution<std::chrono::seconds::rep> d(0, m_seconds.count());

    return m_start + std::chrono::seconds(d(g));
  }

private:
  TimePoint m_start;
  TimePoint m_end;
  std::chrono::seconds m_seconds;
};

You can use it like any other distribution function with a generator: 您可以像使用生成器的任何其他分发函数一样使用它:

// uniform_time_dist.h -- continuation 
template <class TimePoint>
TimePoint randomTime(TimePoint start, TimePoint end){
  static std::random_device rd;
  static std::mt19937 gen(rd());

  uniform_time_distribution<TimePoint> t(start, end);

  return t(gen);
}

You can combine this method with your time_t functions by using clock::to_time_t : 您可以使用clock::to_time_t将此方法与time_t函数结合使用:

#include <iostream>
#include "uniform_time_dist.h" // see above

using namespace std::chrono;

int main(){
  auto k = system_clock::to_time_t(randomTime(
    system_clock::now(),
    system_clock::now() + hours(24 * 365 * 10)));

  std::cout << std::ctime(&k);    
}

Note that the class above is just a small sketch, you should be able to improve it vastly in order to match the other distribution functions. 请注意,上面的类只是一个小草图,您应该能够大大改进它以匹配其他分布函数。

I managed to create a solution based on Phil's answer: 我设法根据Phil的答案创建了一个解决方案:

time_t currTime = time(0);
tm *ltm = std::localtime(&currTime);
ltm->tm_mday = std::rand() % 3650 * -1;
time_t next = mktime(ltm);
ltm = std::localtime(&next);
std::cout << ltm->tm_year + 1900 << " " << ltm->tm_mon + 1 << " " << ltm->tm_mday << std::endl;

If you are using boost libs you can use this class that I wrote to get random dates: 如果您正在使用boost库,您可以使用我编写的这个类来获取随机日期:

#include <iostream>
#include <ctime>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/variate_generator.hpp>
#include "boost/date_time/posix_time/posix_time.hpp"
#include "boost/date_time/gregorian/gregorian.hpp"


using namespace std;
using namespace boost;
using namespace boost::posix_time;
using namespace boost::gregorian;


class Randomizer {
private:
    static const bool debug_mode = false;
    random::mt19937 rng_;

    // The private constructor so that the user can not directly instantiate
    Randomizer() {
        if(debug_mode==true){
            this->rng_ = random::mt19937();
        }else{
            this->rng_ = random::mt19937(current_time_nanoseconds());
        }
    };

    int current_time_nanoseconds(){
        struct timespec tm;
        clock_gettime(CLOCK_REALTIME, &tm);
        return tm.tv_nsec;
    }

    // C++ 03
    // ========
    // Dont forget to declare these two. You want to make sure they
    // are unacceptable otherwise you may accidentally get copies of
    // your singleton appearing.
    Randomizer(Randomizer const&);     // Don't Implement
    void operator=(Randomizer const&); // Don't implement

public:
    static Randomizer& get_instance(){
        // The only instance of the class is created at the first call get_instance ()
        // and will be destroyed only when the program exits
        static Randomizer instance;
        return instance;
    }
    bool method() { return true; };

    int rand(unsigned int floor, unsigned int ceil){
        random::uniform_int_distribution<> rand_ = random::uniform_int_distribution<> (floor,ceil);
        return (rand_(rng_));
    }

    // Is not considering the millisecons
    time_duration rand_time_duration(){
        boost::posix_time::time_duration floor(0, 0, 0, 0);
        boost::posix_time::time_duration ceil(23, 59, 59, 0);
        unsigned int rand_seconds = rand(floor.total_seconds(), ceil.total_seconds());
        return seconds(rand_seconds);
    }


    date rand_date_from_epoch_to_now(){
        date now = second_clock::local_time().date();
        return rand_date_from_epoch_to_ceil(now);
    }

    date rand_date_from_epoch_to_ceil(date ceil_date){
        date epoch = ptime(date(1970,1,1)).date();
        return rand_date_in_interval(epoch, ceil_date);
    }

    date rand_date_in_interval(date floor_date, date ceil_date){
        return rand_ptime_in_interval(ptime(floor_date), ptime(ceil_date)).date();
    }

    ptime rand_ptime_from_epoch_to_now(){
        ptime now = second_clock::local_time();
        return rand_ptime_from_epoch_to_ceil(now);
    }

    ptime rand_ptime_from_epoch_to_ceil(ptime ceil_date){
        ptime epoch = ptime(date(1970,1,1));
        return rand_ptime_in_interval(epoch, ceil_date);
    }

    ptime rand_ptime_in_interval(ptime floor_date, ptime ceil_date){
        time_duration const diff = ceil_date - floor_date;
        long long gap_seconds = diff.total_seconds();
        long long step_seconds = Randomizer::get_instance().rand(0, gap_seconds);
        return floor_date + seconds(step_seconds);
    }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM