Is it a struggle though? They needed to have a locale matching the language of the localised time string they wanted to parse, they needed to use strptime to parse the string, they needed to use timegm() to convert the result to seconds when seen as UTC. The man pages pretty much describe these things. The interface or these things could certainly be nicer, but most of the things they bring up as issues aren't even r…
What's a man page? [cit]
The surprising struggle to get a Unix Epoch time from a UTC string in C or C++
91–100 of 106 posts
Re: The surprising struggle to get a Unix Epoch time from a UTC string in C or C++
#92For those skimmimg the problem is mktime() returns local time, and they want it in UTC. So you need to subtract the timezone used, but the timezone varies by date you feed mktime() and there is no easy way to determime it. If you are happy for the time to perhaps be wrong around the hours timezone changes, this is an easy hack: import time def time_mktime_utc(_tuple): result = time.mktime(_tuple[:-1] + (0,)) return r…
That is not really the problem. mktime() parses the time string which lacks any information on time zones then the article uses timegm() to convert it to unixtime on the assumption that it was in UTC also it's about C
No, mktime() doesn't parse a string. Parsing the string is done by strptime(). mktime() takes the output of strptime(), which is a C structure or the equivalent in Python - a named tuple with the same fields.
> the time string lacks any information on time zones
Not necessarily. Time strings often contain a time zone. The string you happen to be parsing doesn't contain a time zone you could always append one. If it did have a time zone you could always change it to UTC. So this isn't the problem either.
The root cause of the issue is the "struct tm" that strptime() outputs didn't have field for the time zone so if the string has one, it is lost. mktime() needs that missing piece of information. It solves that problem by assuming the missing time zone is local time.
> then the article uses timegm() to convert it to unixtime on the assumption that it was in UTC
It does, but timegm() is not a POSIX function so isn't available on most platforms. gmtime() is a POSIX function and is available everywhere. It doesn't convert a "struct tm", but it does allow you to solve the core problem the article labours over, which is finding out what time zone offset mktime() used. With that piece of information it's trivial to convert to UTC, as the above code demonstrates in 2 lines.
> also it's about C
The python "time" module is a very thin wrapper around the POSIX libc functions and structures. There is a one to one correspondence, mostly with the same names. Consequently any experienced C programmer will be able translate the above python to C. I chose Python because it expresses the same algorithm much more concisely.
Re: The surprising struggle to get a Unix Epoch time from a UTC string in C or C++
#93The concept of a process-wide locale was a mistake. All locale-dependent functons should be explicit. Yes that means some programs won't respect your locale because the author didn't care to add support but at least they won't break in unexpected ways because some functions magically work differently between the user's and developers system.
It was a very reasonable design when most programs were local-only.
Re: The surprising struggle to get a Unix Epoch time from a UTC string in C or C++
#94Earlier quoted context omitted.
That is not really the problem. mktime() parses the time string which lacks any information on time zones then the article uses timegm() to convert it to unixtime on the assumption that it was in UTC also it's about C
> mktime() parses the time string No, mktime() doesn't parse a string. Parsing the string is done by strptime(). mktime() takes the output of strptime(), which is a C structure or the equivalent in Python - a named tuple with the same fields. > the time string lacks any information on time zones Not necessarily. Time strings often contain a time zone. The string you happen to be parsing doesn't contain a time zone yo…
Re: The surprising struggle to get a Unix Epoch time from a UTC string in C or C++
#95Earlier quoted context omitted.
UTC is a timezone, though. Or am I misunderstanding what you're saying?
That is fine as long as the input / output is always in UTC... but at the end of the day you often want to communicate that timepoint to a human user (e.g. an appointment time, the time at which some event happened, etc.), which is when our stupid monkey brains expect the ascii string you are showing us to actually make sense in our specific locale (including all of the warts each of those particular timezones have,…
But the title specifically say "from a UTC string", so it _is_ a UTC string, always.
> ascii string you are showing us to actually make sense in our specific locale
Locale and TZ are two completely separate things. You can use any locale in any TZ. You can use any locale in any location, too.
Re: The surprising struggle to get a Unix Epoch time from a UTC string in C or C++
#96Earlier quoted context omitted.
It is not. int main(void) { struct tm tm = {0}; const char *time_str = "Mon, 20 Jan 2025 06:07:07 GMT"; const char *fmt = "%a, %d %b %Y %H:%M:%S GMT"; // Parse the time string if (strptime(time_str, fmt, &tm) == NULL) { fprintf(stderr, "Error parsing time\n"); return 1; } // Convert to Unix timestamp (UTC) time_t timestamp = timegm(&tm); if (timestamp == -1) { fprintf(stderr, "Error converting to timestamp\n"); retur…
I can't find `timegm` neither in the C99 standard draft nor in POSIX.1-2024. The first sentence of your link reads: >The C/Unix time- and date-handling API is a confusing jungle full of the corpses of failed experiments and various other traps for the unwary, many of them resulting from design decisions that may have been defensible when the originals were written but appear at best puzzling today.
Re: The surprising struggle to get a Unix Epoch time from a UTC string in C or C++
#97Earlier quoted context omitted.
It was a very reasonable design when most programs were local-only.
It really wasn't. Even local-only programs need to process data that isn't formatted in the user's locale.
But you don't want to be processing data in locale dependent-ways using the crap available in ISO C.
Re: The surprising struggle to get a Unix Epoch time from a UTC string in C or C++
#98Earlier quoted context omitted.
It is not. int main(void) { struct tm tm = {0}; const char *time_str = "Mon, 20 Jan 2025 06:07:07 GMT"; const char *fmt = "%a, %d %b %Y %H:%M:%S GMT"; // Parse the time string if (strptime(time_str, fmt, &tm) == NULL) { fprintf(stderr, "Error parsing time\n"); return 1; } // Convert to Unix timestamp (UTC) time_t timestamp = timegm(&tm); if (timestamp == -1) { fprintf(stderr, "Error converting to timestamp\n"); retur…
"Mon, 20 Jan 2025 06:07:07 GMT" I thought the default output of date(1), with TZ unset, is something like Mon Jan 20 06:07:07 UTC 2025 That's the busybox default anyway
date.l:
int fileno (FILE *);
FILE *f;
int printf(const char *__restrict, ...);
#include
char *strptime(const char *s, const char *f, struct tm *tm);
struct tm t;
a (Mon|Tue|Wed|Thu|Fri|Sat|Sun)
b (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
d [0-2][0-9]|3[01]
H [0-2][0-9]
M [0-5][0-9]
S [0-5][0-9]
Y [1-9][0-9][0-9][0-9]
%option nounput noinput noyywrap
%%
{a}[ ]{b}[ ]{d}[ ]{H}:{M}:{S}[ ]UTC[ ]{Y} {
strptime(yytext,"%a %b %d %H:%M:%S UTC %Y",&t);
printf("%ld\n",mktime(&t));
}
.|\n
%%
int main(){yylex();exit(0);}
flex -8Cem date.l
cc -O3 -std=c89 -W -Wall -pipe lex.yy.c -static -s -o yydate
date|yydate
This works for me. No need for timegm().But if I substitute %Z or %z for "UTC" in strptime() above then this does not work.
Fun fact: strptime() can make timestamps for dates that do not exist on any calandar.
echo "Thu Jun 31 01:59:26 UTC 2024"|yydateRe: The surprising struggle to get a Unix Epoch time from a UTC string in C or C++
#99Earlier quoted context omitted.
I can't find `timegm` neither in the C99 standard draft nor in POSIX.1-2024. The first sentence of your link reads: >The C/Unix time- and date-handling API is a confusing jungle full of the corpses of failed experiments and various other traps for the unwary, many of them resulting from design decisions that may have been defensible when the originals were written but appear at best puzzling today.
Here is some of my code that works around not having timegm. It is detected in a configure script, so there's a #define symbol indicating whether it's available. https://www.kylheku.com/cgit/txr/tree/time.c
[1] https://zolk3ri.name/cgit/m4conf/about/
Nice job though.
Re: The surprising struggle to get a Unix Epoch time from a UTC string in C or C++
#100Earlier quoted context omitted.
Here is some of my code that works around not having timegm. It is detected in a configure script, so there's a #define symbol indicating whether it's available. https://www.kylheku.com/cgit/txr/tree/time.c
Regarding "detected in a configure script", one could use m4conf[1] which is lightweight and does the job without messy configure scripts. [1] https://zolk3ri.name/cgit/m4conf/about/ Nice job though.
Oh look, m4sugar.m4 is taken from GNU Autoconf and is GPLv3. The. m4conf project's master license doesn't mention this; it's a "BSD1" type license (like BSD2, but with no requirement for the copyright notice to appear in documentation or accompanying materials). Oops!
m4sugar says that it requires GNU m4, not just any POSIX m4.
I wrote the configure script in shell because that's what I decided I can depend on being present in the target systems. I deliberately rejected any approach involving m4 to show that a GNU style configure script can be obtained in as straightforward way, without convoluted metaprogramming.
There is a lot of copy-paste programming in my configure script, but it doesn't have to be that way; a script of this type can be better organized than my example. Anyway, you're not significantly disadvantaged writing in shell compared to m4, especially if you're mostly interested in probing the environment, not complex text generation.
I don't think that it's enough to test for header files being present. Almost all my tests target library features: including a header, calling some functions and actually linking a program. The contents of headers vary from system to system and with compiler options.