# 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? Aug 4, 2020 at 16:55

## 2 Answers

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.

Your answer is spot on, fpmurphy. Thank you very much.

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 Feb 15, 2021 at 20:24