Dakuan
Anmeldungsdatum: 2. November 2004
Beiträge: 6339
Wohnort: Hamburg
|
Ich versuche gerade eine UTC (GMT) Zeitangabe, die in Textform vorliegt, in ein lokales Datum umzuwandeln. Dabei soll die Zeitzone und die Sommerzeit berücksichtigt werden. Aber irgendwas mache ich dabei falsch. 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | // gmt2loc.c
// gcc -Wall -g -o gmt2loc gmt2loc.c
//
#define _XOPEN_SOURCE
#include <stdio.h>
#include <string.h>
#include <time.h>
int
main( int argc, char * argv[] ) {
const char * gmt_time_str = "2022-11-23 10:12:51";
char out[32];
size_t len;
time_t unix_tm;
struct tm * local;
struct tm tmp_gmt;
printf( "in: %s\n", gmt_time_str );
memset( &tmp_gmt, 0, sizeof(struct tm) );
tmp_gmt.tm_isdst = -1;
strptime( gmt_time_str, "%F %T", &tmp_gmt );
unix_tm = mktime( &tmp_gmt );
local = localtime( &unix_tm );
len = strftime( out, 30, "%F %T", local );
printf( "out: %s\n", out );
return 0;
}
|
Kann mir da jemand auf die Sprünge helfen?
|
lubux
Anmeldungsdatum: 21. November 2012
Beiträge: 13896
|
Dakuan schrieb: Ich versuche gerade eine UTC (GMT) Zeitangabe, die in Textform vorliegt, in ein lokales Datum umzuwandeln. Dabei soll die Zeitzone und die Sommerzeit berücksichtigt werden.
Evtl. im source code von date nachschauen:
:~$ TZ=UTC date -d @"$(date +%s -d "2022-11-23 10:12:51")"
Mi 23. Nov 09:12:51 UTC 2022
:~$ TZ=UTC date -d @"$(date +%s -d "2022-09-23 10:12:51")"
Fr 23. Sep 08:12:51 UTC 2022
:~$ TZ='Europe/Berlin' date -d @"$(TZ=UTC date +%s -d "2022-11-23 10:12:51")"
Mi 23. Nov 11:12:51 CET 2022
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Ich denke das Problem ist, dass du den String für die Zeit in UTC in Lokalzeit parsed - probier es mal so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 | #define _XOPEN_SOURCE
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int
main( int argc, char * argv[] ) {
const char * gmt_time_str = "2022-11-23 10:12:51";
char out[32];
size_t len;
struct tm mytm = {0};
time_t mytime;
// set timezone to UTC
setenv("TZ", "UTC", 1);
tzset();
// parse time string
printf( "in: %s\n", gmt_time_str );
strptime( gmt_time_str, "%F %T", &mytm );
mytime = mktime(&mytm);
// revert timezone change
unsetenv("TZ");
tzset();
// print the new time
localtime_r(&mytime, &mytm);
len = strftime( out, 30, "%F %T", &mytm );
printf( "out: %s\n", out );
return 0;
}
|
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6339
Wohnort: Hamburg
|
Danke seahawk1986, das scheint zu funktionieren. Ich frage mich allerdings, warum ich solche Tricks in den Dokus nicht entdecken konnte. Kann aber auch daran liegen, das mir da die Zusammenhänge noch nicht ganz klar sind. Die Anfragen an die bekannten Suchmaschinen zeigen jedenfalls, dass ich nicht der einzige mit diesem Problem bin. Die gefundenen Lösungen fand ich aber nicht so überzeugend wie Deine Lösung. Die erscheint mir aber überraschend logisch, wenn man den Mechanismus kennt. Ich werde das morgen mal in meine eigentliche Anwendung einbauen und dann berichten. p.s. Es überrascht mich allerdings, dass man hier den Umweg über das Environment gehen muss. aber wenn es funktioniert ...
|
seahawk1986
Anmeldungsdatum: 27. Oktober 2006
Beiträge: 11176
Wohnort: München
|
Das war der einfachste Weg, den ich auf die Schnelle gefunden habe - wenn man das richtig machen will, nimmt man eine Bibliothek, die die Nutzing von Zeitzonen beherrscht - C++20 kann das z.B. mit std::chrono aus der STL - leider sind GCC (und Clang) noch nicht soweit, dass sie C++20 vollständig nutzen können, aber mit MSVC funktioniert das unter Windows schon mal recht elegant:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | #include <chrono>
#include <iostream>
int main()
{
std::chrono::utc_clock::time_point utc_tp;
std::istringstream ss("2022-11-23 10:12:51");
ss >> std::chrono::parse("%F %T", utc_tp);
if (ss.fail())
std::cout << "Parse failed\n";
else {
auto tp_sys = std::chrono::clock_cast<std::chrono::system_clock>(utc_tp);
std::chrono::zoned_time localtime{ "Europe/Berlin", tp_sys};
std::cout << "UTC: " << std::format("{:%F %T}", tp_sys) << '\n';
std::cout << "Lokalzeit: " << std::format("{:%F %T}", localtime) << '\n';
}
return 0;
}
|
Und liefert dann:
UTC: 2022-11-23 10:12:51.0000000
Lokalzeit: 2022-11-23 11:12:51.0000000
|
snafu1
Anmeldungsdatum: 5. September 2007
Beiträge: 2123
Wohnort: Gelsenkirchen
|
Ist leider bei allen länderabhängigen Dingen so. Wenn man Dezimalzahlen entsprechend formatieren will (in dem Fall: Komma statt Punkt), dann läuft das auch über Umgebungsvariablen.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6339
Wohnort: Hamburg
|
Die Umwandlung funktioniert jetzt auch in der in der eigentlichen Anwendung. Ich habe da jetzt noch eine andere Idee, aber bevor ich mich damit blamiere, will ich die erst testen.
|
Dakuan
(Themenstarter)
Anmeldungsdatum: 2. November 2004
Beiträge: 6339
Wohnort: Hamburg
|
Gut, dass ich die "Luftnummer" gestern nicht näher erläutert hatte. Aber ich hatte weiter gesucht. Aufgrund eines Kommentars auf Stack Overflow hatte ich mal einen Blick in <time.h> geworfen und da die Funktion timegm() gefunden. Man muss dann nur noch die tm Struktur richtig ausfüllen und "_DEFAULT_SOURCE" aktivieren (keine Ahnung warum). Hier das vorläufige Endergebnis:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 | // gmt2loc4.c
// gcc -Wall -g -o gmt2loc gmt2loc4.c
//
//#define _XOPEN_SOURCE
#define _DEFAULT_SOURCE // timegm()
#include <stdio.h>
#include <string.h>
#include <time.h>
int
fill_tm( struct tm * tmptr, const char * dstr ) {
int year, mon, day, hour, min, sec;
memset( tmptr, 0, sizeof(struct tm) );
if( sscanf( dstr, "%d-%d-%d %d:%d:%d", &year, &mon, &day, &hour, &min, &sec ) == 6 ){
tmptr->tm_sec = sec;
tmptr->tm_min = min;
tmptr->tm_hour = hour;
tmptr->tm_mday = day;
tmptr->tm_mon = mon - 1;
tmptr->tm_year = year - 1900;
return 0;
}
return -1;
}
int
main( int argc, char * argv[] ) {
// const char * gmt_time_str = "2022-11-23 10:12:51";
const char * gmt_time_str = "2022-06-03 10:12:51"; // DST
char out[32];
time_t unix_tm;
struct tm * local;
struct tm tmp_gmt;
printf( "in: %s\n", gmt_time_str );
fill_tm( &tmp_gmt, gmt_time_str );
unix_tm = timegm( &tmp_gmt );
local = localtime( &unix_tm );
strftime( out, 30, "%F %T", local );
printf( "out: %s\n", out );
return 0;
}
|
|