2009-08-03 3 views
24

내가 아주 단순한 것으로 생각하는 것을 찾고 있는데 - 특정 시간대 (예 : "America/New_York"와 같이 문자열로 지정)에 로컬 Unix 시간을 주면 - 이 아니라 현지 시간으로이됩니다. 해당 시간 값 (GMT).Linux에서 시간대 변환 C API, 누구입니까?

 #include <time.h> 
     #include <stdlib.h> 

     time_t 
     my_timegm(struct tm *tm) 
     { 
      time_t ret; 
      char *tz; 

      tz = getenv("TZ"); 
      setenv("TZ", "", 1); 
      tzset(); 
      ret = mktime(tm); 
      if (tz) 
       setenv("TZ", tz, 1); 
      else 
       unsetenv("TZ"); 
      tzset(); 
      return ret; 
     } 

꼭보다 더 나은 방법이있을 : 그것은 소리 즉,

time_t get_gmt_time(time_t local_time, 
        const char* time_zone); 

으로 믿을 수 없 간단한의 라인을 따라 뭔가, 내가 찾을 수있는 가장 가까운 timegm의 man 페이지에서 다음 코드 조각이었다 이것은 호전적으로 스레드로부터 안전한 가증 행위가 아닙니다. 맞습니까? 권리??

+6

좋은 질문입니다. 상황은 정말 그렇게 나빠요. 전 세계는 다른 표준 시간대에있는 것처럼 보이지 않거나 아마도 UTC 이외의 시간대로 변환해야한다고 생각하는 것처럼 보입니다. 그것은 문제입니다. –

+0

'time_t'와'struct tm'의 의미는 약간 혼란 스럽습니다.모든 UN * X 계열 시스템에서'time_t' /'time()'은 'epoch'(UTC 0:00 01/01/1970) 이후의 초이며, 이는 struct tm으로 변환 될 수 있습니다. 'mtime()'은 반대쪽에'struct tm'을'time_t로 변환한다. (timezone-corrected 결과를 준다)'gmtime()'(UTC로 결과를 준다) '. 그럼 당신이 코딩 한 것은'mktime()'입니다. –

+0

스레드 안전 문제에 관심이 있습니다. "현재"영역이 아니라 임의의 시간대로 변환하는 방법 ** 스레드로부터 안전한 ** 방법. 변환뿐만 아니라 strftime을 사용하여 영역을 인쇄하십시오. – netjeff

답변

1

나는 정말로 glib에 뭔가 있다고 생각했지만 잘못 기억 한 것 같습니다. 나는 당신이 아마 C 코드를 작성하려고 노력하고 있음을 알고 있습니다 :

클래스를 통해 파이썬에 시간대 개념이 있다는 것을 알고 있습니다. datetime documentation에서 읽을 수 있습니다. 모듈의 소스 코드를 살펴볼 수 있습니다 (tarball에 있음, 모듈/datetime.c에 있음) - 문서가있는 것으로 보입니다. 그래서 뭔가를 얻을 수 있습니다. tzfile에서

+0

예, 물론 곧장 C API를 의미합니다. 피사체가 지금 고쳐졌습니다, 감사합니다! 파이썬 구현을 살펴보면, 그 아이디어는 cro 나는 그 길을 피하려고 정말로 희망했다. 소스와 API 문서를 살펴보면, Python의 datetime은 시간대를 알지 못한다는 것을 알게되었습니다. 시간이 지나면 시간 변환을 할 때 구현해야하는 추상 tzinfo 클래스입니다. 영역. 그것을 구현하는 라이브러리가 몇 개 있습니다 만, 정말로 - 정말 * 나쁜 것입니까? – igor

4

(5)는/usr/share에있는 파일을 문서화하는 /은 zoneinfo 소름 끼치는 세부 사항 (내 시스템에) :

그 시간대가 내부적으로 tzfile 사용 보이지만의 glibc는 에 거부 그것을 사용자 공간에 노출하십시오. 표준화 된 함수가 더 유용하고 이식 가능하고 실제로 glibc에 의해 문서화되기 때문에 이것은 대부분 입니다.

다시 말하지만, 이것은 아마도 당신이 찾고있는 API가 아니 겠지만 정보는 거기에 있으며 너무 심하게 파싱 할 수 있습니다. 파이썬 대답 유사

+0

그래,이게이 작품을 만들 수있는 유일한 방법 같아. 못생긴 것처럼. 물론, 일단 구현되면, 나는 첫 번째 장소에서 찾고 있었던 일반적인 시간대 변환 API로 끝날 것이다. o 현재 단일 스레드 포크 프로세스를 다루고 있기 때문에 동기 부여가 충분하지 않을 수있다. 이렇게하면 timegm의 man 페이지에 언급 된 TZ "hack"을 선택할 가능성이 높습니다. – igor

1

, 내가 R가 무엇을 보여줄 수

R> now <- Sys.time()  # get current time 
R> format(now)    # format under local TZ 
[1] "2009-08-03 18:55:57" 
R> format(now,tz="Europe/London") # format under explicit TZ 
[1] "2009-08-04 00:55:57" 
R> format(now,tz="America/Chicago") # format under explicit TZ 
[1] "2009-08-03 18:55:57" 
R> 

하지만, R은 보통 struct tm을 확장 내부 표현을 사용 --- R-2.9.1/src에가/주 참조/datetime.c.

여전히 털이 많은 주제이며 표준 라이브러리라면 좋을 것입니다. 아마도 최선의 방법은 사용하지 않는 것입니다. Boost Date_Time (example)

+1

내가 아는 바로는, Boost의 Date_time은 시스템의 zoneinfo 파일을 사용하지 않고 대신 자신의 시간대 데이터베이스를 사용합니다. 따라서이 파일은 비 초보자 인 IMHO가됩니다. 내가 틀린다면 나에게 올바른 것을해라. – igor

0

gmtime_r()을 사용할 수없는 이유는 무엇입니까? 나를 위해 잘 일한 :

int main() 
{ 
    time_t t_gmt, t_local=time(NULL); 
    struct tm tm_gmt; 

    gmtime_r(&t_local, &tm_gmt); 

    t_gmt = mktime(&tm_gmt); 

    printf("Time now is: %s", ctime(&t_local)); 
    printf("Time in GMT is: %s", ctime(&t_gmt)); 

    return 0; 
} 
+0

원래의 포스터가 "GMT"라고 말한 이후로, 특히 궁금해했다. –

+2

꽤 좋지만 컴퓨터 시간대가 +1이고 변환하려는 시간이 +2라고 상상해보십시오. 그리고 그것은 최악의 시나리오는 아닙니다. 필자의 경우처럼 컴퓨터 시간대가 유럽/암스테르담이라고 가정하고 'tm'구조로 변환하려는 시간은 유럽/아테네 시간대에 있습니다. 1 시간 추가/빼기뿐만 아니라 지구 곳곳에서 다른 일광 절약 시간도 있습니다. – NickSoft

5

여기에 조금 더 자세히 설명하고 싶습니다.다음 시도 할 경우

는 :

#include <stdio.h> 
#include <time.h> /* defines 'extern long timezone' */ 

int main(int argc, char **argv) 
{ 
    time_t t, lt, gt; 
    struct tm tm; 

    t = time(NULL); 
    lt = mktime(localtime(&t)); 
    gt = mktime(gmtime(&t)); 

    printf("(t = time(NULL)) == %x,\n" 
     "mktime(localtime(&t)) == %x,\n" 
     "mktime(gmtime(&t)) == %x\n" 
     "difftime(...) == %f\n" 
     "timezone == %d\n", t, lt, gt, 
     difftime(gt, lt), timezone); 
    return 0; 
} 

당신이 알 수 있습니다 그 시간대의 전환을 확인하십시오

  • mktime(localtime(t)) == t

    • mktime(gmtime(t)) == t + timezone,
      그러므로 :
    • difftime(mktime(gmtime(t)), mktime(localtime(t))) == timezone
      (후자는 tzset() 또는 시간대 변환 함수의 호출로 초기화되는 전역 변수입니다). 위의

    예 출력 : 그런 의미에서

     
    $ TZ=GMT ./xx 
    (t = time(NULL)) == 4dd13bac, 
    mktime(localtime(&t)) == 4dd13bac, 
    mktime(gmtime(&t)) == 4dd13bac 
    difftime(...) == 0.000000 
    timezone == 0 
    
    $ TZ=EST ./xx 
    (t = time(NULL)) == 4dd13baf, 
    mktime(localtime(&t)) == 4dd13baf, 
    mktime(gmtime(&t)) == 4dd181ff 
    difftime(...) == 18000.000000 
    timezone == 18000 
    
    $ TZ=CET ./xx 
    (t = time(NULL)) == 4dd13bb2, 
    mktime(localtime(&t)) == 4dd13bb2, 
    mktime(gmtime(&t)) == 4dd12da2 
    difftime(...) == -3600.000000 
    timezone == -3600 
    

    , 당신은 "거꾸로 그것을"시도하고 - time_t는 UN * X에서 절대로 처리됩니다, 즉, 항상 상대 "EPOCH"(1970 년 1 월 1 일 0시 UTC).

    UTC와 현재 시간대 (마지막 tzset() 호출)의 차이는 항상 external long timezone입니다.

    환경 조작 불량을 없애지는 못하지만, mktime()을 통과하는 노력을 아낄 수 있습니다.

  • +1

    시간대 사이의 오프셋이 일정하지 않으므로 (DST 및 기록적인 오프셋 변경) 생각하기 때문에 그렇게하지 않을 것입니다. –

    +0

    분명히 말하자면, 당신은 무엇을 "하지 않겠습니까?" 유엔 * X 시간대 메커니즘이 역사적인 데이터베이스가 아닌 것으로 동의합니다. 그럼에도 불구하고 위의 내용이 잘못된 결과를내는 예를 들어 줄 수 있습니까? –

    +0

    이 답변은 실제로 최고입니다! 고마워요! :) – Gandaro

    1

    gmtime, localtime 및 그 변형의 문제점은 TZ 환경 변수에 의존한다는 것입니다. 시간 함수는 먼저 DZ 오프셋을 결정하기 위해 TZ를 읽는 tzset (void)를 호출합니다. 사용자 환경에서 TZ가 설정되지 않은 경우, (g) libc는 시스템 시간대를 사용합니다. 예를 들어 'Europe/Paris'에 로컬 구조체가 있고 사용자의 컴퓨터 또는 환경이 'America/Denver'로 설정되어 있으면 GMT로 변환 할 때 잘못된 오프셋이 적용됩니다. 모든 시간 함수는 char * tzname [2], 긴 시간대 (GMT로부터의 초 단위의 diff) 및 int daylight (DST의 부울 값)를 설정하기 위해 TZ를 읽는 tzset (void)를 호출합니다. 이들을 직접 설정하는 것은 영향을 미치지 않습니다. 왜냐하면 다음에 localtime 등을 호출 할 때 tzset()이 덮어 쓸 것이기 때문입니다.

    setenv는 원래 질문에서 'igor'와 동일한 문제에 직면했습니다. re-entran?). 나는 위에서 언급 한 변수를 명시 적으로 설정하기 위해 tzset (void)를 tzset (char *)으로 수정할 수 있는지 더 자세히 살펴보기로 결정했습니다. 음, 물론, 그것은 나쁜 생각입니다 ...하지만 glibc 소스와 IANA TZ 데이터베이스 소스를 탐색 할 때 setenv 접근법이 그렇게 나쁘지는 않다는 결론에 도달했습니다.

    우선, setenv는 프로세스 글로벌 'char ** environ'(호출하는 쉘이 아니므로 '실제'TZ는 영향을받지 않습니다) 만 수정합니다. 두 번째로, glibc는 실제로 setenv에 잠금을 설정합니다. 단점은 setenv/tzset 호출이 원자 적이지 않기 때문에 다른 스레드가 원래 스레드 호출 tzset 전에 TZ에 기록 할 수 있다고 생각할 수 있습니다. 그러나 스레드를 사용하는 잘 구현 된 응용 프로그램은이를 위해 항상주의해야합니다.

    POSIX에서 tzset을 정의하여 확장 IANA TZ 데이터베이스에서 char *를 사용하여 (사용자 또는 시스템 TZ /를 사용한다는 의미로 NULL을 사용하지만) 실패하면 setenv는 다음과 같이 나타납니다. 괜찮아.