2012-08-25 10 views
9

Wykonuję poniższy kod.Mylące zachowanie funkcji mktime(): zwiększenie liczby tm_hour o jeden

int main() 
{ 
struct tm storage={0,0,0,0,0,0,0,0,0}; 
char *p = NULL; 
p = (char *)strptime("2012-08-25 12:23:12","%Y-%m-%d %H:%M:%S",&storage); 
char buff[1024]={0}; 
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage); 
cout << buff << endl; 
storage.tm_sec += 20; 
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage); 
cout << buff << endl; 
mktime(&storage); 
strftime(buff,1024,"%Y-%m-%d %H:%M:%S",&storage); 
cout << buff << endl; 
return 0; 
} 

Jeżeli powyższy program wykonywany, drukuje '25.08.2012 13:23:32' zamiast '2012-08-25 12:23:32'. Proszę pomóż, dlaczego zwiększa wartość tm_hour. Działa to poprawnie, jeśli wprowadzę datę wprowadzenia jako "2012-02-25 12:23:32" w programie, co jest mylące.

wyjście ->

[[email protected] root]$ ./a.out 
2012-08-25 12:23:12 
2012-08-25 12:23:32 
2012-08-25 13:23:32 
[[email protected] root]$ 

najświeższe informacje na moim systemie ->

[[email protected] root]$ date 
Sat Aug 25 08:28:26 EDT 2012 
+0

Kod nie pokazuje, że godzina się zwiększa.Aby to zrobić, wyświetl wynik, który pochodzi z 'strptime', a także wynik, który pochodzi z wywołania' mktime'. Pomoże to ustalić, co się właściwie dzieje. –

+0

Przepraszam, nie mogę tego przetworzyć. Ma trzy wyjścia zamiast jednego, ale nie wskazuje, skąd pochodzą. Zaktualizuj przykładowy kod, aby dopasować wynik. –

Odpowiedz

11

Co dzieje

Termin określono ma czasu letniego w efekcie ale podczas wywoływania mktime, storage.tm_isdst wynosi zero. mktime widzi to i myśli: "Hej, dali mi datę z nieprawidłową flagą oszczędzania dziennego, naprawmy to". Następnie ustawia tm_isdst na 1 i zmienia tm_hour.

Zobacz także odpowiedź this.

go naprawić

  • użycie timegm zamiast mktime
  • ustawić strefę czasową na UTC przed wywołaniem mktime (patrz także przykład z timegm):
    setenv("TZ", "", 1); 
    tzset(); 
    mktime();
  • użyć dobrego Data- biblioteki czasu (np. boost::locale::date_time/boost::date_time, ale przeczytaj sekcję Q & A na stronie boost::locale::date_time przed jej wybraniem)
+1

Dzięki, pomógł mi i wyjaśnił moje wątpliwości. Teraz muszę uruchomić mój kod w obu systemach (włączanie i wyłączanie DST). na przykład Jeśli wstawię tm_isdst = 1 w kodzie przed wywołaniem do mktime(), spowoduje to niepoprawny wynik w systemie, w którym DST jest wyłączony (to skończy się zmniejszeniem tm_hour o jeden). Czy jest jakiś inny sposób dodania sekund do podanej daty? (Może to być "unikanie używania mktime()" lub "Make smart use of mktime(), które zignoruje flagę tm_isdst") –

+0

@DhirajNeve: Dodałem kilka poprawek. Jeśli potrzebujesz więcej rzeczy związanych z datą/czasem, myślę, że powinieneś użyć dobrej biblioteki daty/czasu w C++. – rve

+0

Czy tylko POSIX nie jest "timegmem"? – stackptr

4

Wow, nie tylko nie sposób wokół niego. Musi to być błąd w implementacji mktime (3) twojego systemu. mktime (3) nie powinien zmieniać przekazanego mu struct tm *.

Proponuję sprawdzić wartość storage.tm_isdst. Spróbuj ustawić wartość na 0, aby upewnić się, że nie ma wątpliwości co do czasu letniego. Jeśli to nie zadziała, spróbuj ustawić wartość na -1, aby automatycznie wyznaczyć właściwą wartość.

mktime - convert broken-down time into time since the Epoch

dodatnią lub wartość 0 do tm_isdst powoduje mktime() początkowo założyć, że zmiana czasu, odpowiednio, jest lub nie jest w rzeczywistości przez określony czas. Wartość ujemna dla tm_isdst powoduje, że mktime() próbuje określić, czy czas letni ma obowiązywać przez określony czas.


myliłem o mktime (3), nie modyfikując struct tm *. Właściwe zachowanie normalizuje wartość.

+0

Według 'man mktime' (http://linux.die.net/man/3/mktime) może (i robi) zmienić' stuct tm'. Normalizuje swoje wartości i wypełnia brakujące pola. – rve

+0

@rve wygląda na to, że masz rację. Źle zrozumiałem sformułowanie. Myślałem, że to normalizowanie dla celów ustawiania time_t. –

+0

Tak, implementacja jest nieprawidłowa ... –

Powiązane problemy