2017-03-22 8 views
1

임베디드 리눅스에서 작업 중이며 시스템/컨트롤러 시간은 1/1/1970부터 밀리 초 형태로 유지됩니다. gmtime을 사용하려고하지만 정확한 결과를 얻을 수 없습니다. 이 시간 (밀리 초)을 실시간 시간 : 분 : 초 : 일 : 월로 변환하는 예제가 유용 할 것입니다.gmtime() 함수는 윤년을 고려합니까?

+0

확실히해야합니다. 귀하가 얻고 있다고 말하는 부정확 한 결과의 예가 그것들을 생산하는 [mcve]와 함께 도움이 될 것입니다. 실제로 질문에 대한 답변을 얻으려면 필수적입니다. ('tm_mday'는 1 기반이고,'tm_mon'은 0 기반이고,'tm_year'는 1900 기반입니다, 맞습니까?) –

답변

1

, 그것은 또한 tm_sec 필드의 범위는 [0..60]까지로 정의된다 이유 인 윤초에 대한 gmtime() 지원 윤년 계정 않습니다뿐만 아니라.

+1

'C' 표준에 따르면'gmtime()'은 윤초를 설명하기 위해 _ 필수가 아니지만 허용됩니다. 이 특성은 지정되지 않은 상태로 남습니다. POSIX에 따르면,'time_t'가 1970-01-01T00 : 00 : 00 UTC부터 그 카운트에 _not_를 포함하지 않기 때문에'gmtime()'은 윤년을 고려하지 않습니다. 결과적으로'gmtime()'의 구현이 윤초를 설명하는 경우는 거의 없다. 도약 년, 네. 도약 초, 아니. 당신이'tm_sec'의 범위에 대해서 정확 하긴하지만. 그런 점에서,'struct tm'는 윤초를 나타낼 수 있습니다.'time_t'만이 할 수 없습니다. –

+2

@HowardHinnant'time_t'가 리눅스와 FreeBSD에서의 윤초를 포함하는지 (아마도 다른 것들도) 설정 가능합니다. 윤초를 포함하면,'gmtime()'은'tm_sec' 값'60'을 리턴 할 수 있습니다. http://coliru.stacked-crooked.com/a/622da23fd57dabca를 참조하십시오. – hvd

+0

@hvd :'putenv ("TZ = right/UTC")와 좋은 데모, 고마워. –

1

Howard Hinnant의 chrono-Compatible Low-Level Date Algorithms에서 파생되고 자세히 설명 된 civil_from_days을 사용할 수 있습니다. 이 함수는 1970 년 1 월 1 일부터 일수를 취하여 {y, m, d} 필드로 변환합니다. 완료하면 밀리 초 타임 스탬프에서 일 수를 뺀 다음 자정부터 밀리 초를 가져와 h:M:s.ms으로 분해해야합니다. 그냥 내가 입력 1490285505123ms으로 사용 된 예로서

#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'; 
} 

, 출력은 다음과 같습니다 :

여기에 전체 코드의

2017-03-23 16:11:45.123 

이 계좌로 도약 년이 걸린다. 윤초를 고려하지 않습니다. 임베디드 리눅스 시스템/컨트롤러 중 하나를 사용하는 것은 거의 불가능하므로 그렇게 시도하는 것은 잘못 될 수 있습니다.

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

(+/- 5,800,000년)

당신이 t0000-03-01 00:00:00.000의 하한을 제한 괜찮다면 :

위의 알고리즘은 t에 대한 유효성의 매우 큰 범위가 당신이 낮은 리터를 제한 할 수있는 경우

int32_t era = z/146097; 

: 당신은에 era의 계산을 단순화 할 수 있습니다

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

그런 다음 era 간단하게 될 수 있습니다 :이 4백년 범위에 t을 제한하고자하는 경우, 마지막으로

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

그리고 : t1970-01-01 00:00:00.000의 IMIT는 z의 계산을 단순화 할 수있다 :

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'; 
}