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

The C standard does not require time_t to be signed (nor does POSIX). Just changing the 32-bit type to unsigned would (in some senses) extend the lifetime of the type out to 2106. You could at least avoid some classes of ABI breakage in this way. (On the other hand, Glibc has explicitly documented that its time_t is always signed. So they do not have this option.)


While that avoids 2038 as a "drop dead" date for 32-bit time_t, it also removes the ability to represent any date/time prior to 00:00:00 UTC on 1 January 1970 using 32-bit time_t because you lose the ability to represent negative values.

Having all existing stored date/times that are currently prior to the epoch suddenly become dates post 2038 is also not a good scenario.


> it also removes the ability to represent any date/time prior to 00:00:00 UTC on 1 January 1970 using 32-bit time_t

Yes, of course. This is probably not the main use of negative values with signed time_t, though -- which is just representing the result of subtraction when the operand happened before the subtrahend.

> Having all existing stored date/times that are currently prior to the epoch suddenly become dates post 2038 is also not a good scenario.

In practice, there are ~zero of these on systems with 32-bit time_t and a challenging migration path as we approach 2038.


> Yes, of course. This is probably not the main use of negative values with signed time_t, though -- which is just representing the result of subtraction when the operand happened before the subtrahend.

This is definitely a bigger concern, yes. One has to be very careful with subtraction of timestamps. But to be fair one already had to be very careful before because POSIX doesn't say what the size or signedness of `time_t` is to begin with.

Indeed, in POSIX `time_t` can even be `float` or `double`[0]!

  time_t and clock_t shall be integer or real-floating types.
Though on all Unix, BSD, Linux, and any Unix-like systems thankfully `time_t` is always integral. It's really only size and signedness that one has to be careful with.

Thus one should always subtract only the smaller value from the larger, and cast the result to a signed integer. And one has to be careful with overflow. Fortunately `difftime()` exists in POSIX. And there's a reason that `difftime()` returns a `double`: to avoid having the caller have to deal with overflows.

Basically working safely with `time_t` arithmetic is a real PITA.

  [0] https://pubs.opengroup.org/onlinepubs/009696799/basedefs/sys/types.h.html


> Indeed, in POSIX `time_t` can even be `float` or `double`[0]!

Standard C, yes. Newer POSIX (your link is to the 2004 version) requires time_t be an integer type: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sy...

> Though on all Unix, BSD, Linux, and any Unix-like systems thankfully `time_t` is always integral. It's really only size and signedness that one has to be careful with. Thus one should always subtract only the smaller value from the larger, and cast the result to a signed integer. And one has to be careful with overflow. Fortunately `difftime()` exists in POSIX. And there's a reason that `difftime()` returns a `double`: to avoid having the caller have to deal with overflows.

> Basically working safely with `time_t` arithmetic is a real PITA.

Yes.


Yes, I know that was older POSIX. But we're talking about old code, the unstated context is portability over a long period of time, and I wanted to make a point :)

So use `difftime()`, don't assume signedness or size, but do assume that it's an integral type.


Stored _where_ exactly?


You would then lose the ability to represent times before Jan. 1st, 1970. Which is not just a theoretical concern; those times appear e.g. in databases with people's date of birth.


And a signed 32 bit time_t with an epoch of 1970 cannot represent dates before 1902. Using time_t to store legacy dates is not advisable - even if you ignore all the issues with time zones and changing local laws pertaining to offsets from UTC and daylight saving time.


While true, that limitation has always existed, so everyone has already implemented whatever was necessary to represent dates earlier than that.

Changing 32-bit time_t to unsigned suddenly makes all dates from 1902 to Jan 1 1970 which were stored using time_t (even if it was non-advisable, it still will have occurred) appear to teleport into the future beyond 2038.


That's alright, see, because I have no filesystems, no tarballs, no backups, no files on any kind of media with timestamps before 1970, and indeed, no one can except by manually setting those timestamps -- and why bother doing that?!

So any pre-1970 32-bit signed timestamps will be in... not spreadsheets, in what? In databases? No, not either. So in some sort of documents, so software consuming those will need fixing, but we're not going to see much teleporting of 1902-1970 timestamps to 2038-2106. I'm not concerned.


Many important software projects predate UNIX. Perhaps you want to create a Git repository for one of them, with historically accurate commit timestamps?


Well, Git doesn't seem to set file timestamps when cloning. And as the sibling comment says, Git doesn't use 32-bit signed integers to store timestamps. So this is not a problem.

If, however, Git were to some day get an option to set file mtimes and atimes at clone time to the last-modified time of the files based on commit history, then you could always just use a 64-bit system where `time_t` is 64-bit.


> Well, Git doesn't seem to set file timestamps when cloning.

This is intentional btw because otherwise with many build system things would not get rebuilt correctly when checking out an older snapshot.


More importantly than a git repository, you might have archives (a .tar or equivalent) of these software projects, and might want to unpack them while preserving the timestamps contained within these archives.


Unix did not exist before 1970. Neither did tar. There are no tar files with files with timestamps before 1970 _unless_ you've used `touch -t 195001010000` or `utime(2)` or `futimes(3)` to set the files' time to before 1970. That seems pretty unlikely.


If I create a new archive format today and use it to archive the contents of my disk or whatever USB stick I find do you not thing it might end up containing files with timestamps before today?


Git represents timestamps in ASCII strings, like "12345." Not time_t. (I am not sure if it even allows negative integers in this format.)


I was just using Git as an example of an application where pre-1970 timestamps could be useful. But as it turns out,

  $ git commit -m foo --date='1969-12-31 00:00:00'
  [main 25b6e63] foo
   Date: Sun Dec 30 23:00:00 2012 -0500
   1 file changed, 0 insertions(+), 0 deletions(-)
   create mode 100644 bar


Serious question: do people use time_t for representing a date of birth?

To me that wouldn't seem right: a date of birth isn't a timestamp and you typically receive it without a corresponding place or time zone so there's no reasonable way to convert it into a timestamp.

(The other problem is that a signed 32-bit time_t only goes back to 1901. You might not have to deal with a date of birth before 1901 today, unless you're doing genealogy, of course, but until fairly recently it's something you'd probably want to be able to handle.)


> Serious question: do people use time_t for representing a date of birth?

I have seen people in real life use seconds since the UNIX epoch to represent DOB, yes.


My birth certificate has location, day, year, hour, and minute of birth. Birth is an event in time, perfectly represented with a (UTC) timestamp.


Your birth is an event that happened at an instant in time, but very few systems concern themselves with that detail. The vast majority need to store birth _date_ and have no interest in the time or location.


> have no interest in the time

Setting the bottom couple of bytes to zero achieves this, while maintaining nearly universal consistency with all other events in time that might need to be related with a packing of bits. People do it because it's what's being used at nearly every other level of the stack.


> Birth is an event in time, perfectly represented with a (UTC) timestamp.

That's not the same thing as `time_t` though. `time_t` is UTC. UTC is not `time_t`.


Databases do not and can not use system time_t. Consider how their on-disk state would be impacted by a change from 32-bit time_t to 64-bit! Instead they use specific or variable size integer types.


Broad statements like this are universally untrue.


Does any database actually use time_t? PostgreSQL uses its own datatype, the number of microseconds since 4713 BC. I am sure that other databases do the same.

https://www.postgresql.org/docs/current/datatype-datetime.ht...


How the timestamps are stored on disk is irrelevant if the code data from those databases ends up using time_t (e.g. because it needs to compare stored timestamps with the current time).


Those databases might not even use `time_t`. It's their problem anyways, not the OS's.


Openbsd did just this for 32bit compat when they changed to 64bit time 12 years ago, and seems to have worked out fine.


No, time_t is a signed 64-bit type on all architectures, 64-bit architectures have no "32bit compat".

https://www.openbsd.org/55.html


From the notes, this is what i was referring to, I think I just mistook the meaning -

Parts of the system that could not use 64-bit time_t were converted to use unsigned 32-bit instead, so they are good till the year 2106


Ah yes, let's introduce subtle bugs or code that calculates the difference between two time_t's where the result can be negative.

If something is effectively always signed you can assume that things depend on it being signed even if the standard doesn't guarantee it. If you are building a Linux distribution you can't just handwave such code away as "technically it was already broken on this theoretical POSIX compliant platform that no one uses".


If time_t is unsigned, how do times before the unix epoch get represented?


They don't, much like they already do not. 32-bit time_t has always been finite, and 1970 was a long, long time ago. (See "in some senses" in my earlier comment.)


1970 is not all that long ago when there are stil plenty of people born before that alive today. People with the attitude you are displaying should be kept far far away from time handling code.


>1970 was a long long time

I thought it was a time_t! (≧◡≦)




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

Search: