C ++:将表格20160120中的日期转换为自纪元以来的日期

时间:2016-11-05 13:26:10

标签: c++ date chrono

假设我们有一个表示日期的整数,格式为20160120.我想将此转换为epoch(1970-01-01)以来的日期,以便它对应于POSIX样式的日期。因此,例如int 20160718将成为int 17000。

我的尝试在下面,我首先将int转换为字符串,然后转换为自纪元以来的秒数,然后转换为自纪元以来的几天。这样做的一个问题是我必须将日期移动3小时才能获得正确的日期(请参阅std::to_string(d*100 + 3))行。我怀疑这与时区有关?我在UTC - 1.我不知道如何处理。

所以我想知道是否有一种不太复杂的方式,如果不是 - 我如何解决时区问题。

#include <iostream>
#include <chrono>
#include <time.h>
#include <iomanip>
#include <sstream>
#include <string>

typedef std::chrono::duration<int, std::ratio<60 * 60 * 24>> days_type;
typedef std::chrono::system_clock sysclock;

int convert(const unsigned d){
    std::tm t = {};
    std::istringstream ss(std::to_string(d*100 + 3));   
    ss >> std::get_time(&t, "%Y%m%d%H");

    time_t t_ =  mktime(&t);

    /*
     Now convert seconds since epoch to days since epoch via chrono...
     */

    sysclock::time_point tp = sysclock::from_time_t(t_);

    std::chrono::time_point<sysclock, days_type> tp_day = 
    std::chrono::time_point_cast<days_type>(tp);

    return tp_day.time_since_epoch().count();
}


int main(){
    int d = 20160718;
    std::cout << d << ": " << convert(d) << std::endl; //17000
    return 0;
}

3 个答案:

答案 0 :(得分:3)

使用date library

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

int convert(unsigned d) {
  date::year_month_day ymd{date::year(d / 100 / 100),
                           date::month(d / 100 % 100), date::day(d % 100)};
  return date::sys_days{ymd}.time_since_epoch().count();
}

int main() {
  int d = 20160718;
  std::cout << d << ": " << convert(d) << '\n'; // 17000
}

See it run

当然,convert() API会通过更强类型来改进,例如直接返回date::sys_days来表示时间点。

答案 1 :(得分:1)

您系统上POSIX纪元开头的

time_t可能不是0

这是一个显示不同结果的程序:

#include "date.h" // uses this library: https://github.com/HowardHinnant/date
#include <iostream>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <string>

time_t convert_local(int d)
{
    std::tm t{};
    auto ts{std::to_string(d)};
    ts.insert(8, " ");
    ts.insert(6, " ");
    ts.insert(4, " "); // this is a workaround for a VS2015 bug: http://stackoverflow.com/q/21172767/1460794
    std::istringstream ss(ts);
    ss >> std::get_time(&t, "%Y %m %d");
    if(!ss) std::cout << "parse fail.\n";

    time_t t_{mktime(&t)};
    return t_;
}

time_t convert_UTC(int d)
{
    std::tm base_t{};
    base_t.tm_mday = 1;
    base_t.tm_mon = 0;
    base_t.tm_year = 70;
    base_t.tm_wday = 4;
    auto base_tt{std::mktime(&base_t)};

    std::tm t{};
    auto ts{std::to_string(d)};
    ts.insert(8, " ");
    ts.insert(6, " ");
    ts.insert(4, " "); // this is a workaround for a VS2015 bug: http://stackoverflow.com/q/21172767/1460794
    std::istringstream ss(ts);
    ss >> std::get_time(&t, "%Y %m %d");
    if(!ss) std::cout << "parse fail.\n";

    time_t t_{mktime(&t)};
    return t_ - base_tt;
}

typedef std::chrono::duration<int, std::ratio<60 * 60 * 24>> days_type;
typedef std::chrono::system_clock sysclock;

int days_since_epoch(time_t t)
{
    sysclock::time_point tp = sysclock::from_time_t(t);
    std::chrono::time_point<sysclock, days_type> tp_day =
        std::chrono::time_point_cast<days_type>(tp);
    return tp_day.time_since_epoch().count();
}

int main()
{
    std::tm t{};

    t.tm_mday = 1;
    t.tm_mon = 0;
    t.tm_year = 70;
    t.tm_wday = 4;

    auto tt{std::mktime(&t)};
    auto tp{std::chrono::system_clock::from_time_t(tt)};

    time_t t0{0};
    auto tp0{std::chrono::system_clock::from_time_t(t0)};

    using namespace date;
    std::cout << tp << " for Jan 1 1970 00:00 UTC in my timezone (-6)\n";
    std::cout << std::chrono::system_clock::now() << " is the time now in my timezone (-6)\n";
    std::cout << tp0 << " is what we get from time_t{0} in my timezone (-6)\n";

    int d = 20160718;
    std::cout << "\n\n";
    std::cout << d << " converted to time_t is " << convert_local(d) << " but it considers local timezone on my system.\n";
    std::cout << "Now, using this time_t, converted to days since epoch: " << days_since_epoch(convert_local(d));

    std::cout << "\n\n";
    std::cout << d << " converted to time_t, adjusted for local timezone is " << convert_UTC(d) << ".\n";
    std::cout << "Now, using this time_t, converted to days since epoch: " << days_since_epoch(convert_UTC(d));

    return 0;
}

在我的系统上它产生:

1970-01-01 06:00:00.0000000 for Jan 1 1970 00:00 UTC in my timezone (-6)
2016-11-05 14:42:19.1299886 is the time now in my timezone (-6)
1970-01-01 00:00:00.0000000 is what we get from time_t{0} in my timezone (-6)


20160718 converted to time_t is 1468821600 but it considers local timezone on my system.
Now, using this time_t, converted to days since epoch: 17000

20160718 converted to time_t, adjusted for local timezone is 1468800000.
Now, using this time_t, converted to days since epoch: 17000

在另一台服务器(live demo)上,它会产生:

1970-01-01 00:00:00.000000000 for Jan 1 1970 00:00 UTC in my timezone
2016-11-05 14:37:15.661541264 is the time now in my timezone
1970-01-01 00:00:00.000000000 is what we get from time_t{0} in my timezone


20160718 converted to time_t is 1468800000 but it considers local timezone on my system.
Now, using this time_t, converted to days since epoch: 17000

20160718 converted to time_t, adjusted for local timezone is 1468800000.
Now, using this time_t, converted to days since epoch: 17000

最后,最好是明确地(通过指定日期,月份和年份)获得两个时间点。

通过这种方式,您可以使用system_clock,这无关紧要,因为我们只想查看以天为单位的持续时间:

#include <iostream>
#include <chrono>
#include <ctime>
#include <iomanip>
#include <string>
#include <sstream>

auto get_epoch_tp()
{
    std::tm base_t{};
    base_t.tm_mday = 1;
    base_t.tm_mon = 0;
    base_t.tm_year = 70;
    base_t.tm_wday = 4;
    auto base_tt{std::mktime(&base_t)};
    auto tp{std::chrono::system_clock::from_time_t(base_tt)};
    return tp;
}

int get_days_since_epoch(int d)
{
    std::tm t{};
    auto ts{std::to_string(d)};
    ts.insert(8, " ");
    ts.insert(6, " ");
    ts.insert(4, " "); // this is a workaround for a VS2015 bug: http://stackoverflow.com/q/21172767/1460794
    std::istringstream ss(ts);
    ss >> std::get_time(&t, "%Y %m %d");
    if(!ss) std::cout << "parse fail.\n";
    time_t tt{mktime(&t)};

    auto tp{std::chrono::system_clock::from_time_t(tt)};

    using days_type = std::chrono::duration<int, std::ratio<60 * 60 * 24>>;
    auto duration{tp - get_epoch_tp()};
    auto days{std::chrono::duration_cast<days_type>(duration)};
    return days.count();
}

int main()
{
    int d = 20160718;
    std::cout << d << ": " << get_days_since_epoch(d) << std::endl; //17000
}

demo

答案 2 :(得分:0)

转换为时间后你可以做简单的数学运算。

OneToOneField