199

I have Linux ( RH 5.3) machine

I need to add/calculate 10 days plus date so then I will get new date (expiration date))

for example

 # date 
 Sun Sep 11 07:59:16 IST 2012

So I need to get

     NEW_expration_DATE = Sun Sep 21 07:59:16 IST 2012

Please advice how to calculate the new expiration date ( with bash , ksh , or manipulate date command ?)

1

5 Answers 5

266

You can just use the -d switch and provide a date to be calculated

date
Sun Sep 23 08:19:56 BST 2012
NEW_expration_DATE=$(date -d "+10 days")
echo $NEW_expration_DATE
Wed Oct 3 08:12:33 BST 2012 
  -d, --date=STRING
          display time described by STRING, not ‘now’

This is quite a powerful tool as you can do things like

date -d "Sun Sep 11 07:59:16 IST 2012+10 days"
Fri Sep 21 03:29:16 BST 2012

or

TZ=IST date -d "Sun Sep 11 07:59:16 IST 2012+10 days"
Fri Sep 21 07:59:16 IST 2012

or

prog_end_date=`date '+%C%y%m%d' -d "$end_date+10 days"`

So if $end_date = 20131001 then $prog_end_date = 20131011.

12
  • 5
    Thank you!! Your examples should be in the GNU date info page! Nov 15, 2017 at 13:30
  • 14
    On OS X when using the build-in date you will recieve an error. Use brew install coreutils to install GNU's date function, gdate. Jun 20, 2018 at 10:47
  • 3
    doesn't work: $ docker run -it bash bash bash-5.0# date -d "+10 days" date: invalid date '+10 days' bash-5.0# Feb 13, 2019 at 2:49
  • 2
    @ChristianBongiorno It does work, it has worked for years if not decades. The problem is almost certainly something to do with your environment.
    – user591
    Feb 13, 2019 at 7:37
  • 1
56

You can use "+x days" as format string:

$ date -d "+10 days"
1
  • Note: you should be careful with the DST depending on the time zone. To see what I mean and the way to handle it correctly, see this answer
    – Adrian B.
    Apr 6 at 21:52
39

In Mac OS (and maybe other BSD distros):

$ date -v -1d

In order to get 1 day back date using date command:

$ date -v -1d

It will give (current date -1) means 1 day before .

$ date -v +1d

This will give (current date +1) means 1 day after.

Similarly below written code can be used in place of "d" to find out year,month etc.

y-Year
m-Month 
w-Week 
d-Day 
H-Hour 
M-Minute  
S-Second
6
  • 9
    This works for me on my mac, but not on our Gentoo servers. May 6, 2015 at 17:19
  • 1
    Much better than the accepted answer, this allows for arbitrary date formats too in a single line.
    – pferrel
    Nov 9, 2015 at 16:48
  • 9
    this does not work on Ubuntu 15.10 or RedHat 6.6. I assume it does not work on RH5.3 either. Reason: '-v' and '-1d' are no valid switches for 'date'
    – syss
    Mar 2, 2016 at 9:22
  • 2
    This does appear to be a Unix/BSD syntax for date, which GNU's date (gdate on many BSDs) doesn't support. GNU's date uses the syntax in the accepted answer. Always remember: GNU's Not Unix!
    – Bacon Bits
    May 18, 2016 at 18:08
  • 1
    @BaconBits - but if you're rms you can claim that because a lot of GNU util code has been ported to Linux that therefore "Linux is GNU". Except, of course, for the fact that GNU Hurd (FSF's Once-And-Future-OS) is just barely a thing. I suppose what pisses rms off is that while he spent his time pontificating, Linus spent his time writing code - which turns out to be proof positive that you're much more likely to create working software if you write code than if you pontificate. :-) Jul 6, 2016 at 18:41
5

I gave up on the GNU date command due to timezone confusion, and went to python.

python -c "import datetime, dateutil.parser; print((dateutil.parser.parse(\"$myDate\") + datetime.timedelta(days=10)).isoformat())"

Maybe it's overkill, but it's straightforward to read, understand and modify as needed.

dateutil.parser.parse is not part of the python standard library, so you have to pip install dateutil; alternatively you can use datetime.datetime.fromisoformat, but you need to be more careful about formats.

4

As previous answers, you can use the -d switch like :

date -d "$myDate + 10 days"

But you need to be careful with the time zone!

An example of something that can go wrong : If you want to get an interval for a day like [start of day, end of day] for the "8 march 2020" with the timezone at Montreal, where the DST start at 2:00:00 am, you could do

startDate=$(date --iso-8601=n -d "8 march 2020 00:00:00.000000001")
endDate=$(date --iso-8601=n -d "$startDate + 1 day")

but instead of

startDate → "2020-03-08T00:00:00,000000001-0500"
endDate   → "2020-03-09T00:00:00,000000001-0400"

you'll get 1 hour of the 9 march 2020

startDate → "2020-03-08T00:00:00,000000001-0500"
endDate   → "2020-03-09T01:00:00,000000001-0400"

To fix that, you could do the following :

# Returns the difference between two dates' local time offsets. E.g. : "3600" or "- 1800"
getLocalTimeOffsetDiffInSeconds() {

    # Get the offset in the following format: -0530 for -05h30min
    localOffset1=$(date -d "$1" +%z)
    localOffset2=$(date -d "$2" +%z)
    
    # Get the offset in seconds
    localOffsetInSec1=$(echo $localOffset1 | sed -E 's/^([+-])(..)(..)/scale=2;0\1(\2 * 3600 + \3 * 60)/' | bc)
    localOffsetInSec2=$(echo $localOffset2 | sed -E 's/^([+-])(..)(..)/scale=2;0\1(\2 * 3600 + \3 * 60)/' | bc)
    
    # Compute diff
    diffOffsetInSec=$(echo "$localOffsetInSec2 - $localOffsetInSec1" | bc)
    
    # Add a space between the sign and the value, so it can be used by the command "date".
    echo "$diffOffsetInSec" | sed -E 's/([+-])(.*)/\1 \2/'
}

  startDate=$(date --iso-8601=n -d "8 march 2020 00:00:00.000000001")
  endDate=$(date --iso-8601=n -d "$startDate + 1 day")
  
  # Fixes endDate if the DST changed between the two dates.
  
  dstDiff=$(getLocalTimeOffsetDiffInSeconds "$startDate" "$endDate")
  
  # dateFix will be a string to remove the dstDiff from the date in a format
  # that can be understood by the command "date". E.g. "3600 seconds" or "- 3600 seconds".
  dateFix=$(echo "$(echo "- $dstDiff" | bc | sed -E 's/([+-])(.*)/\1 \2/')")
  endDate=$(date --iso-8601=n -d "$endDate $dateFix seconds")

You must log in to answer this question.