2

Bear with me I am not strong with bash. I have a date/time as in YYYYMMDDHHMMSS format such as 20031005000000in string. I like to add one year to it. I've read man date but it was a bit hard to interpret what it says although I think I do have basic understanding of -d and -s option looking at many examples from WWW.

These are a few of many I read:

So at the moment, I know how to add one year to current date.

myDatePlusOneYr=$(date -d "+365 days" '+%Y%m%d%H%M%S')

And I can add one year to date without having time segment (HHMMSS).

myDate="20031005"
date -d "$myDate +365 day"
Mon Oct  4 00:00:00 GMT 2004

However I have not found a way to add one year to a date/time format. When I tried with second option having with time segment, I get following error msg.

date: invalid date `20031005000000 +365 day'

I noticed backtick at the beginning of date/time and single quote at the end. I am not sure how to interpret the error msg. I'd appreciate your advice.

Update: I found an answer for invalid date: https://stackoverflow.com/questions/4197606/how-to-convert-yyyymmddhhmmss-to-a-date-readable-by-date

3 Answers 3

4

I might be over-simplifying it, but:

% expr 20091005000000 + 10000000000
20101005000000
3
  • I appreciate your reply. I didn't know about expr until now. I think I can parse out year and add 1 to it.
    – DaeYoung
    Aug 27, 2020 at 18:28
  • or only with bash: d=20031005000000; declare -i x; x=$d+10000000000; echo $x
    – Cyrus
    Aug 27, 2020 at 18:46
  • The user below is correct that this approach doesn't work if the day is February 29th.
    – Chris W.
    Sep 4, 2020 at 17:22
4

You could just treat the string as a number:

#/bin/sh
date='20000229000000'
echo "$((date + 10000000000))"

that prints 20041005000000. Of course it doesn't work correctly if your date happens to Feb 29th on a leap year, but that should be the only exception. You can deal with that by splitting the string to pieces and taking the leap day as a special case:

#!/bin/bash
date='20000229000000'
# assume it's correctly formatted
y=${date:0:4}
m=${date:4:2}
d=${date:6:2}
t=${date:8}

if [[ $m == 02 && $d == 29 ]]; then
        m=03
        d=01
fi

echo "$((y+1))$m$d$t"

In some shells, including Bash, the arithmetic treats numbers starting with zeroes as octal, but we're only doing arithmetic on the year, and it shouldn't have leading zeroes.

1

I don't like this answer because it invokes 3 shell commands to do it, but it works. Start with myDate="20031005010203"

I assume you want 1 year added to that. The ugly way is to take it apart, treat the first 8 characters as a YYYYMMDD, add a year, and use the date command to format the result. It stitches the time back onto the time value. Notice that for my test data I use 20040229 (a valid leap year).

myDate="20040229010203"
datebit=$(echo $myDate | cut -c 1-8)
timebit=$(echo $myDate | cut -c 9-)
newdate=$(date -d "$datebit +1 year" +"%Y%m%d${timebit}")
echo "${newdate}"

The input was 20040229010203 and the output should be 20050301010203.

So "one year from 01:02:03 on Feb 29 2004" is "01:02:03 on Mar 01 2005"

I tested this on ubuntu with the standard date command there.

1
  • Dammit. If I had just looked at @ikkachu's answer, I would see how to avoid most of these shell calls. But use date -d to do your math. Don't do special casing on february 29.
    – Paco Hope
    Aug 27, 2020 at 19:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.