【问题标题】:Addition some interval to tm structs为 tm 结构添加一些间隔
【发布时间】:2011-05-11 23:53:16
【问题描述】:

我有一个结构 tm
我需要添加一些固定的时间间隔(以 xx 年、xx 个月、xx 天为单位) 到 tm 结构。
是否有任何标准功能可以做到这一点?

我使用的编译器是 Windows XP 上的 MSVC 2005。

【问题讨论】:

  • 请告诉我们您使用的编译器和平台(如果您知道,它支持哪些标准)。这是为了澄清为什么mk_time 不适合您。即使您已经找到了适合您的解决方案,它也会帮助其他人。
  • Windows XP,MSVC 2005,我尝试从 pmg 复制粘贴代码,无论是否使用 mktime,它都不起作用
  • 请在此处粘贴您的完整测试代码!

标签: c time-t ctime


【解决方案1】:

有两个函数可以转换时间格式:

  1. mktime()struct tm(代表当地时间)转换为time_t
  2. localtime()time_t 转换为struct tm 中的当地时间。

有趣的是第一个,它接受超出范围的结构成员值,并作为转换的副产品适当地设置它们(和所有其他)。这可用于在算术运算之后校正字段数据值。但是字段的类型是 int,因此如果 e。 G。您在一年中添加秒数。

因此,如果您想获得实际日期,此代码会有所帮助(来自@pmg 的答案的修改副本):

struct tm addinterval(struct tm x, int y, int m, int d) {
    x.tm_year += y;
    x.tm_mon += m;
    x.tm_mday += d;
    mktime(&x);
    return x;
}

还要注意tm_isdst会员,关心一下。当您跳过夏令时切换日期时,它的值可能会导致时间来回移动。

【讨论】:

  • 我之前写过,那个修正没有用。 mktime(&x) 返回 -1
  • 我认为(希望)DST 不会改变结果,因为我们处理的是几天,而不是几个小时。
  • 对不起,我写我的时候没有看到你评论。但是mktime 可以和我的 GCC 一起使用。如果您的编译器不支持 c99 标准,您的代码可能会失败。
  • @pmg:如果 mk 时间看到时间 13:17 Dec, 7tm_isdst 设置为 1,它将尝试设置更正此标志,这将导致时间(可能还有日期)发生变化。如果在mktime() 之前将tm_isdst 设置为-1,则不会发生更改。 我对此进行了测试。
  • mktime() 在标准 C 中一直具有规范化行为,它不需要 C99。
【解决方案2】:

标准加法运算符有效。

struct tm x;
/* add 2 years and 3 days to x */
x.tm_year += 2;
x.tm_mday += 3;

编辑:您可以轻松制作函数

struct tm addinterval(struct tm x, int y, int m, int d) {
    x.tm_year += y;
    x.tm_mon += m;
    x.tm_mday += d;
    mktime(&x); /* normalize result */
    return x;
}

编辑:添加mktime 以标准化结果

【讨论】:

  • +1 但要注意溢出,例如将 3 个月加到 10 个月不是 13 个月,而是 1 年零 1 个月
  • 是的……必须注意。 "2012-02-29 + 1 年是 2013-03-01"
  • 非常感谢,简单的加法需要注意闰年和月份长度的差异吗?例如,如果我将 31 天的月份添加到 28 天的月份,这会在 1 上增加月份,在 3 上增加天字段?
  • @StNickolay:如果您在应用添加后调用mktime(&x),它将使结构正常化(例如,10 月 40 日变为 11 月 9 日)。
  • 我找到了正确的解决方案stackoverflow.com/questions/423961/… 谢谢大家。主题已关闭。
【解决方案3】:

我建议先将手头的日期转换为天数。那么添加一个间隔是微不足道的。然后,将数字转换回日期。

您可以找到将日期转换为天数并返回的算法,例如http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html

【讨论】:

    【解决方案4】:

    其他答案会导致高度不稳定的结果,具体取决于您的系统如何初始化 struct tm 以及中午时间值是否已正确初始化。

    如果您只关心日期的变化,而时间保持不变,则将tm_isdsttm_hourtm_sec全部设置为0,然后再传递给mktime。更好的是,在之前获取它们的值并在之后重置它们以保持一致性(如果它们之前不一致,它们将始终保持不变)。重用其他答案的代码:

    tm addinterval(tm t, int y, int m, int d)
    {
        auto hour = t.tm_hour;
        auto min = t.tm_min;
        auto sec = t.tm_sec;
    
        // First we discover the DST Flag. By setting hour to 12
        //   we can assure the mktime does not shift the date
        //   because it will shift the hour!
        t.tm_isdst = 0;
        t.tm_hour = 12;
        t.tm_min = 0;
        t.tm_sec = 0;
        mktime(&t);
    
        // Now we can add the interval
        t.tm_year += y;
        t.tm_mon += m;
        t.tm_mday += d;
        mktime(&t);
    
        // Now reset the mid-day time values
        t.tm_hour = hour;
        t.tm_min = min;
        t.tm_sec = sec;
    
        // Return struct tm while keeping mid-day time the same
        //   while the only values that changed are the date and perhaps isdst.
        return t;
    }
    

    我希望它更简单,但这就是必须的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-11
      • 2013-06-23
      • 2017-04-11
      • 2015-04-27
      • 2012-12-07
      • 2021-03-21
      • 1970-01-01
      相关资源
      最近更新 更多