代码之家  ›  专栏  ›  技术社区  ›  Andrew Stein

如何在从time()获得的时间上添加一天

  •  16
  • Andrew Stein  · 技术社区  · 17 年前

    我有一个时间表示为自UTC 1970年1月1日午夜以来经过的秒数(先前调用time()的结果)。如何在这段时间内增加一天?

    添加24*60*60在大多数情况下都有效,但如果夏令时在这两者之间开启或关闭,则会失败。换句话说,我主要想增加24小时,但有时是23或25小时。

    为了说明-程序:

    #include <time.h>
    #include <iostream>
    
    int main()
    {
      time_t base = 1142085600;
      for(int i = 0; i < 4; ++i) {
        time_t time = base + i * 24 * 60 * 60;
        std::cout << ctime(&time);
      }
      return 0;
    

    }

    Sat Mar 11 08:00:00 2006
    Sun Mar 12 09:00:00 2006
    Mon Mar 13 09:00:00 2006
    Tue Mar 14 09:00:00 2006
    

    我要3月12日、13日的泰晤士报。。。也是早上8点。


    FigBug提供的答案为我指明了正确的方向。但是我不得不使用localtime而不是gmtime。

    int main()
    {
      time_t base = 1142085600;
      for(int i = 0; i < 4; ++i) {
        struct tm* tm = localtime(&base);
        tm->tm_mday += i;
        std::cout << asctime(tm);
     }
     return 0;
    }
    

    给我:

    Sat Mar 11 08:00:00 2006
    Sat Mar 12 08:00:00 2006
    Sat Mar 13 08:00:00 2006
    Sat Mar 14 08:00:00 2006
    

    但是,请注意,所有的日子都是Sat。同样,它会持续到3月32日、33日等。如果我加入mktime函数,我会回到我开始的地方:

    #include <time.h>
    #include <iostream>
    
    int main()
    {
      time_t base = 1142085600;
      for(int i = 0; i < 4; ++i) {
        struct tm* tm = localtime(&base);
        tm->tm_mday += i;
        time_t time = mktime(tm);
        std::cout << asctime(tm);
     }
     return 0;
    }
    

    2006年3月11日星期六08:00:00
    2006年3月13日星期一09:00:00
    2006年3月14日星期二09:00:00
    

    我错过了什么???


     std::cout << ctime(&time);
    

    而不是时间,但我得到了同样的结果。所以我猜我的库和/或编译器是一团糟。我正在cygwin上使用g++3.4.4。我将这些文件复制到Solaris 5.8,并在那里使用g++3.3进行编译。我在那里得到了正确的结果!事实上,无论我使用ctime还是asctime进行输出,我都能得到正确的结果:

    Sat Mar 11 08:00:00 2006
    Sun Mar 12 08:00:00 2006
    Mon Mar 13 08:00:00 2006
    Tue Mar 14 08:00:00 2006
    

    我还使用g++3.4.6在Red Hut Linux上获得了正确的结果(使用两个输出函数)。

    所以我想我遇到了一只Cygwin虫子。

    5 回复  |  直到 10 年前
        1
  •  23
  •   Roland Rabien    17 年前

    使用 时间 到 将时间

    tmmday )

    使用 mktime() 转换 回到 时间

    看见 time.h 更多信息

    编辑:

    我刚试过,这个很有效:

    int main()
    {
      time_t base = 1142085600;
      for(int i = 0; i < 4; ++i) {
        struct tm* tm = localtime(&base);
        tm->tm_mday += i;
        time_t next = mktime(tm);
        std::cout << ctime(&next);
     }
     return 0;
    }
    
        2
  •  8
  •   Andrew Selivanov    17 年前

    几乎 tm->tm_isdst=-1

    tm_isdst的正值或0值 使mktime()最初假定 夏令时, 在指定的时间内。负片 尝试确定是否存在日光 节省时间对客户有效 指定时间。

    mktime spec )

    int main()
    {
      time_t base = 1142085600;
      for(int i = 0; i < 4; ++i) {
        struct tm* tm = localtime(&base);
        tm->tm_mday += i;
        tm->tm_isdst = -1;        // don't know if DST is in effect, please determine
                                  // this for me
        time_t next = mktime(tm);
        std::cout << ctime(&next);
     }
     return 0;
    }
    

    否则会出现错误(例如,从2009年3月29日01:59:59开始的莫斯科夏令时):

    int main()
    {
        // 28 March 2009 05:00:00 GMT ( local - 08:00 (MSK) )
        time_t base = 1238216400;
    
        std::time_t start_date_t = base;
        std::time_t end_date_t = base;
    
        std::tm start_date = *std::localtime(&start_date_t);
        std::tm end_date = *std::localtime(&end_date_t);
    
        end_date.tm_mday += 1;
    //    end_date.tm_isdst = -1;
    
        std::time_t b = mktime(&start_date);
        std::time_t e = mktime(&end_date);
    
        std::string start_date_str(ctime(&b));
        std::string stop_date_str(ctime(&e));
    
        cout << " begin (MSK) (DST is not active): " << start_date_str;
        cout << " end   (MSD) (DST is active):     " << stop_date_str;
    }
    

    输出:

    begin (MSK) (DST is not active): Sat Mar 28 08:00:00 2009
    end   (MSD) (DST is active):     Sun Mar 29 09:00:00 2009
    
        3
  •  4
  •   Pyrolistical    17 年前

        4
  •  3
  •   Toon Krijthe    17 年前

    当您想要显示这些值时,我始终保持UTC时间戳,并将它们转换为指定的时区(包括夏令时),这是最好的结果。

        5
  •  2
  •   Howard Hinnant    9 年前

    一个非常老的问题的新答案。

    新答案的基本原理:现在有更好的工具来解决这个问题,通过最小化串行数据,使结果更不容易出错,更易于阅读,实际上更高效<-&燃气轮机;字段转换。

    新答案需要C++11/14, <chrono> free, open source, timezone library .

    代码如下:

    #include "tz.h"
    #include <iostream>
    
    int
    main()
    {
        using namespace std::chrono;
        using namespace date;
        auto base = make_zoned("Pacific/Easter", sys_seconds{1142085600s});
        for (int i = 0; i < 4; ++i)
        {
            std::cout << format("%a %b %d %T %Y %Z", base) << '\n';
            base = base.get_local_time() + days{1};
        }
    }
    

    zoned_time

    它被格式化为所需的任何格式。

    Sat Mar 11 09:00:00 2006 -05
    Sun Mar 12 09:00:00 2006 -06
    Mon Mar 13 09:00:00 2006 -06
    Tue Mar 14 09:00:00 2006 -06
    

    事实证明,这个输出并不是OP所期望的(请求的输出是每天08:00:00)。然而,我使用这个库来全面调查整个星球在这一天的时间转变。在这一天,只有一个时区发生了转变:太平洋/复活节。而这一转变就是移动 向前地 . 这是智利使用的时区,在南半球 瀑布

            base = base.get_sys_time() + days{1};
    

    使用 base.get_sys_time() ,而不是 base.get_local_time()

    Sat Mar 11 09:00:00 2006 -05
    Sun Mar 12 08:00:00 2006 -06
    Mon Mar 13 08:00:00 2006 -06
    Tue Mar 14 08:00:00 2006 -06
    
    推荐文章