1833714 Members
2180 Online
110063 Solutions
New Discussion

Date Calculations

 
SOLVED
Go to solution
Doug Dell
Advisor

Date Calculations

Hello everyone,

I am working on a script which generates a report. I need to know the dates 30, 60, 90, and 120 days from a given date
unless any of those dates fall on a weekend or a holiday. In that case, I would like to skip to the next regular working day.

I have been trying to use the date command but that does not work very well so far. The ideal command would be something
like "future 12/20/2001 30" and would return 01/21/2002. Thirty days from 12/20/2001 is actually 01/19/2002 but that is on a Saturday so I want it to skip to the following Monday.

Can anybody help?

Thanks, Doug
13 REPLIES 13
Craig Rants
Honored Contributor

Re: Date Calculations

Here are some variables based on a script I used to calculate dates based on the epoch.
If you can figure out your current epoch date these should lead you down the right road. You can use the adb command to convert epoch to readable time.

NINETY='7776000'
SIXTY='5184000'
THIRTY='2592000'
FORMULA=`echo "0d$NUMBER=Y" | adb`
NDAYS=`expr $CURRENT - $NINETY`
SDAYS=`expr $CURRENT - $SIXTY`
TDAYS=`expr $CURRENT - $THIRTY`

Hope this is a step in the right direction...
"In theory, there is no difference between theory and practice. But, in practice, there is. " Jan L.A. van de Snepscheut
linuxfan
Honored Contributor

Re: Date Calculations

Hi doug,

To do any kind of date manipulations, the easiest way i have found is to use Clay's caljd.sh script.

You can download the latest from
http://forums.itrc.hp.com/cm/QuestionAnswer/1,,0x6901c7af36b7d5118ff10090279cd0f9,00.html

this script works and should get you started (uses the caljd.sh script)

/Begin/
#!/usr/bin/ksh

# USAGE: future.sh 12 20 2001 30
# future.sh mm dd yyyy increment_in_days
# future.sh 12 20 2001 30
# future.sh 12 20 2001 60

PATH=/usr/bin:/usr/local/bin

DATE1=$(caljd.sh $1 $2 $3)

DAYS=$4

WK_DAY=$(caljd.sh -w $(caljd.sh -n $DAYS $DATE1))
echo "wk day is $WK_DAY"

if [ $WK_DAY -ge 1 -a $WK_DAY -le 5 ]
then
FUTURE_DATE=$(caljd.sh -n $DAYS $DATE1)
echo $FUTURE_DATE

elif [ $WK_DAY -eq 6 ]
then
FUTURE_DATE=$(caljd.sh -n $DAYS $DATE1+2)
echo $FUTURE_DATE

elif [ $WK_DAY -eq 0 ]
then
FUTURE_DATE=$(caljd.sh -n $DAYS $DATE1+1)
echo $FUTURE_DATE
fi

/End/

If you want to give the date in mm/dd/yyyy format just change the above script to manipulate the input.

I am attaching the caljd.sh script for your reference

-HTH
Ramesh
They think they know but don't. At least I know I don't know - Socrates
A. Clay Stephenson
Acclaimed Contributor
Solution

Re: Date Calculations

Hi Doug:

Since Ramesh mentioned the caljd.sh script, I suppose I should tell you what it does. It takes a calendar date and converts into a fairly large integer called a Julian Date or Julian Day. This is the method used by astromers to avoid messy calculations that might span hundreds of years. The JD is actually the number of days since ~4713BCE. The neat thing about this is that they count off sequentially so things like (JD + offset) mod 7 = day of week. The other neat thing is that leap years, century years, are taken into account.

Questions very similar to yours have appeared fairly recently and the one that piqued my interest was needing to calculate yesterday's
date unless it were on the weekend in which case return the previous Friday. This is essentially your problem in reverse. I had been working on an improved version that would do this without any outside calculations. I think I have it:


#!/usr/bin/sh

MDY="12 21 2001"

NEXT=30
N30=$(caljd.sh $(caljd.sh -n ${NEXT} -x 6 -x 0 ${MDY}))
echo "${MDY} + ${NEXT} days skipping over weekends is ${N30}."

Note the nested caljd.sh calls. The inner one takes MDY (12 21 2001) and adds 30 days to it (-n ${NEXT}. If the final date falls on Sat. (-x 6) or Sun. (-x 0) skip to the next unexcluded weekday and output the Julian Day. The Julian Day is then converted by the outer caljd.sh call back into a calendar date.

The format is MM DD YYYY rather than MM/DD/YYYY but everything else is about what you wanted. It doesn't do the holidays but back in the dawn of UNIX I seem to remember a holidays program and a holidays file. Maybe someone will remember what that was or I can find. If so, I may add that as to the script at some point. The important point is that all of your request now becomes a one-liner in the shell (except for holidays).

If you invoke caljd.sh -u, it will print a usage message to stderr. I added some options to allow yyyy mm dd output and dd mm yyyy output as well as outputs without spaces because there were some requests for filename generation.

There are quite a few features added to this version rather than the earlier version which Ramesh posted.

Enjoy, Clay
If it ain't broke, I can fix that.
A. Clay Stephenson
Acclaimed Contributor

Re: Date Calculations

Hi Again,

I thought I would also attach the script I use to test caljd.sh (caljdtest.sh). It runs cajld.sh through all of its arguments plus converts dates to Julian dates and back and compare them. The process must be reversible or there is an error. You can basically use this to see more ways to do your date calculations. There is also a JulianDate module in perl that works well.

Clay
If it ain't broke, I can fix that.
James R. Ferguson
Acclaimed Contributor

Re: Date Calculations

Hi Clay:

I think the file you are looking for is :

/etc/acct/holidays
/usr/sbin/acct/holidays

They're part of the accounting module.

Regards!

...JRF...
A. Clay Stephenson
Acclaimed Contributor

Re: Date Calculations

Thanks Jim, I haven't had a request for accounting in so many moons that I had forgotten. I would give you some points but ...

Doug, give this boy some points.

Regards, Clay
If it ain't broke, I can fix that.
Doug Dell
Advisor

Re: Date Calculations

Thanks everybody! This is great stuff. Clay, I just wish I understood how this works. Honestly, my shell script had grown to over 600 lines and still wasn't working correctly. I just ran your testscript and I was amazed. It even knew that 2000 was a leap year even if it was a century year!!! I guess I'll have to do the holidays but thank you.

Best wishes, Doug
A. Clay Stephenson
Acclaimed Contributor

Re: Date Calculations

Hi Doug:

All of the real work of this this is done in just two awk functions CAL_JDATE which converts a calendar date to a Julian Day and JDATE_CAL which does the reverse. In fact, the bulk of the code is command line argument processing, usage messages, and a shell function to skip over the excluded weekdays.

The CAL_JDATE function is actually a one-liner; get out your calculator and try it but remember to use integer arithmetic and throw away any fractional results. I had a bug in an earlier version because like an idiot I missed one.

The JDATE_CAL is more difficult and I gave up on making it a one-liner. You can take out your calculator and step through it as well.

I suppose the neatest thing about these routines is that they don't use a single IF statement and yet they are able through the magic of integer arithmetic to do the 'Thirty days hath September ...' month calculations. I can't take credit for the Julian Days calculations; they've been around a very long time - back to the days when computers were people. I should also point out that real Julian Dates are floating point values that include the fractional part of each day and begin at noon UTC. That way, the astronomical 'day' doesn't have to worry about events occuring on different days and nobody worries about Daylight Saving Time. All astromical events are published only in UTC and Julian Date values to avoid the confusion of "what time is it?" and "where am i?".

By the way if you feel up to it, by all means add the holidays Jim cited and post the resulting script. That's how the forums become a valued added product.

Regards, Clay

If it ain't broke, I can fix that.
A. Clay Stephenson
Acclaimed Contributor

Re: Date Calculations

Hi Doug:

I spent a few minutes over the weekend and today adding the holidays exclusion to caljd.sh (Vrsn 2.01). Believe it or not, I actually had a need for it. The guy who does the tape exports from the library for offsite storage had asked me about a year ago if I couldn't make the return tape (which is normally 7 days from now) also skip over holidays. Anyway -x 6 -x 0 -h will skip Saturdays, Sundays, and holidays as defined in the file Jim dug up: /etc/acct/holidays. I had to make a slight modification in case the year's cross, it looks in /etc/acct/holidays_yyyy (e.g.) /etc/acct/holidays_2002 for holidays outside the current year. This will in no way interfere with the normal usage of the file. You simply have to create the holidays file and caljd.sh will now take care of the rest.

Regards, Clay



If it ain't broke, I can fix that.
Doug Dell
Advisor

Re: Date Calculations

Thanks Clay. This appears to be just what I needed! The only holidays file I have is for 1996. Obviously this isn't being used. Can I just change this one?

Doug
James R. Ferguson
Acclaimed Contributor

Re: Date Calculations

Hi Doug:

'/etc/acct/holidays' can/should be edited to your tastes. The '/usr/sbin/acct/holidays' file I pointed out originally is but a link to the file in /etc.

You always have a virgin copy of the holidays file as '/usr/newconfig/etc/acc
t/holidays'.

Regards!

...JRF...
A. Clay Stephenson
Acclaimed Contributor

Re: Date Calculations

Well you could; however, if you are really going to use this as I intended, you should do this:

1) Create a current file e.g. /etc/acct/holidays_2001.
2) mv /etc/acct/holidays /etc/acct/holidays_1996
3) ln -s /etc/acct/holidays_2001 /etc/acct/holidays

When each new year rolls around, create a new symbolic link between the holidays_yyyy file and the holidays file. That way, if you use accounting (which you obviously do not); the accounting system continues to work as before.
I trust you have figured out that you can use caljd.sh to calculate the days offset for the holidays file entries. If you don't have a holidays file for a given year but you have specified the -h option to skip holidays, caljd.sh will not consider this an error. It first tests for the existence of the indicated holidays files. If not found, it just goes on its merry way and assumes that you intentionally did not create a holidays file for a given year.

You might want to add a cron entry that sends you a reminder at the end of the year to update /etc/acct/holidays file. Systems which actually use accounting have that as a normal crontab entry.

Regards, Clay
If it ain't broke, I can fix that.
Doug Dell
Advisor

Re: Date Calculations

Thanks guys! That really helped. I continue to be amazed at the amount of expertise that I find on these forums.

Thanks for everything, Doug.