Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

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");
        return 1;
    }

    printf("Unix timestamp: %ld\n", timestamp);
    return 0;
  }
It is a C99 code snippet that parses the UTC time string and safely converts it to a Unix timestamp and it follows best practices from the SEI CERT C standard, avoiding locale and timezone issues by using UTC and timegm().

You can avoids pitfalls of mktime() by using timegm() which directly works with UTC time.

Where is the struggle? Am I misunderstanding it?

Oh by the way, must read: https://www.catb.org/esr/time-programming/ (Time, Clock, and Calendar Programming In C by Eric S. Raymond)



"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


Well, `Mon Jan 20 06:07:07 UTC 2025` does not match `fmt` in the code. My input matches the format string exactly, which is why it works.

You could use `"%a %b %d %H:%M:%S %Z %Y"` for `fmt` (which is indeed the default for `date`) and it would work with yours.

Both results in the same timestamp.


If I use "UTC" it works. For example,

date.l:

    int fileno (FILE *);
    FILE *f;
    int printf(const char *__restrict, ...);
    #include <time.h>
    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"|yydate


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.


timegm was finally standardized by C23, and POSIX-2024 mentions it in the FUTURE DIRECTIONS section of mktime. I don't know precisely what happened with POSIX. I think timegm got lost in the shuffle and by the time Austin Group attention turned back to it, it made more sense to let C23 pick it up first so there were no accidental conflicts in specification.[1]

[1] POSIX-2024 incorporates C17, not C23, but in practice the typical POSIX environment going forward will likely be targeting POSIX-2024 + C23, or just POSIX-2024 + extensions; and hopefully neither POSIX nor C will wait as long between standard updates as previously.


https://man7.org/linux/man-pages/man3/timegm.3.html

It's not posix, but it's pretty available


Yeah, you're correct that `timegm` is neither part of the C99 standard nor officially specified in POSIX.1-2024 but it is widely supported in practice on many platforms, including glibc, musl, and BSD systems which makes it a pragmatic choice in environments where it is available. Additionally, it is easy to implement it in a portable way when unavailable.

So, while `timegm` is not standardized in C99 or POSIX, it is a practical solution in most real-world environments, and alternatives exist for portability, and thus: handling time in C is not inherently a struggle.

As for the link, it says "You may want to bite the bullet and use timegm(3), even though it’s nominally not portable.", but see what I wrote above.


timegm() is even available on Haiku


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.


m4conf obviously has messy configure scripts; they are just written in m4. For instance, it somes with a 120 kilobyte file m4sugar which is fully of m4 cruft.

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.


While m4sugar is from GNU Autoconf (which is GPLv3), it's properly listed as a dependency and ISC is GPL-compatible, so there's no licensing issue that I know of. The code explicitly seems to avoid GNU m4-specific features for BSD compatibility, and it goes well beyond header-only testing. While shell scripting is a valid approach, m4conf provides structured macros for maintainable configuration and advanced features like runtime CPU capability detection. As far as I can tell, the code is well-documented and organized, though you raise fair points about the tradeoffs between shell and m4 approaches, but as others have mentioned it (and seen in example m4 file), it is extremely simple to use and works with third-party libraries as well.


> runtime CPU capability detection

You mean build-time (with m4conf, that is).


m4conf is not using anything requiring GNU stuff though, and it has been tested with BSD m4 as well. It is noted in base.m4.

The license of m4conf itself is ISC.

m4sugar could be vetted so it is can become less than 120 KB.

I don't know if it is messy, look at the example configuration file. For me, it is more straightforward and less bloated than autotools, for example.

> 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.

This is configurable as well in base.m4.


Perhaps an addition could be added, however, for third-party header files and functions.


I'll contact the author about this perhaps.

Oh and by the way:

> I don't think that it's enough to test for header files being present.

It checks for functions, too, not just header files, along with CPU features.


And "m4conf obviously has messy configure scripts" is not true, there are no scripts at all. Check out the examples. You cannot get any simpler.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: