Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 907307
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 15, 20262026-05-15T16:32:06+00:00 2026-05-15T16:32:06+00:00

I need to do date arithmetic in Unix shell scripts that I use to

  • 0

I need to do date arithmetic in Unix shell scripts that I use to control the execution of third party programs.

I’m using a function to increment a day and another to decrement:

IncrementaDia(){
echo $1 | awk '
BEGIN {
        diasDelMes[1] = 31
        diasDelMes[2] = 28
        diasDelMes[3] = 31
        diasDelMes[4] = 30
        diasDelMes[5] = 31
        diasDelMes[6] = 30
        diasDelMes[7] = 31
        diasDelMes[8] = 31
        diasDelMes[9] = 30
        diasDelMes[10] = 31
        diasDelMes[11] = 30
        diasDelMes[12] = 31
}
{
        anio=substr($1,1,4)
        mes=substr($1,5,2)
        dia=substr($1,7,2)

        if((anio % 4 == 0 && anio % 100 != 0) || anio % 400 == 0)
        {
                diasDelMes[2] = 29;
        }

        if( dia == diasDelMes[int(mes)] ) {
                if( int(mes) == 12 ) {
                        anio = anio + 1
                        mes = 1
                        dia = 1
                } else {
                        mes = mes + 1
                        dia = 1
                }
        } else {
                dia = dia + 1
        }
}
END {
        printf("%04d%02d%02d", anio, mes, dia)
}
'
}

if [ $# -eq 1 ]; then
        tomorrow=$1
else
        today=$(date +"%Y%m%d")
        tomorrow=$(IncrementaDia $hoy)
fi

but now I need to do more complex arithmetic.

What it’s the best and more compatible way to do this?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-15T16:32:07+00:00Added an answer on May 15, 2026 at 4:32 pm

    I have written a bash script for converting dates expressed in English into conventional
    mm/dd/yyyy dates. It is called ComputeDate.

    Here are some examples of its use. For brevity I have placed the output of each invocation
    on the same line as the invocation, separarted by a colon (:). The quotes shown below are not necessary when running ComputeDate:

    $ ComputeDate 'yesterday': 03/19/2010
    $ ComputeDate 'yes': 03/19/2010
    $ ComputeDate 'today': 03/20/2010
    $ ComputeDate 'tod': 03/20/2010
    $ ComputeDate 'now': 03/20/2010
    $ ComputeDate 'tomorrow': 03/21/2010
    $ ComputeDate 'tom': 03/21/2010
    $ ComputeDate '10/29/32': 10/29/2032
    $ ComputeDate 'October 29': 10/1/2029
    $ ComputeDate 'October 29, 2010': 10/29/2010
    $ ComputeDate 'this monday': 'this monday' has passed.  Did you mean 'next monday?'
    $ ComputeDate 'a week after today': 03/27/2010
    $ ComputeDate 'this satu': 03/20/2010
    $ ComputeDate 'next monday': 03/22/2010
    $ ComputeDate 'next thur': 03/25/2010
    $ ComputeDate 'mon in 2 weeks': 03/28/2010
    $ ComputeDate 'the last day of the month': 03/31/2010
    $ ComputeDate 'the last day of feb': 2/28/2010
    $ ComputeDate 'the last day of feb 2000': 2/29/2000
    $ ComputeDate '1 week from yesterday': 03/26/2010
    $ ComputeDate '1 week from today': 03/27/2010
    $ ComputeDate '1 week from tomorrow': 03/28/2010
    $ ComputeDate '2 weeks from yesterday': 4/2/2010
    $ ComputeDate '2 weeks from today': 4/3/2010
    $ ComputeDate '2 weeks from tomorrow': 4/4/2010
    $ ComputeDate '1 week after the last day of march': 4/7/2010
    $ ComputeDate '1 week after next Thursday': 4/1/2010
    $ ComputeDate '2 weeks after the last day of march': 4/14/2010
    $ ComputeDate '2 weeks after 1 day after the last day of march': 4/15/2010
    $ ComputeDate '1 day after the last day of march': 4/1/2010
    $ ComputeDate '1 day after 1 day after 1 day after 1 day after today': 03/24/2010
    

    I have included this script as an answer to this problem because it illustrates how
    to do date arithmetic via a set of bash functions and these functions may prove useful
    for others. It handles leap years and leap centuries correctly:

    #! /bin/bash
    #  ConvertDate -- convert a human-readable date to a MM/DD/YY date
    #
    #  Date ::= Month/Day/Year
    #        |  Month/Day
    #        |  DayOfWeek
    #        |  [this|next] DayOfWeek
    #        |  DayofWeek [of|in] [Number|next] weeks[s]
    #        |  Number [day|week][s] from Date
    #        |  the last day of the month
    #        |  the last day of Month
    #
    #  Month ::= January | February | March | April | May | ...  | December
    #  January  ::= jan | january | 1
    #  February  ::= feb | january | 2
    #  ...
    #  December ::=  dec | december | 12
    #  Day   ::= 1 | 2 | ... | 31
    #  DayOfWeek ::= today | Sunday | Monday | Tuesday | ...  | Saturday
    #  Sunday    ::= sun*
    #  ...
    #  Saturday  ::= sat*
    #
    #  Number ::= Day | a
    #
    #  Author: Larry Morell
    
    if [ $# = 0 ]; then
       printdirections $0
       exit
    fi
    
    
    
    # Request the value of a variable
    GetVar () {
       Var=$1
       echo -n "$Var= [${!Var}]: "
       local X
       read X
       if [ ! -z $X ]; then
          eval $Var="$X"
       fi
    }
    
    IsLeapYear () {
       local Year=$1
       if [ $[20$Year % 4]  -eq  0 ]; then
          echo yes
       else
          echo no
       fi
    }
    
    # AddToDate -- compute another date within the same year
    
    DayNames=(mon tue wed thu fri sat sun )  # To correspond with 'date' output
    
    Day2Int () {
       ErrorFlag=
       case $1 in
          -e )
             ErrorFlag=-e; shift
             ;;
       esac
       local dow=$1
       n=0
       while  [ $n -lt 7 -a $dow != "${DayNames[n]}" ]; do
          let n++
       done
       if [ -z "$ErrorFlag" -a $n -eq 7 ]; then
          echo Cannot convert $dow to a numeric day of wee
          exit
       fi
       echo $[n+1]
    
    }
    
    Months=(31 28 31 30 31 30 31 31 30 31 30 31)
    MonthNames=(jan feb mar apr may jun jul aug sep oct nov dec)
    # Returns the month (1-12) from a date, or a month name
    Month2Int () {
       ErrorFlag=
       case $1 in
          -e )
             ErrorFlag=-e; shift
             ;;
       esac
       M=$1
       Month=${M%%/*}  # Remove /...
       case $Month in
          [a-z]* )
             Month=${Month:0:3}
             M=0
             while [ $M -lt 12 -a ${MonthNames[M]} != $Month ]; do
                let M++
             done
             let M++
       esac
       if [  -z "$ErrorFlag" -a $M -gt 12 ]; then
          echo "'$Month' Is not a valid month."
          exit
       fi
       echo $M
    }
    
    # Retrieve month,day,year from a legal date
    GetMonth() {
       echo ${1%%/*}
    }
    
    GetDay() {
       echo $1 | col / 2
    }
    
    GetYear() {
       echo ${1##*/}
    }
    
    
    AddToDate() {
    
       local Date=$1
       local days=$2
       local Month=`GetMonth $Date`
       local Day=`echo $Date | col / 2`   # Day of Date
       local Year=`echo $Date | col / 3`  # Year of Date
       local LeapYear=`IsLeapYear $Year`
    
       if [ $LeapYear = "yes" ]; then
          let Months[1]++
       fi
       Day=$[Day+days]
       while [ $Day -gt ${Months[$Month-1]} ]; do
           Day=$[Day -  ${Months[$Month-1]}]
           let Month++
       done
       echo "$Month/$Day/$Year"
    }
    
    # Convert a date to normal form
    NormalizeDate () {
       Date=`echo "$*" | sed 'sX  *X/Xg'`
       local Day=`date +%d`
       local Month=`date +%m`
       local Year=`date +%Y`
       #echo Normalizing Date=$Date > /dev/tty
       case $Date in
          */*/* )
             Month=`echo $Date | col / 1 `
             Month=`Month2Int $Month`
             Day=`echo $Date | col / 2`
             Year=`echo $Date | col / 3`
             ;;
          */* )
             Month=`echo $Date | col / 1 `
             Month=`Month2Int $Month`
             Day=1
             Year=`echo $Date | col / 2 `
             ;;
          [a-z]* ) # Better be a month or day of week
             Exp=${Date:0:3}
             case $Exp in
                jan|feb|mar|apr|may|june|jul|aug|sep|oct|nov|dec )
                   Month=$Exp
                   Month=`Month2Int $Month`
                   Day=1
                   #Year stays the same
                   ;;
                mon|tue|wed|thu|fri|sat|sun )
                   # Compute the next such day
                   local DayOfWeek=`date +%u`
                   D=`Day2Int $Exp`
                   if [ $DayOfWeek -le $D ]; then
                      Date=`AddToDate $Month/$Day/$Year $[D-DayOfWeek]`
                   else
                      Date=`AddToDate $Month/$Day/$Year $[7+D-DayOfWeek]`
                   fi
    
                   # Reset Month/Day/Year
                   Month=`echo $Date | col / 1 `
                   Day=`echo $Date | col / 2`
                   Year=`echo $Date | col / 3`
                   ;;
                * ) echo "$Exp is not a valid month or day"
                    exit
                   ;;
                esac
             ;;
          * ) echo "$Date is not a valid date"
              exit
             ;;
       esac
       case $Day in
          [0-9]* );;  # Day must be numeric
          * ) echo "$Date is not a valid date"
              exit
             ;;
       esac
          [0-9][0-9][0-9][0-9] );;  # Year must be 4 digits
          [0-9][0-9] )
              Year=20$Year
          ;;
       esac
       Date=$Month/$Day/$Year
       echo $Date
    }
    # NormalizeDate jan
    # NormalizeDate january
    # NormalizeDate jan 2009
    # NormalizeDate jan 22 1983
    # NormalizeDate 1/22
    # NormalizeDate 1 22
    # NormalizeDate sat
    # NormalizeDate sun
    # NormalizeDate mon
    
    ComputeExtension () {
    
       local Date=$1; shift
       local Month=`GetMonth $Date`
       local Day=`echo $Date | col / 2`
       local Year=`echo $Date | col / 3`
       local ExtensionExp="$*"
       case $ExtensionExp in
          *w*d* )  # like 5 weeks 3 days or even 5w2d
                ExtensionExp=`echo $ExtensionExp | sed 's/[a-z]/ /g'`
                weeks=`echo $ExtensionExp | col  1`
                days=`echo $ExtensionExp | col 2`
                days=$[7*weeks+days]
                Due=`AddToDate $Month/$Day/$Year $days`
          ;;
          *d )    # Like 5 days or 5d
                ExtensionExp=`echo $ExtensionExp | sed 's/[a-z]/ /g'`
                days=$ExtensionExp
                Due=`AddToDate $Month/$Day/$Year $days`
          ;;
          * )
                Due=$ExtensionExp
          ;;
       esac
       echo $Due
    
    }
    
    
    # Pop -- remove the first element from an array and shift left
    Pop () {
       Var=$1
       eval "unset $Var[0]"
       eval "$Var=(\${$Var[*]})"
    }
    
    ComputeDate () {
       local Date=`NormalizeDate $1`; shift
       local Expression=`echo $* | sed 's/^ *a /1 /;s/,/ /' | tr A-Z a-z `
       local Exp=(`echo $Expression `)
       local Token=$Exp  # first one
       local Ans=
       #echo "Computing date for ${Exp[*]}" > /dev/tty
       case $Token in
          */* ) # Regular date
             M=`GetMonth $Token`
             D=`GetDay $Token`
             Y=`GetYear $Token`
             if [ -z "$Y" ]; then
                Y=$Year
             elif [ ${#Y} -eq 2 ]; then
                Y=20$Y
             fi
             Ans="$M/$D/$Y"
             ;;
          yes* )
             Ans=`AddToDate $Date -1`
             ;;
          tod*|now )
             Ans=$Date
             ;;
          tom* )
             Ans=`AddToDate $Date 1`
             ;;
          the )
             case $Expression in
                *day*after* )  #the day after Date
                   Pop Exp;   # Skip the
                   Pop Exp;   # Skip day
                   Pop Exp;   # Skip after
                   #echo Calling ComputeDate $Date ${Exp[*]} > /dev/tty
                   Date=`ComputeDate $Date ${Exp[*]}` #Recursive call
                   #echo "New date is " $Date > /dev/tty
                   Ans=`AddToDate $Date 1`
                   ;;
                *last*day*of*th*month|*end*of*th*month )
                   M=`date +%m`
                   Day=${Months[M-1]}
                   if [ $M -eq 2 -a `IsLeapYear $Year` = yes ]; then
                      let Day++
                   fi
                   Ans=$Month/$Day/$Year
                   ;;
                *last*day*of* )
                   D=${Expression##*of }
                   D=`NormalizeDate $D`
                   M=`GetMonth $D`
                   Y=`GetYear $D`
                   # echo M is $M > /dev/tty
                   Day=${Months[M-1]}
                   if [ $M -eq 2 -a `IsLeapYear $Y` = yes ]; then
                      let Day++
                   fi
                   Ans=$[M]/$Day/$Y
                   ;;
                * )
                   echo "Unknown expression: " $Expression
                   exit
                   ;;
             esac
             ;;
          next* ) # next DayOfWeek
             Pop Exp
             dow=`Day2Int $DayOfWeek` # First 3 chars
             tdow=`Day2Int ${Exp:0:3}` # First 3 chars
             n=$[7-dow+tdow]
             Ans=`AddToDate $Date $n`
             ;;
          this* )
             Pop Exp
             dow=`Day2Int $DayOfWeek`
             tdow=`Day2Int ${Exp:0:3}` # First 3 chars
             if [ $dow -gt $tdow ]; then
                echo "'this $Exp' has passed.  Did you mean 'next $Exp?'"
                exit
             fi
             n=$[tdow-dow]
             Ans=`AddToDate $Date $n`
             ;;
          [a-z]* ) # DayOfWeek ...
    
             M=${Exp:0:3}
             case $M in
                jan|feb|mar|apr|may|june|jul|aug|sep|oct|nov|dec )
                   ND=`NormalizeDate ${Exp[*]}`
                   Ans=$ND
                   ;;
                mon|tue|wed|thu|fri|sat|sun )
                   dow=`Day2Int $DayOfWeek`
                   Ans=`NormalizeDate $Exp`
    
                   if [ ${#Exp[*]} -gt 1 ]; then # Just a DayOfWeek
                      #tdow=`GetDay $Exp` # First 3 chars
                      #if [ $dow -gt $tdow ]; then
                         #echo "'this $Exp' has passed.  Did you mean 'next $Exp'?"
                         #exit
                      #fi
                      #n=$[tdow-dow]
                   #else  # DayOfWeek in a future week
                      Pop Exp  # toss monday
                      Pop Exp  # toss in/off
                      if [ $Exp = next ]; then
                         Exp=2
                      fi
                      n=$[7*(Exp-1)]   # number of weeks
                      n=$[n+7-dow+tdow]
                      Ans=`AddToDate $Date $n`
                   fi
                   ;;
             esac
             ;;
          [0-9]* ) # Number  weeks [from|after] Date
             n=$Exp
             Pop Exp;
             case $Exp in
                w* ) let n=7*n;;
             esac
    
             Pop Exp; Pop Exp
             #echo Calling ComputeDate $Date ${Exp[*]} > /dev/tty
             Date=`ComputeDate $Date ${Exp[*]}` #Recursive call
             #echo "New date is " $Date > /dev/tty
             Ans=`AddToDate $Date $n`
             ;;
       esac
       echo $Ans
    }
    
    Year=`date +%Y`
    Month=`date +%m`
    Day=`date +%d`
    DayOfWeek=`date +%a |tr A-Z a-z`
    
    Date="$Month/$Day/$Year"
    ComputeDate $Date $*
    

    This script makes extensive use of another script I wrote (called col … many apologies to those who use the standard col supplied with Linux). This version of
    col simplifies extracting columns from the stdin. Thus,

    $ echo a b c d e | col 5 3 2
    

    prints

    e c b
    

    Here it the col script:

    #!/bin/sh
    # col -- extract columns from a file
    # Usage:
    #    col [-r] [c] col-1 col-2 ...
    #   where [c] if supplied defines the field separator
    #   where each col-i represents a column interpreted according to  the presence of -r as follows:
    #        -r present : counting starts from the right end of the line
    #        -r absent  : counting starts from the left side of the line
    Separator=" "
    Reverse=false
    case "$1" in
     -r )  Reverse=true; shift;
     ;;
     [0-9]* )
     ;;
     * )Separator="$1"; shift;
     ;;
    esac
    
    case "$1" in
     -r )  Reverse=true; shift;
     ;;
     [0-9]* )
     ;;
     * )Separator="$1"; shift;
     ;;
    esac
    
    #  Replace each col-i with $i
    Cols=""
    for  f in $*
    do
      if [ $Reverse = true ]; then
         Cols="$Cols \$(NF-$f+1),"
      else
         Cols="$Cols \$$f,"
      fi
    
    done
    
    Cols=`echo "$Cols" | sed 's/,$//'`
    #echo "Using column specifications of $Cols"
    awk -F "$Separator"  "{print $Cols}"
    

    It also uses printdirections for printing out directions when the script is invoked improperly:

    #!/bin/sh
    #
    #  printdirections -- print header lines of a shell script
    #
    #  Usage:
    #      printdirections path
    #  where
    #      path is a *full* path to the shell script in question
    #      beginning with '/'
    #
    #  To use printdirections, you must include (as comments at the top
    #  of your shell script) documentation for running the shell script.
    
    if [ $# -eq 0 -o "$*" = "-h" ]; then
       printdirections $0
       exit
    fi
    #  Delete the command invocation at the top of the file, if any
    #  Delete from the place where printdirections occurs to the end of the file
    #  Remove the # comments
    #  There is a bizarre oddity here.
       sed '/#!/d;/.*printdirections/,$d;/ *#/!d;s/# //;s/#//' $1 > /tmp/printdirections.$$
    
    #  Count the number of lines
    numlines=`wc -l /tmp/printdirections.$$ | awk '{print $1}'`
    
    #  Remove the last   line
    numlines=`expr $numlines - 1`
    
    
    head -n $numlines /tmp/printdirections.$$
    rm /tmp/printdirections.$$
    

    To use this place the three scripts in the files ComputeDate, col, and printdirections, respectively. Place the file in directory named by your PATH, typically, ~/bin. Then make them executable with:

    $ chmod a+x ComputeDate col printdirections
    

    Problems? Send me some emaiL: morell AT cs.atu.edu Place ComputeDate in the subject.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'm using MS SQL Server 2005 and I need to store date values partially.
I'm writing a Perl script that does date operations that need to take holidays
I'm using this widget http://www.frequency-decoder.com/2006/10/02/unobtrusive-date-picker-widgit-update So, I use it on how it is supposed
I need the get a date object that specifies the next 2:00am that will
We have a custom list that has a column called Connection Date and need
I need a date format for above date ,my code is like this function
I need to find future date using php.But using php, I am unable to
I need to fetch only first record (because I need last date) of resultset,
i have a date (eg: 2010-04-17 ) i need the date of after 20
HI i have two date pickers. datepicker1, datepicker2. I need datepicker1.date to compare with

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.