2008-11-21 145 views
16

我有一個時間表示爲自1970年1月1日午夜以來UTC(早期調用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 

我想時間13 3月12日......至上午八時。


由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 

這就是我想要的。使用gmtime給我的時間在14:00:00

但是,請注意,所有的日子都是週六。此外,它關係到三月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; 
} 

給我:

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 

我在想什麼???


OK,我已經嘗試了FigBug的最新建議,那就是使用:

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

代替asctime,但我得到了相同的結果。所以我想我的庫和/或編譯器搞砸了。我在cygwin上使用g ++ 3.4.4。我將這些文件複製到Solaris 5.8並在那裏使用g ++ 3.3進行編譯。我在那裏得到正確的結果!事實上,我得到正確的結果是否我使用的ctime或asctime輸出:在Red必勝客的Linux

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。

所以我想我遇到了Cygwin的錯誤。

感謝您對所有您的幫助和建議....

+0

我想你想在最終版本中使用ctime而不是asctime,因爲您希望在當地時區使用該時間。 time()返回UTC,localtime()將其轉換爲您的時區。在您的時區添加一天,然後轉換回UTC。用ctime()在你的時區打印出來。很混亂。 – 2008-11-22 01:49:33

+0

再多一行:tm-> tm_wday =(tm-> tm_wday + i)%7; – 2008-11-22 02:40:35

+0

您不必擔心:從mktime文檔: timeptr的成員tm_wday和tm_yday的原始值將被忽略,並且其餘成員的值的範圍不限於其正常值(像tm_mday在1和31之間)。 – 2008-11-22 04:08:43

回答

18

使用gmtime的() time_t的轉換爲結構TM

添加一個新的一天( tm_mday

使用mktime()轉換結構TM time_t的

看到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; 
} 
3

我總是有最好的結果與保持時間戳UTC並將其轉換爲指定的時區(包括夏令時)時要顯示的值。

這樣可以節省很多麻煩(並且使程序獨立於時區。

5

只需添加24 * 60 * 60。它不應該在DST期間失敗,因爲UTC不會使用DST。

如果失敗,那麼你是不是在你的代碼中使用UTC地方。刪除時區依賴。

5

FigBug的解決方案將每次工作幾乎,但它需要DST修正:TM-> tm_isdst的= -1

的tm_isdst爲原因 一個正或0值mktime()初始設定 該夏令時, 分別是或不是在指定的時間效應 。的tm_isdst爲負 值導致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日1點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 
2

對於一個非常古老的問題的新答案灰。

新答案的基本原理:現在有更好的工具可以解決這個問題,通過最小化串行轉換,使結果更容易出錯,更易於閱讀,而且更加高效。

新答案需要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}; 
    } 
} 

的通過配對無論是與Unix時間時間戳所需的時區創建zoned_time開始了。

以任何所需格式格式化。

並且在時區的本地時間系統中添加1天,這將考慮夏令時。輸出是:

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每天)。不過,我使用這個庫來全面調查整個星球在這一天的時間轉換。在這個日期只有一個時區有過渡:太平洋/復活節。並且該轉換是將移回一小時,而不是轉發。這是智利在南半球使用的時區,其中一個在3月的時間框架內下降了

這可以通過以UTC而不是本地時間進行算術來演示。這是一種微小的調整,在上述程序中一個行:

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

使用base.get_sys_time(),相對於base.get_local_time(),引起「系統時間」,這是UTC忽略閏秒做算術。現在輸出更改爲:

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