는 C

2009-08-13 3 views
3

이 아무도 할 필요가 없어야합니다 뭔가 것 같아,하지만 임베디드 시스템은 time.h가하는 것 같다있는 (OpenWRT)에 대한 커널 모듈에서 일하고 있어요에서 유닉스 시간을 분해하는 방법timespec 포함 및 time_t 유형 및 clock_gettimegmtime 작동하지만 하지이 매우 localtime, ctime, time, 또는의 tm 유형을 포함한다.는 C

gmtime에서 자신의 구조체로 반환 포인터를 캐스팅하려고하면 segfault가 발생합니다.

두 가지 방법 중 하나를 사용하여 문제를 해결할 수 있습니다. 누락 된 유형에 액세스하는 방법을 알아내는 것이 좋을 것입니다. 또는 대안으로 내 분해 방법을 롤백하는 방법도 있습니다. 유닉스 타임 스탬프.

+1

'gmtime'은'time.h'에서 어떻게 선언되어 있습니까? – caf

답변

5

이 정확해야는 (내 year 대신 1900 CE의 시대의 일반적인 시대를 사용하는 struct tm의 컷 다운 모방을 채 웁니다) : 모든 마법의 숫자

struct xtm 
{ 
    unsigned int year, mon, day, hour, min, sec; 
}; 

#define YEAR_TO_DAYS(y) ((y)*365 + (y)/4 - (y)/100 + (y)/400) 

void untime(unsigned long unixtime, struct xtm *tm) 
{ 
    /* First take out the hour/minutes/seconds - this part is easy. */ 

    tm->sec = unixtime % 60; 
    unixtime /= 60; 

    tm->min = unixtime % 60; 
    unixtime /= 60; 

    tm->hour = unixtime % 24; 
    unixtime /= 24; 

    /* unixtime is now days since 01/01/1970 UTC 
    * Rebaseline to the Common Era */ 

    unixtime += 719499; 

    /* Roll forward looking for the year. This could be done more efficiently 
    * but this will do. We have to start at 1969 because the year we calculate here 
    * runs from March - so January and February 1970 will come out as 1969 here. 
    */ 
    for (tm->year = 1969; unixtime > YEAR_TO_DAYS(tm->year + 1) + 30; tm->year++) 
     ; 

    /* OK we have our "year", so subtract off the days accounted for by full years. */ 
    unixtime -= YEAR_TO_DAYS(tm->year); 

    /* unixtime is now number of days we are into the year (remembering that March 1 
    * is the first day of the "year" still). */ 

    /* Roll forward looking for the month. 1 = March through to 12 = February. */ 
    for (tm->mon = 1; tm->mon < 12 && unixtime > 367*(tm->mon+1)/12; tm->mon++) 
     ; 

    /* Subtract off the days accounted for by full months */ 
    unixtime -= 367*tm->mon/12; 

    /* unixtime is now number of days we are into the month */ 

    /* Adjust the month/year so that 1 = January, and years start where we 
    * usually expect them to. */ 
    tm->mon += 2; 
    if (tm->mon > 12) 
    { 
     tm->mon -= 12; 
     tm->year++; 
    } 

    tm->day = unixtime; 
} 

나의 사과를. 367 * month/12는 달력의 30/31 일 순서를 생성하는 깔끔한 트릭입니다. 계산은 3 월에 시작하여 마지막에 수정이 이루어질 때까지 작동합니다. 그 덕분에 일년이 끝나는 시점에 윤일이 오기 때문에 쉽습니다.

+1

매직 넘버에 대해 사과하는 것보다 코드에서 덜 분명한 것들에 대해 적어도 논평하지 않는 이유는 무엇입니까? 이 함수는 약간의 논평을 통해 이점을 얻을 수 있습니다. –

+0

도움이 될만한 의견을 추가했습니다. – caf

0

사용자 공간에서 glibc는 시간 표현의 "로컬"부분을 처리하는 것과 관련하여 많은 작업을 수행합니다. 커널 내에서는 이것이 가능하지 않습니다. 아마도 사용자 공간에서 필요하다면 모듈 내에서이 작업을 고민하지 않아야합니다.

+1

주기적으로 proc 인터페이스에 날짜를 쓰는 cron 작업을 작성했습니다. 원형 교차로처럼 보이지만 궁극적으로이 타이밍 요소보다 더 나은 솔루션이었습니다. 그래서 네, 그냥 사용자 공간에서 그것을 당겨에 좋은 전화. – mikepurvis

0

time_t은 UTC 1970 년 1 월 1 일 이후의 초 수로, 월, 일 및 연도로 분해하는 것은 그 결과를 UTC로 원한다면 제공하는 것이 어렵지 않습니다. Googling "gmtime source"에 의해 bunch of source available이 있습니다. 대부분의 임베디드 시스템은 시간대 설정과 환경에 의존하기 때문에 조금 더 어려워지기 때문에 로컬 시간 처리를 생략합니다.