[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)