2017-03-22 211 views
1

我正在使用嵌入式Linux,自1970年1月1日以來系統/控制器時間保持爲毫秒的形式。我正在嘗試使用gmtime,但無法獲得準確的結果。任何將此時間(毫秒)轉換爲實時小時數:分鐘:秒:日:月的示例都會有所幫助。gmtime()函數是否考慮了閏年?

+0

它當然應該。你說你得到的不準確結果的一個例子,以及產生它們的[mcve]會有所幫助 - 事實上,如果你想回答你的問題,這是非常重要的。 (你知道'tm_mday'是基於1的,'tm_mon'是基於0的,'tm_year'是基於1900的,對嗎?) –

回答

1

不僅gmtime()支持閏年,它也佔閏秒,這就是爲什麼它是tm_sec場的範圍被定義爲0..60]包容性。

+1

根據'C'標準,'gmtime()'不需要考慮閏秒,但它是被允許的。這個特點是沒有說明的。根據POSIX的說法,'gmtime()'不會佔用閏秒,因爲UTC時間1970-01-01T00:00:00時間__不包括它們。隨後,很少(如果有的話)'gmtime()'的實現佔用了閏秒(我知道沒有)。閏年,是的。閏秒,沒有。雖然你對'tm_sec'的範圍是正確的。在這方面,'struct tm'可以代表閏秒,而'time_t'不能。 –

+2

@HowardHinnant「time_t」是否包含Linux和FreeBSD上的閏秒(可能還有其他人)是可配置的。當它包含閏秒時,它們的'gmtime()'可以返回'60'的'tm_sec'值。見http://coliru.stacked-crooked.com/a/622da23fd57dabca – hvd

+0

@hvd:好的演示與'putenv(「TZ =右/ UTC」)',謝謝。 –

1

您可以使用在Howard Hinnant的chrono-Compatible Low-Level Date Algorithms中得到並詳細解釋的civil_from_days。此函數自1970年1月1日以來計算天數,並將其轉換爲{y, m, d}字段。一旦你完成了,你只需要處理從毫秒時間戳中減去天數,以便從午夜開始獲得毫秒數,然後將其分解爲h:M:s.ms

下面是完整的代碼:

#include <iostream> 
#include <iomanip> 
#include <cstdint> 

int 
main() 
{ 
    using namespace std; 
    int64_t t = 1490285505123;  // milliseconds since epoch 
    int32_t z = (t >= 0 ? t : t - (1000*86400-1))/(1000*86400); // days since epoch 
    t -= z * (1000LL * 86400);  // milliseconds since midnight 
    z += 719468; 
    int32_t era = (z >= 0 ? z : z - 146096)/146097; 
    int32_t doe = z - era * 146097; 
    int32_t yoe = (doe - doe/1460 + doe/36524 - doe/146096)/365; 
    int32_t y = yoe + era * 400; 
    int32_t doy = doe - (365*yoe + yoe/4 - yoe/100); 
    int32_t m = (5*doy + 2)/153; 
    int32_t d = doy - (153*m + 2)/5 + 1; // day 
    m += m < 10 ? 3 : -9;     // month 
    y += m <= 2;       // year 
    int32_t h = t/(1000 * 3600);  // hour 
    t -= h * (1000 * 3600); 
    int32_t M = t/(1000 * 60);   // minute 
    t -= M * (1000 * 60); 
    int32_t s = t/1000;     // second 
    int32_t ms = t - s * 1000;   // ms 
    cout.fill('0'); 
    cout << setw(4) << y << '-' << setw(2) << m << '-' << setw(2) << d 
        << ' ' << setw(2) << h << ':' << setw(2) << M 
        << ':' << setw(2) << s << '.' << setw(3) << ms << '\n'; 
} 

正如我已經用作輸入1490285505123ms爲例,輸出爲:

2017-03-23 16:11:45.123 

這需要閏年考慮在內。它不考慮閏秒。你的嵌入式linux系統/控制器也不太可能,所以嘗試這樣做是不正確的。

上述算法有t一個非常大的有效範圍:

-5877641-06-23 00:00:00.000 <= t <= 5880010-09-09 23:59:59.999 

(+/- 580萬年)

如果你不介意的制約t0000-03-01 00:00:00.000下限那麼你可以簡化era的計算爲:

int32_t era = z/146097; 

如果你可以限制低l的t1970-01-01 00:00:00.000 IMIT那麼z計算可以簡化爲:

int32_t z = t/(1000 * 86400); // days since epoch 

最後,如果你願意限制t到這家擁有400年份範圍:

2000-03-01 00:00:00.000 <= t <= 2400-02-29 23:59:59.999 

然後era可以變得簡單:

int32_t const era = 5; 

FWIW,這裏是一個high-level date/time library撬動C++1分之11 4 <chrono>庫執行完全相同的計算,只是清晰的語法。你的std :: lib將不得不支持<chrono>來使用這個庫:

#include "date.h" 
#include <iostream> 

int 
main() 
{ 
    using namespace date; 
    using namespace std; 
    using namespace std::chrono; 
    cout << sys_time<milliseconds>(1490285505123ms) << '\n'; 
}