How to find the difference in days between two dates?

BashShellDate

Bash Problem Overview


A="2002-20-10"
B="2003-22-11"

How to find the difference in days between two dates?

Bash Solutions


Solution 1 - Bash

The bash way - convert the dates into %y%m%d format and then you can do this straight from the command line:

echo $(( ($(date --date="031122" +%s) - $(date --date="021020" +%s) )/(60*60*24) ))

Solution 2 - Bash

If you have GNU date, it allows to print the representation of an arbitrary date (-d option). In this case convert the dates to seconds since EPOCH, subtract and divide by 24*3600.

Example using GNU date (from https://stackoverflow.com/a/9008871/215713):

let DIFF=($(date +%s -d 20210131)-$(date +%s -d 20210101))/86400
echo $DIFF
30

This also works with dates in other formats, for example "2021-01-31".

Other answers suggest ways to do it that don't require GNU date.

Solution 3 - Bash

tl;dr

date_diff=$(( ($(date -d "2015-03-11 UTC" +%s) - $(date -d "2015-03-05 UTC" +%s)) / (60*60*24) ))

Watch out! Many of the bash solutions here are broken for date ranges which span the date when daylight savings time begins (where applicable). This is because the $(( math )) construct does a 'floor'/truncation operation on the resulting value, returning only the whole number. Let me illustrate:

DST started March 8th this year in the US, so let's use a date range spanning that:

start_ts=$(date -d "2015-03-05" '+%s')
end_ts=$(date -d "2015-03-11" '+%s')

Let's see what we get with the double parentheses:

echo $(( ( end_ts - start_ts )/(60*60*24) ))

Returns '5'.

Doing this using 'bc' with more accuracy gives us a different result:

echo "scale=2; ( $end_ts - $start_ts )/(60*60*24)" | bc

Returns '5.95' - the missing 0.05 being the lost hour from the DST switchover.

So how should this be done correctly?
I would suggest using this instead:

printf "%.0f" $(echo "scale=2; ( $end_ts - $start_ts )/(60*60*24)" | bc)

Here, the 'printf' rounds the more accurate result calculated by 'bc', giving us the correct date range of '6'.

Edit: highlighting the answer in a comment from @hank-schultz below, which I have been using lately:

date_diff=$(( ($(date -d "2015-03-11 UTC" +%s) - $(date -d "2015-03-05 UTC" +%s) )/(60*60*24) ))

This should also be leap second safe as long as you always subtract the earlier date from the later one, since leap seconds will only ever add to the difference - truncation effectively rounds down to the correct result.

Solution 4 - Bash

And in python

$python -c "from datetime import date; print (date(2003,11,22)-date(2002,10,20)).days"
398

Solution 5 - Bash

This works for me:

A="2002-10-20"
B="2003-11-22"
echo $(( ($(date -d $B +%s) - $(date -d $A +%s)) / 86400 )) days

Prints

398 days

What is happening?

  1. Provide valid time string in A and B
  2. Use date -d to handle time strings
  3. Use date %s to convert time strings to seconds since 1970 (unix epoche)
  4. Use bash parameter expansion to subtract seconds
  5. divide by seconds per day (86400=606024) to get difference as days
  6. ! DST is not taken into account ! See this answer at unix.stackexchange!

Solution 6 - Bash

Here's the MacOS X / *BSD version for your convenience.

$ A="2002-20-10"; B="2003-22-11";
$ echo $(((`date -jf %Y-%d-%m "$B" +%s` - `date -jf %Y-%d-%m "$A" +%s`)/86400))

nJoy!

Solution 7 - Bash

If the option -d works in your system, here's another way to do it. There is a caveat that it wouldn't account for leap years since I've considered 365 days per year.

date1yrs=`date -d "20100209" +%Y`
date1days=`date -d "20100209" +%j`
date2yrs=`date +%Y`
date2days=`date +%j`
diffyr=`expr $date2yrs - $date1yrs`
diffyr2days=`expr $diffyr \* 365`
diffdays=`expr $date2days - $date1days`
echo `expr $diffyr2days + $diffdays`

Solution 8 - Bash

Even if you don't have GNU date, you'll probably have Perl installed:

use Time::Local;
sub to_epoch {
  my ($t) = @_; 
  my ($y, $d, $m) = ($t =~ /(\d{4})-(\d{2})-(\d{2})/);
  return timelocal(0, 0, 0, $d+0, $m-1, $y-1900);
}
sub diff_days {
  my ($t1, $t2) = @_; 
  return (abs(to_epoch($t2) - to_epoch($t1))) / 86400;
}
print diff_days("2002-20-10", "2003-22-11"), "\n";

This returns 398.041666666667 -- 398 days and one hour due to daylight savings.


The question came back up on my feed. Here's a more concise method using a Perl bundled module

days=$(perl -MDateTime -le '
    sub parse_date { 
        @f = split /-/, shift;
        return DateTime->new(year=>$f[0], month=>$f[2], day=>$f[1]); 
    }
    print parse_date(shift)->delta_days(parse_date(shift))->in_units("days");
' $A $B)
echo $days   # => 398

Solution 9 - Bash

Here's my working approach using zsh. Tested on OSX:

# Calculation dates
## A random old date
START_DATE="2015-11-15"
## Today's date
TODAY=$(date +%Y-%m-%d)

# Import zsh date mod
zmodload zsh/datetime

# Calculate number of days
DIFF=$(( ( $(strftime -r %Y-%m-%d $TODAY) - $(strftime -r %Y-%m-%d $START_DATE) ) / 86400 ))
echo "Your value: " $DIFF

Result:

Your value:  1577

Basically, we use strftime reverse (-r) feature to transform our date string back to a timestamp, then we make our calculation.

Solution 10 - Bash

Using mysql command

$ echo "select datediff('2013-06-20 18:12:54+08:00', '2013-05-30 18:12:54+08:00');"  | mysql -N

Result: 21

NOTE: Only the date parts of the values are used in the calculation

Reference: <http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_datediff>

Solution 11 - Bash

This is the simplest i managed to get working on centos 7:

OLDDATE="2018-12-31"
TODAY=$(date -d $(date +%Y-%m-%d) '+%s')
LINUXDATE=$(date -d "$OLDDATE" '+%s')
DIFFDAYS=$(( ($TODAY - $LINUXDATE) / (60*60*24) ))

echo $DIFFDAYS

Solution 12 - Bash

I'd submit another possible solution in Ruby. Looks like it's the be smallest and cleanest looking one so far:

A=2003-12-11
B=2002-10-10
DIFF=$(ruby -rdate -e "puts Date.parse('$A') - Date.parse('$B')")
echo $DIFF

Solution 13 - Bash

Another Python version:

python -c "from datetime import date; print date(2003, 11, 22).toordinal() - date(2002, 10, 20).toordinal()"

Solution 14 - Bash

Use the shell functions from http://cfajohnson.com/shell/ssr/ssr-scripts.tar.gz; they work in any standard Unix shell.

date1=2012-09-22
date2=2013-01-31
. date-funcs-sh
_date2julian "$date1"
jd1=$_DATE2JULIAN
_date2julian "$date2"
echo $(( _DATE2JULIAN - jd1 ))

See the documentation at http://cfajohnson.com/shell/ssr/08-The-Dating-Game.shtml

Solution 15 - Bash

on unix you should have GNU dates installed. you do not need to deviate from bash. here is the strung out solution considering days, just to show the steps. it can be simplified and extended to full dates.

DATE=$(echo `date`)
DATENOW=$(echo `date -d "$DATE" +%j`)
DATECOMING=$(echo `date -d "20131220" +%j`)
THEDAY=$(echo `expr $DATECOMING - $DATENOW`)

echo $THEDAY 

Solution 16 - Bash

This assumes that a month is 1/12 of a year:

#!/usr/bin/awk -f
function mktm(datespec) {
  split(datespec, q, "-")
  return q[1] * 365.25 + q[3] * 365.25 / 12 + q[2]
}
BEGIN {
  printf "%d\n", mktm(ARGV[2]) - mktm(ARGV[1])
}

Solution 17 - Bash

Command line bash solution

echo $((($(date +%s -d 20210131)-$(date +%s -d 20210101))/86400)) days

will print

30 days

Solution 18 - Bash

Give this a try:

perl -e 'use Date::Calc qw(Delta_Days); printf "%d\n", Delta_Days(2002,10,20,2003,11,22);'

Solution 19 - Bash

Assume we rsync Oracle DB backups to a tertiary disk manually. Then we want to delete old backups on that disk. So here is a small bash script:

#!/bin/sh

for backup_dir in {'/backup/cmsprd/local/backupset','/backup/cmsprd/local/autobackup','/backup/cfprd/backupset','/backup/cfprd/autobackup'}
do

    for f in `find $backup_dir -type d -regex '.*_.*_.*' -printf "%f\n"`
    do

        f2=`echo $f | sed -e 's/_//g'`
        days=$(((`date "+%s"` - `date -d "${f2}" "+%s"`)/86400))

        if [ $days -gt 30 ]; then
            rm -rf $backup_dir/$f
        fi

    done

done

Modify the dirs and retention period ("30 days") to suit your needs.

Solution 20 - Bash

For MacOS sierra (maybe from Mac OS X yosemate),

To get epoch time(Seconds from 1970) from a file, and save it to a var:

old_dt=`date -j -r YOUR_FILE "+%s"`

To get epoch time of current time

new_dt=`date -j "+%s"`

To calculate difference of above two epoch time

(( diff = new_dt - old_dt ))

To check if diff is more than 23 days

(( new_dt - old_dt > (23*86400) )) && echo Is more than 23 days

Solution 21 - Bash

echo $(date +%d/%h/%y) date_today
echo " The other date is 1970/01/01"
TODAY_DATE="1970-01-01"
BEFORE_DATE=$(date +%d%h%y)
echo "THE DIFFERNS IS " $(( ($(date -d $BEFORE_DATE +%s) - $(date -d $TODAY_DATE +%s)) )) SECOUND

use it to get your date today and your sec since the date you want. if you want it with days just divide it with 86400

echo $(date +%d/%h/%y) date_today
echo " The other date is 1970/01/01"
TODAY_DATE="1970-01-01"
BEFORE_DATE=$(date +%d%h%y)
echo "THE DIFFERNS IS " $(( ($(date -d $BEFORE_DATE +%s) - $(date -d $TODAY_DATE +%s))/ 86400)) SECOUND

Solution 22 - Bash

Instead of hard coding the expiration to a set amount of days when generating self-signed certificates, I wanted to have them expire just before the Y2k38 problem kicks in (on 19 January 2028). But, OpenSSL only allow the expiration to be set using -days, which is the number of days from the current date. I ended up using this:

openssl req -newkey rsa -new -x509 \
  -days $((( $((2**31)) - $(date +%s))/86400-1)) \
  -nodes -out new.crt -keyout new.key -subj '/CN=SAML_SP/'

Solution 23 - Bash

for zsh (Only works if dates in the same year)

echo $(($(date -d "today" +%j) - $(date -d "08 Jan 2021" +%j) )) days

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTreeView Question on Stackoverflow
Solution 1 - BashtechjackerView Answer on Stackoverflow
Solution 2 - Bashuser332325View Answer on Stackoverflow
Solution 3 - Bashevan_bView Answer on Stackoverflow
Solution 4 - BashFred LaurentView Answer on Stackoverflow
Solution 5 - BashjschnasseView Answer on Stackoverflow
Solution 6 - Bashnickl-View Answer on Stackoverflow
Solution 7 - BashRuchiView Answer on Stackoverflow
Solution 8 - Bashglenn jackmanView Answer on Stackoverflow
Solution 9 - BashOlivier B.View Answer on Stackoverflow
Solution 10 - BashbruceView Answer on Stackoverflow
Solution 11 - BashGotxiView Answer on Stackoverflow
Solution 12 - BashGreyCatView Answer on Stackoverflow
Solution 13 - BashUlfView Answer on Stackoverflow
Solution 14 - BashChris F.A. JohnsonView Answer on Stackoverflow
Solution 15 - BashmattymikView Answer on Stackoverflow
Solution 16 - BashZomboView Answer on Stackoverflow
Solution 17 - BashAnatolii ShubaView Answer on Stackoverflow
Solution 18 - BashDennis WilliamsonView Answer on Stackoverflow
Solution 19 - BashAlex CherkasView Answer on Stackoverflow
Solution 20 - Bashosexp2003View Answer on Stackoverflow
Solution 21 - BashZaed KazemView Answer on Stackoverflow
Solution 22 - BashDick VisserView Answer on Stackoverflow
Solution 23 - BashzzapperView Answer on Stackoverflow