【问题标题】:Day of week from seconds since epoch自纪元以来的几秒钟内的星期几
【发布时间】:2016-04-01 12:58:40
【问题描述】:

我正在尝试从纪元时间戳以来的秒数计算星期几。从time.h我可以使用gmtime(),但这增加了1.3kB的程序,可能是因为gmtime()也计算了日期。

所以,我想知道使用类似的东西会有什么问题:

(timestamp / (24*3600)) % 7

我唯一能想到的是闰秒,这样像 00:00:02 这样的日期可能会被归类为错误的日期。

编辑 这是用于嵌入式编程的,1.3kB 是 64kB 程序/固件的重要组成部分。此外,我不希望在此之后对时区或日期做任何事情。

【问题讨论】:

  • 您的代码不支持时区。
  • 对于一个微不足道的程序,或多或少 1.3kB 并不重要,因为这是一个微不足道的一次性示例。对于一个不平凡的程序,或多或少 1.3kB 也并不重要,因为无论如何都会有许多其他类似大(甚至更大)的块链接。我认为您应该选择gmtime()。避免使用本地代码的标准函数只会给您带来可以避免的问题。
  • 经过一番思考,闰秒并不是真正的问题,因为 UNIX 时间不考虑闰秒。我在上面编辑了我的评论以反映这一点。
  • 关于“自纪元以来的秒数”,请注意,这是一个常见的误解,即这是您从time() 得到的。实际上,time() 返回 (time_t) 的编码是“实现定义的”。您可以从timespec_get() 获得“自纪元以来的秒数”,而“纪元”又是实现定义的。小心这种假设。 ;-)
  • 感谢您的回答,我稍微编辑了问题以更好地定义问题。从来不知道 unix 时间不包括闰秒。

标签: c time


【解决方案1】:

使用类似的东西会有什么问题:(?)

(timestamp / (24*3600)) % 7

除了您没有指定纪元开始的星期几(例如星期四)和一周开始的星期几(例如星期一)之外,上述内容并没有太大问题。请参阅8601 以在一周的第一天进行更深入的讨论。还要注意像 24*3600 这样的计算,使用 16 位 int/unsigned 会导致麻烦。

示例:假设时代开始于一周中的第 3 天(星期一:0。星期四:3)。这会同时处理 2 个问题:纪元的星期几和星期的第一天,因为只需要编码正差。

#define EPOCH_DOW 3
#define SECS_PER_DAY 86400 
dow = ((timestamp / SECS_PER_DAY) + EPOCH_DOW) % 7;

如果timestamp 是有符号类型,请附加以下内容以确保[0...6] 范围内的结果。

dow = (dow + 7) % 7;
// or 
if (dow < 0) dow += 7;  

我怀疑您的应用程序中使用了leap seconds。如果是这样,那么任务会复杂得多,因为代码不仅需要处理更复杂的计算,还需要处理如何接收下一个预定闰秒的更新 - 它们不规则地发生。

【讨论】:

    【解决方案2】:

    由于 1970 年 1 月 1 日是星期四,因此您提前了 4 点,根据 % 对负操作数的行为,您可能会计算出纪元之前日期的错误结果。 (最简单的解决方法是检查结果是否为负,如果是则加 7。)但除此之外,您的算法是正确的;它与glibc internal function __offtime 使用的相同,gmtime 最终会调用它。 (你不能自己调用​​它,因为它是一个内部实现细节)。

    无需担心闰秒; Unix 时间会忽略它们。

    我建议将代码封装在一个(可能是内联的)函数中,将 gmtime 实现作为 #if 0 块的注释,以便在您开始需要计算月/年时轻松切换到它好吧。

    【讨论】:

    • “...取决于 % 在负操作数上的行为”——C 严格自 (AFAIK) C99 起定义该行为,而 C++ 则自 C++11 起定义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-17
    • 2019-08-03
    • 1970-01-01
    • 2013-01-06
    • 2013-12-31
    • 2014-04-12
    • 1970-01-01
    相关资源
    最近更新 更多