将格式为20160120的日期转换为自epoch以来的天数

C++: Converting a date in form 20160120 to days since epoch

本文关键字:epoch 转换 格式 20160120 日期      更新时间:2023-10-16

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

我的尝试如下,我首先将int转换为字符串,然后转换为自epoch以来的秒数,然后转换为自epoch以来的天数。这样做的一个问题是,我必须将日期更改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;
}
使用日期库:
#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
}

看它运行

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

time_t在系统POSIX纪元开始时可能不是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 << "nn";
    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 << "nn";
    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

在另一个服务器上(实时演示),它产生:

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
}
演示

您可以在转换为时间后进行简单的数学运算。

#include <iostream>
#include <time.h>
#include <iomanip>
#include <sstream>
int convert(const unsigned d){
    std::tm t = {};
    std::istringstream ss(std::to_string(d));  
    ss >> std::get_time(&t, "%Y%m%d");
    time_t t_ = mktime(&t);
    return (int)t_/(60*60*24);
}

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