# Convert a number of seconds elapsed to date from arbitrary start date

I want to convert a particular amount of seconds to a date. In my case the it's the number of seconds elapsed since 1st of January 0001.

If it were for seconds elapsed from epoch it would be easy: `\$ date -r nr_of_seconds`. It would be awesome if there was a way of telling `date` to start at a particular date. Is there such an option (the `-v` option almost does what I need, ... I think)?

I'm on a Mac.

• You need a geographic reference point to do that. If all your dates are post-epoch, you can just subtract the number of seconds before the epoch. Commented Aug 12, 2014 at 9:43
• @MichaelHomer The year 0001 is not post-epoch! And the problem is that most date/time functions cannot handle that. Commented Aug 12, 2014 at 9:45
• @vinc17: If all your dates are post-epoch, you can subtract. If they aren't, you need a) a geographic reference point and b) (something akin to) Julian day translation for that locale. That is what I said. Commented Aug 12, 2014 at 9:47
• there are 719164 days between 1/1/0001 (UT) and 1/1/1070 (UT). But if you want to compute the seconds, remember that earth didn't always spin with the same speed. You should decide what do you mean when you say "1/1/0001". Commented Aug 12, 2014 at 10:33

`date -r` almost does the job. All you need to do is shift the origin, which is an addition.

``````date -r \$((number_of_seconds - epoch))
``````

where `epoch` is the number of seconds between 1 January 1 and 1 January 1970. The value of `epoch` depends on your calendar.

In the Gregorian calendar, there are 477 leap years between 1 and 1970, so 365 * 1969 + 477 = 719162 days = 62135596800 seconds. Note that this number is greater than 232, so you'll need a shell capable of 64-bit arithmetic to handle it. Your `number_of_seconds` will be more than 232 anyway if it represents dates beyond the second century AD. I think bash supports 64-bit arithmetic even on older, 32-bit OSX but I'm not sure.

``````date -r \$((number_of_seconds - 62135596800))
``````

You can use this:

``````echo \$(( `date +%s` - ` date --date=yesterday +%s ` ))
86400
``````

You can replace 'yesterday' by any date. For example:

``````echo \$(( `date +%s` - ` date --date='Tue Aug 9 11:44:34 CEST 2014' +%s ` ))
259209
``````

Tested on GNU/Linux.

• It even works with the year 0001. Commented Aug 12, 2014 at 9:49
• Note that GNU `date` uses the Gregorian calendar (for all dates). Commented Aug 12, 2014 at 10:11
• it works with year 0001, but is it correct? Commented Aug 12, 2014 at 10:34
• @pqnet. good question. It disagrees with my wide_strftime on 0001-01-01 (and AFAIK, Julian and Gregorian calendars are meant to agree on that date). I remember checking against GNU cal when I wrote it so it would seem GNU date and GNU cal don't agree. Commented Aug 12, 2014 at 10:38
• @StéphaneChazelas I used aa.usno.navy.mil/data/docs/JulianDate.php to compute the value of 719164 days from 1/1/1 to 1/1/1970. It lets you input a date and yields the number of days from the from the julian epoch (somewhere around 4000 BC). Julian and Gregorian calendars agree on winter equinox of 325 AD (year of the first church council). From what I read on the page, it should be a difference of days between Julian 1/1/1 and Gregorian 1/1/1970 Commented Aug 12, 2014 at 10:45

The problem is that not everyone agrees on what the pre-1923 dates are. We (westerners) are now using the Gregorian calendar. Before 1582, people were using the Julian calendar. In between 1582 and 1923, some people used one or the other.

For instance, England switched to the Gregorian calendar in 1752 and that's what the `cal` command uses as the switching point. See the output of `cal 9 1752`.

So if you find an old English document that refers to the 3rd of November 1654, that's not necessarily the same date as the same 3rd of November 1654 referred to in a French document. Both the French and English people at the time would agree on what date 0001-01-01 was (as in for instance what happened on that day), but that's not the date GNU `date` for instance thinks it was.

I once wrote a few POSIX shell functions for arbitrary date calculation using the same calendar switch as `cal` and ignoring leap seconds. You can find it at: https://github.com/stephane-chazelas/misc-scripts/blob/master/wide_strftime.sh

For instance, to know what the date was 10G seconds (assuming 86400 seconds per day, so not all seconds lasting the same amount of time) after 0001-01-01 00:00:00 GMT Julian Calendar:

``````\$ timegm 1 1 1 0 0 0
\$ wide_strftime "%c" "\$((REPLY + 10000000000))"