【问题标题】:Seconds since epoch for a specific date特定日期的纪元以来的秒数
【发布时间】:2021-07-03 16:43:51
【问题描述】:

目前,我有一个解决方案和另一个半解决方案。半解决方案在这里链接,Get seconds since epoch in Linux,但这给出了当前日期时间的纪元以来的时间。我需要让它告诉我指定日期的纪元以来的秒数。我确实有这个功能,但是我找不到它的原始帖子,

std::tm t = {};
std::istringstream ss(dateBuf);
ss >> std::get_time(&t, "%Y-%m-%d");
double seconds = (double)(std::mktime(&t));

不过,我遇到了一些问题。目前,dateBuf = "2020-01-01"; 我要求它不仅能够处理几天,而且能够处理几小时、几分钟、几秒钟……此外,我希望有另一种方法可以做到这一点,而无需每次都分配内存来制作一个新的@987654328 @ 和 std::istringstream,然后将 ss 推入其中。我想知道是否有办法以秒为值直接从char datebuf[]double/long double。出于所有密集目的,程序将多次检查此语句以将日期转换为秒,这似乎效率低下。比如

long double SecondsSinceEpoch(const char* date){
    //Taking in a date such as "2020-01-01 00:00:00" (Local Time)
    //Will return the value 1577836800 (GMT) and Local time of 1577797200

    //And also be able to take in a simpler date such as "2020-01-01"
}

【问题讨论】:

  • 您使用的是什么版本的 C++?如果您可以使用 C++20,那么新的 date-time facilities 非常棒。如果没有,Howard Hinnant 有一个 most excellent library,这是 C++20 版本所基于的。
  • @NathanOliver 可能两者兼而有之,我拥有的一些应用程序可能有 C++ 20,而有些可能没有。您能否举一个可以从我的帖子中使用的示例?
  • 对于基于scanf 的老派答案,我在这里做了一个:stackoverflow.com/a/66795589/7582247 - 我不会担心分配std::tm 除非你每秒执行很多次不过。
  • 这是个好主意,我会试试的。目前,您使用 sscanf_s 的示例效果很好
  • 我唯一需要改变 Ted 的就是传入 const char * 以保存将数组转换为 std::string 然后再返回 c_str()

标签: c++ string datetime time


【解决方案1】:

这是使用preview C++20 chrono library 的通用解决方案:

#include "date/tz.h"
#include <iostream>
#include <sstream>

long double
SecondsSinceEpoch(const char* date)
{
    //Taking in a date such as "2020-01-01 00:00:00" (Local Time)
    //And also be able to take in a simpler date such as "2020-01-01"
    //returns -1 on error
    using namespace date;
    using namespace std;
    using namespace std::chrono;

    istringstream in{date};
    local_days tpd;
    in >> parse("%F", tpd);
    if (in.fail())
        return -1;
    seconds s{};
    in >> parse(" %T", s);
    zoned_time zt{current_zone(), tpd + s};
    return zt.get_sys_time().time_since_epoch().count();
}

昂贵的部分是调用current_zone() 并解析出istringstream(这可能会在堆上创建一个长字符串,具体取决于实现和输入)。

如果我们可以用一个恒定的 UTC 偏移量代替时区,并且如果我们创建不需要做太多错误检查的自定义解析逻辑,上述操作可以更快。

这个库擅长的是获取{y, m, d, h, M, s} 整数值并将它们转换为秒数。因此,如果您可以比strptime(或在此库中等效)更有效地获取这些整数值,包括将 UTC 偏移量应用于本地时间,那么此库可以将这 6 个字段转换为秒数,只需很少的 cpu时钟周期。

更新

如果您的时区不变,您可以做的一件事就是查找一次:

static auto tz = current_zone();
zoned_time zt{tz, tpd + s};

或:

static auto tz = locate_zone("Australia/Sydney");
zoned_time zt{tz, tpd + s};

这两个选项在性能方面大致相当(假设您当前的时区始终是“澳大利亚/悉尼”。

如果您自己扫描成整数类型,那么将这些整数转换为日期看起来更像:

// Return {y, m, d, h, M, s}
std::array<int, 6>
scan(const char* date);

long double
SecondsSinceEpoch(const char* date)
{
    //Taking in a date such as "2020-01-01 00:00:00" (Local Time)
    //And also be able to take in a simpler date such as "2020-01-01"
    //returns -1 on error
    using namespace date;
    using namespace std::chrono;

    auto a = scan(date);  // where you write scan
    auto tp = local_days{year{a[0]}/a[1]/a[2]} + hours{a[3]}
              + minutes{a[4]} + seconds{a[5]};
    static auto tz = locate_zone("Australia/Sydney");
    zoned_time zt{tz, tp};
    return zt.get_sys_time().time_since_epoch().count();
}

使用时区库确实需要some installation

【讨论】:

  • 时区在悉尼,我认为AEST是时区的名称。因此,如果已知,将current_zone() 替换为"AEST" 会更有效/更理想?
猜你喜欢
  • 2018-05-18
  • 2010-09-13
  • 2011-02-08
  • 2013-11-02
  • 2014-03-13
  • 2011-08-31
  • 2011-06-09
  • 2016-11-25
相关资源
最近更新 更多