5

Both on a Raspberry Pi and on a Ubuntu 16.04 x86_64 machine I have access to, running

# date -s @0

returns

date: cannot set date: Invalid argument
thu 1 jan 1970 01:00:00 CET

and I wonder:

  • what is the reasoning behind the impossibility,
  • whether there is a programmatic way of resetting the system time to Epoch.
1
  • I think the most obvious reasoning would be that since the creation of the concept of an "epoch time" it has been a time in the past, and therefore it is impossible that the current date/time will ever be the epoch time.
    – jesse_b
    Commented Aug 1, 2019 at 16:57

2 Answers 2

7

I can't reproduce “Invalid argument” for exactly the epoch on an older system, but:

# strace date -s '@-1'
…
clock_settime(CLOCK_REALTIME, {4294967295, 0}) = -1 EINVAL (Invalid argument)
settimeofday({4294967295, 0}, NULL)     = -1 EINVAL (Invalid argument)
write(2, "date: ", 6date: )                   = 6
write(2, "cannot set date", 15cannot set date)         = 15
write(2, ": Invalid argument", 18: Invalid argument)      = 18
write(2, "\n", 1

(And then date goes on to display the date that it wanted to set, even though it hasn't actually set it.)

In plain English, date is calling the kernel to set the date to one second before the epoch, and the kernel tells it that the proposed date is invalid.

Now in the trace above, you see 4294967295 as the number of seconds instead of -1. That number is 2^32-1 and I ran this on a 32-bit machine. This is actually not the source of the problem: it's a display problem in strace, which doesn't know whether the value is supposed to be signed or not. In fact the number of seconds is a signed integer of type time_t. Glibc 2.23 on Linux defines time_t as __time_t in /usr/include/time.h, __time_t as __TIME_T_TYPE in /usr/include/bits/types.h __TIME_T_TYPE as __SYSCALL_SLONG_TYPE which is __SQUAD_TYPE in /usr/include/bits/typesizes.h, and __SQUAD_TYPE as a 64-bit signed type in /usr/include/bits/types.h. On the kernel side, as of 4.4, the definition of the type of the argument of the settimeofday call is either struct timespec where the seconds are a __kernel_time_t which is a signed 64-bit type on 64-bit machines, or a time64_t which is a signed 64-bit type on 32-bit machines. So the kernel does see -1 as -1 and not some large positive number.

The reason you can't go back before the epoch is that the Linux kernel explicitly refuses to do so. The settimeofday system call returns EINVAL (“Invalid argument”) if timeval_valid rejects the given time structure, and that function rejects number of seconds that are negative.

Different versions of the kernel have code that's organized differently, but I don't think the behavior has changed.

I couldn't see any reason why a time of exactly 0 would be rejected and it worked in the VM where I tested it.

The reason for putting this sanity check is presumably that there's code out there that stores the time since the epoch as an unsigned integer, and thus cannot cope with dates that are before the epoch. Some code might interpret 0 as “the date isn't known”, so it would make sense to reject 0 too, but Linux doesn't actually do that, and it would only last for a second anyway.

Times before the epoch can certainly be represented and manipulated. A lot of software needs to track the time of past events. The timezone database that virtually every operating system uses has historical data going back to when timezones were codified (around the time railways started to take on). But you can't tell a Linux computer that the current time is before 1970.

2
  • Thank you, this all makes perfect sense and it is so thorough and logical that I could not have wished for anything better. Had I had more rep I would have awarded it to you---not that you need it, but this is the kind of answers that should be praised and used as an example.
    – wizclown
    Commented Aug 2, 2019 at 9:39
  • I would like to elaborate a bit the cases of which this question apply to. It is not only that you cant date -s '@0', but in fact, you can't do date -s '@X' where X satisfies X<number_of_seconds_since_last_power_on. The reasoning is the same as was pointed out in the answers above. So, as the time measured during the lifetime of the machine rises, the lower limit of the date you can set rises too.
    – e.ad
    Commented Mar 30, 2023 at 11:48
1

This can happen if the current timezone's idea of epoch is before the (UTC) Unix epoch. Such times just can't be represented.

3
  • 3
    @0 is the epoch, i.e. 1970-01-01 00:00:00 UTC. “Epoch” is independent of any timezone. And earlier times can be represented. Commented Aug 2, 2019 at 8:40
  • 1
    Just to further prove Gilles point, $ date -d '18151210 00:00:00' gives a correct representation of Ada Lovelace's birthday.
    – wizclown
    Commented Aug 2, 2019 at 9:43
  • @gilles, represented, yes; set as current time, no.
    – vonbrand
    Commented Aug 4, 2019 at 14:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .