# GNU Date: inconsistency calculating number of days between dates

I am trying to calculate the number of days between two dates like this:

``````\$ echo \$(((\$(date +%s -d 2016/11/22)-\$(date +%s -d 2016/11/20))/(3600*24))) days
2 days
``````

That is the expected answer and perfectly consistent with this:

``````\$ date -d '2016/11/22 - 2 days'
Sun Nov 20 00:00:00 CET 2016
``````

However, these two seem to be inconsistent:

``````\$ echo \$(((\$(date +%s -d 2020/06/28)-\$(date +%s -d 2016/11/20))/(3600*24))) days
1315 days

\$ date -d '2020/06/28 - 1315 days'
Mon Nov 21 00:00:00 CET 2016
``````

Am I missing something? Why don't I get 1316 days (instead of 1315) in the third command I used?

I have done a few more tests changing the month in the date 2020/06/28. It seems that up to March I get the expected answer (i.e., I get Nov 20 in the fourth command), but from April on the inconsistency is present (i.e., I get Nov 21 in the fourth command). Any hints?

• integer overflow? wrong arithmetic expansion? – alecxs Aug 4 '20 at 16:55

Consider the following:

``````\$ date +%s -d 2020/06/28
1593316800
\$ date +%s -d 2016/11/20
1479618000
\$ echo \$(( 1593316800 - 1479618000 ))
113698800
\$ echo \$(( 113698800 / (3600*24) ))
1315                # integer, no rounding

\$ echo \$(( (3600*24) ))
86400
\$ echo "113698800/86400" | bc
1315
\$ echo "113698800/86400" | bc -l
1315.9583333333333333333
\$ printf "%.0f\n" \$(echo "113698800/86400" | bc -l)
1316                 # rounded to nearest integer
``````

Similar issue with `ksh2020` calculations:

``````\$ printf "%(%s)T\n" 2020/06/28
1593365691
\$ printf "%(%s)T\n" 2016/11/20
1479667133
\$ echo \$(( 1593365691 - 1479667133 ))
113698558
\$ echo \$(( 113698558/86400 ))
1315
\$ echo "113698558/86400" | bc -l
1315.95553240740740740740
``````

Setting the timezone to UTC solves the issue.

``````\$ cat test.sh
#!/bin/bash

edate="\$1"
sdate="\$2"

medate=\$(date +%s -d \$edate)
msdate=\$(date +%s -d \$sdate)
secs=\$(( medate - msdate ))

echo \$(( secs / 86400))
echo "\$secs / 86400" | bc -l
\$
\$ ./test.sh 2020/06/28 2016/11/20
1315
1315.95833333333333333333
\$ sudo timedatectl set-timezone UTC
\$  ./test.sh 2020/06/28 2016/11/20
1316
1316.00000000000000000000
``````

Alternatively, and easier, you can use the `date -u` option to produce the correct result.

-u, --utc, --universal print or set Coordinated Universal Time (UTC)

It would appear to be a daylight savings issue, possibly specific to your timezone setting.

The change from CET to CEST took place on the last Sunday of March, 2020/03/29. Hence the missing 3600 seconds from April on.

I get the correct answer just adding the option -u to date:

``````\$ echo \$(((\$(date +%s -u -d 2020/06/28)-\$(date +%s -u -d 2016/11/20))/(3600*24))) days
1316 days
``````

Obviously you would get the same just by adding the missing hour (3600 seconds) manually:

``````\$ echo \$(((\$(date +%s -d 2020/06/28)-\$(date +%s -d 2016/11/20)+3600)/(3600*24))) days
1316 days
``````

(If you try with 3599 instead of 3600, it goes back to 1315 days).

• "Obviously you would get the same just by adding the missing hour (3600 seconds) manually" only for timezones that switch by an hour twice yearly. You shouldn't assume that – roaima Feb 15 at 20:24