以编程方式检查年份是否更改的最有效方法是什么

What's the most efficient way to programmatically check if the year is changed

我正在尝试从 NIC 捕获数据包并将部分数据包有效负载保存为字符串。

数据包中必须存储的部分是其日志时间,称为 SysLog。每个数据包都有一个系统日志,格式如下:

Nov 01 03 14:50:25 TCP...[other parts of packet Payload]

可以看出,SysLog包没有Year Number。我的程序肯定是全年运行ning,所以我需要在数据包SysLog中添加Year Number,并将SysLog转换为纪元时间。我必须存储的最终字符串是这样的:

1478175389-TCP, ….

我使用以下代码将 Syslog 转换为 EpochTime。

tm* tm_date = new tm();
Std ::string time = Current_Year;
time += " ";
time += packet.substr(0,18);
strptime(time.c_str(), "%Y %b %d %T", tm_date);
EpochTime = timegm(tm_date);

当前年份方法:

std::string    currentYear() {
    std::stringstream now;
    auto tp = std::chrono::system_clock::now();
    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
    size_t modulo = ms.count() % 1000;
    time_t seconds = std::chrono::duration_cast<std::chrono::seconds>(ms).count();
#if HAS_STD_PUT_TIME
#else
    char buffer[25]; // holds "2013-12-01 21:31:42"
    if (strftime(buffer, 25, "%Y", localtime(&seconds))) {
        now << buffer;
    }
#endif // HAS_STD_PUT_TIME
    return now.str();
}

以上操作就是我对每个数据包要做的操作。数据包速率为 100000-1000000 pps,上面的和平代码非常耗时,特别是在 currentYear() 上。 一种可能的优化是删除 currentYear() 方法并保存 年份数作为常量值。如前所述,我的计划必须全年 运行,如您所知,2017 年即将到来。我们不能在 31/12/2016 23:59:00 更改我们的二进制文件,而且我们也不想浪费时间计算年号!!

我需要一种更有效的方法来计算当前年份数字,而无需 运行对每个数据包进行计算。

可能吗?你对我有什么建议?

一旦你获得了当前的日期和时间,据此计算出明年 1 月 1 日午夜的纪元时间应该不难。

计算完一年的预期纪元时间后,您要做的就是在创建日志条目时将其与当前时间进行比较。如果它还没有到达预先计算的 1 月 1 日午夜时间,您就知道这一年还没有过去。

因此,您根本不需要为每个数据包计算年份。只需要检查当前时间与预先计算的 1 月 1 日午夜时间,除非政客决定更改您的时区,否则不应更改,而所有这些都是 运行...

首先,您可能会考虑 currentYear() 返回 int(例如 2016),可能带有 time(2), localtime_r(3)tm_year 字段....然后您将避免制作 C++ 字符串。

然后,你说的是高数据包率,所以你可能有一些 event loop. You don't explain how it is done (hopefully you use some library à la libevent, or at least your own loop around poll(2).....),但你可能只在该事件循环中每十分之一秒计算一次当前年份。或者有一些其他线程偶尔计算当年(你可能需要一个互斥锁,或者使用 std::atomic<int> 作为当年的类型......)

更改以 Jan 开头的日志条目的年份,并且仅更改那些日志条目。

日志条目有时会乱序,或者带有在之前处理过程中保存的时间戳。

从 PC 时钟附加年份会给出不好的结果,例如

2016 Dec 31 23:59:58    normal
2016 Jan 01 00:01:01    printing time placed in packet by remote device, remote clock is running a bit fast
2017 Dec 31 23:59:59    printing timestamp saved locally two seconds before logging occurred
2017 Jan 01 00:00:03    back to normal

不能只是将本地时钟的年份与日志消息的月...秒连接起来。您必须指定避免大时钟跳跃的年份。

既然你试图生成 Unix 时间(自纪元以来的秒数),首先将日志消息时间转换为 Julian(自年初以来的秒数)并测试 Julian 是小于还是大于 10百万(大约 4 个月)。

您可以 "cache" 您生成的字符串,并且仅在年份更改时更改它。这可能只是 "little" 的改进,具体取决于哪些操作花费的时间最多。

//somewhere
static int currentYear = 0;
static std::string yearStr = ""; 

//in your function
auto now = std::chrono::system_clock::now();   
auto tnow = system_clock::to_time_t(now);
auto lt = localtime(&tnow); //or gmtime depends on your needs.
if(currentYear != lt.tm_year)
{
    yearStr = std::to_string(lt.tm_year + 1900);
    currentYear = t.tm_year;
}

return yearStr;

我不确定 static 在读取字符串的性能方面是否有任何 negative/positive 方面,或者由于缓存局部性,成员变量在这里可能更好。你必须测试这个。

如果你在多线程中使用它,你必须在这里使用互斥锁,这可能会降低性能(你必须再次测量它)。