[HN Gopher] The surprising struggle to get a Unix Epoch time fro...
       ___________________________________________________________________
        
       The surprising struggle to get a Unix Epoch time from a UTC string
       in C or C++
        
       Author : PascalW
       Score  : 65 points
       Date   : 2025-01-19 16:10 UTC (6 hours ago)
        
 (HTM) web link (berthub.eu)
 (TXT) w3m dump (berthub.eu)
        
       | udidnmem wrote:
       | You cannot since it's missing time zone
        
         | RHSeeger wrote:
         | UTC is a timezone, though. Or am I misunderstanding what you're
         | saying?
        
           | cvadict wrote:
           | 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, including leap second, DST, etc.)
        
           | jxjsndbxbd wrote:
           | UTC would be marked as +Z
           | 
           | Without any marking, it could be anything
        
             | loeg wrote:
             | The article explicitly mentions UTC all over the place.
             | It's UTC.
        
             | DamonHD wrote:
             | No '+'.
             | 
             | Noon UTC is "12:00Z".
        
       | sylware wrote:
       | Until you understand that the core of unix time is the "day", in
       | the end, you only need to know the first leap year (If I recall
       | properly it is 1972), then you have to handle the "rules" of leap
       | years, and you will be ok (wikipedia I think, don't use google
       | anymore since they now force javascript upon new web engines).
       | 
       | I did write such code in RISC-V assembly (for a custom command
       | line on linux to output the statx syscall output). Then, don't be
       | scared, with a bit of motivation, you'll figure it out.
        
         | DamonHD wrote:
         | The core of the UNIX time is _seconds_ since epoch, nothing
         | else.  'Day' has no special place at all. There are calendars
         | for converting to and from dates, including Western-style, but
         | the days in those calendars vary in length because of daylight
         | saving switches and leap seconds for example.
        
           | Kwpolska wrote:
           | UNIX time ignores leap seconds, so every day is exactly 86400
           | seconds, and every year is either 365*86400 or 366*86400
           | seconds. This makes converting from yyyy-mm-dd to UNIX time
           | quite easy, as you can just do `365*86400*(yyyy-1970) +
           | leap_years*86400` to get to yyyy-01-01.
        
             | XorNot wrote:
             | Well yes, in the sense that not all Unix epoch seconds are
             | equally long...
        
       | emcell wrote:
       | again, one of the many reasons i dont code in c or cpp anymore
        
         | pif wrote:
         | And the fox said: "These grapes are sour".
        
           | Dylan16807 wrote:
           | That makes no sense in this context. What's the situation
           | you're imagining where they _wanted_ to use C but something
           | else prevented them so they made up an excuse to call C bad?
           | 
           | You know sometimes people just dislike things, right?
        
         | ta-195678 wrote:
         | Was waiting for rustaceans to come and base c/cpp.. didn't take
         | long
        
       | 1970-01-01 wrote:
       | 13 more years to go until the 2038 problem.
       | 
       | Surely we'll have everything patched up by then..
        
         | ahubert wrote:
         | wow that is dedication 1970-01-01! :-)
        
       | chikere232 wrote:
       | 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 relevant for
       | the task they're trying to do. Why do they talk about daylight
       | savings time being confusing when they're only trying to deal
       | with UTC which doesn't have it?
        
         | pif wrote:
         | What's a man page? [cit]
        
           | johnisgood wrote:
           | "manual pages", type "man man" in your terminal.
           | 
           | https://man7.org/linux/man-pages/man1/man.1.html
        
         | johnisgood wrote:
         | 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)
        
           | paxcoder wrote:
           | 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.
        
             | chikere232 wrote:
             | https://man7.org/linux/man-pages/man3/timegm.3.html
             | 
             | It's not posix, but it's pretty available
        
             | johnisgood wrote:
             | 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.
        
               | oofabz wrote:
               | timegm() is even available on Haiku
        
       | zX41ZdbW wrote:
       | The first rule of thumb is to never use functions from glibc
       | (gmtime, localtime, mktime, etc) because half of them are non-
       | thread-safe, and another half use a global mutex, and they are
       | unreasonably slow. The second rule of thumb is to never use
       | functions from C++, because iostreams are slow, and a
       | stringstream can lead to a silent data loss if an exception is
       | thrown during memory allocation.
       | 
       | ClickHouse has the "parseDateTimeBestEffort" function:
       | https://clickhouse.com/docs/en/sql-reference/functions/type-...
       | and here is its source code:
       | https://github.com/ClickHouse/ClickHouse/blob/74d8551dadf735...
        
       | d_burfoot wrote:
       | My personal rule for time processing: use the language-provided
       | libraries for ONLY 2 operations: converting back and forth
       | between a formatted time string with a time zone, and a Unix
       | epoch timestamp. Perform all other time processing in your own
       | code based on those 2 operations, and whenever you start with a
       | new language or framework, just learn those 2.
       | 
       | I've wasted so many dreary hours trying to figure out crappy time
       | processing APIs and libraries. Never again!
        
       | jonstewart wrote:
       | The headline doesn't match the article. As it points out, C++20
       | has a very nice, and portable, time library. I quibble with the
       | article here, though: in 2025, C++20 is widely available.
        
         | jeffbee wrote:
         | Indeed. The article should be retitled "C still useless in
         | 2025, including time handling".
        
       | p0w3n3d wrote:
       | I think that time handling is the most hard thing in the world of
       | programming.
       | 
       | Explanation: you can learn heap sort or FFT or whatever algorithm
       | there is and implement it. But writing your own calendar from
       | scratch, that will do for example chron job on 3 am in the day of
       | DST transition, that works in every TZ, is a work for many people
       | and many months if not years...
        
         | timewizard wrote:
         | Time handling is exceptionally easy. Time zone handling is
         | hard. It doesn't help that the timezone database isn't actually
         | designed to make this any easier.
        
           | p0w3n3d wrote:
           | Meanwhile I edited my comment but we're still agreeing. And
           | adding them for example to embedded systems is additional
           | pain. Example: tram or train electronic boards / screens
        
       | rstuart4133 wrote:
       | For 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
       | result * 2 - time.mktime(time.gmtime(result))
       | 
       | If you are just using it for display this is usually fine as time
       | zone changes are usually timed to happen when nobody is looking.
        
         | chikere232 wrote:
         | 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
        
       | richrichie wrote:
       | > give us some truly excellent code that we really don't deserve
       | 
       | Why such self flagellation?
        
       ___________________________________________________________________
       (page generated 2025-01-19 23:00 UTC)