Solved

# Difference between dates

Posted on 2005-04-25
Medium Priority
569 Views
Me again....

Ok, I thought I had this question answered, but appreantly not. Here's what I'm trying to do:

Read a command line argument as a:
3-letter month string (eg. Jan)
day number (eg. 5)
4-digit year (eg. 1940).

Next I need to calculate the number of days from Jan 1, 1940 to that date.
**No dates before Jan 1, 1940 or after the current year
**Needs to take leap years into account
**Cannot use the date command
Example:
\$ ./cal_dif Jan 5 1940
4 days

Here's what I have so far:
#! /bin/sh
# ./cal_dif MMM DD YYYY

# Checks for correct arguements
[ \$# -ne 2 -a \$# -ne 3 ] && (echo "usage: \$0 mon dd [yyyy]" && exit 1 )

# Converts month to lower case
tr '[A-Z]' '[a-z]' < \$1

# Converts alpha month to interger
case \$1 in

jan) mon=1;;
feb) mon=2;;
mar) mon=3;;
apr) mon=4;;
may) mon=5;;
jun) mon=6;;
jul) mon=7;;
aug) mon=8;;
sep) mon=9;;
oct) mon=10;;
nov) mon=11;;
dec) mon=12;;
*) echo "usage: \$0 mon dd [yyyy]" && exit 1;;
esac

year=\$3

# Add the number of days appropriate to the month.
case \$mon in
1|3|5|7|8|10|12) day=31;;
4|6|9|11) day=30;;
2)
if [ `expr \$year % 4` -eq 0 ]; then
if [ `expr \$year % 400` -eq 0 ]; then
day=29
elif [ `expr \$year % 100` -eq 0 ]; then
day=28
else
day=29
fi
else
day=28
fi
;;
esac

# If days entered > day then \$2 invalid
if [ \$2 > day ]; then
echo "Days in month incorrect" && exit 1
;;
fi

Now that I have an intereger month, day and year I think I need to convert it to epoch then check that the epoch value is not less than Jan 1, 1940. How do I do this though?
0
Question by:nrstahl
• 4
• 3
• 2

LVL 38

Expert Comment

ID: 13864494
The easy way to do it is to use Julian conversion (conver the date into number of days since
January 1, 4713 BC), the simply use "new - old" to find out the difference.

To work out the Julian date, please have a look at the scripts in the following pages to

http:Q_20068668.html
http:Q_20486669.html
http://www.unixreview.com/documents/s=9020/ur0401d/
0

LVL 38

Expert Comment

ID: 13864523
0

LVL 4

Expert Comment

ID: 13867002
Too bad you can't use GNU date.

Anyhow - cal can easily give you the days of the month (that is - if you can use it).
# Get the number of days appropriate to the month.
: \$(cal \$mon \$year )
day=\$_
# If days entered > day then \$2 invalid
if [ \$2 > \$day ]; then
echo "Days in month incorrect" && exit 1
fi

But are you sure a shell script is really the way to go?
0

LVL 4

Expert Comment

ID: 13867156
Here's a nice little PD shell script for julian2date and date2julian:
http://home.comcast.net/~j.p.h/cus-faq.html#APP_A
0

LVL 4

Accepted Solution

bytta earned 2000 total points
ID: 13901438
Still no luck?
I was bored, so here's a little script not using any extra program, except echo and tr...

Changed your stuff from /bin/sh to bin/bash because it's my home ground. let me know if that's a problem...
Because it doesn't use any other programs, it can't check if the date entered is after today, and "cal_dif mon dd" defaults to the year 2005 (both easily solved using GNU date or even cal ;o)
Gives error on:
cal_dif Dec              -> usage: \$0 mon dd [yyyy]
cal_dif Dec 31 1939 -> Year can't be before 1940
cal_dif DeX 31 1941 -> usage: \$0 mon dd [yyyy]
cal_dif Dec 32 1941 -> Days in month incorrect
cal_dif Dec -1 1941 -> Days in month incorrect

#! /bin/bash
# ./cal_dif MMM DD YYYY

# Julian Day Number from calendar date
# Public domain - originally written in /bin/sh by Tapani Tarvainen
date2julian() #  day month year
{
day=\$1;  month=\$2;  year=\$3
tmpmonth=\$[ 12*year+month-3 ]
tmpyear=\$[ tmpmonth/12 ]
# echo \$[ (...) ] should be in a single line - EE might split it into 2 lines
echo \$[ (734*tmpmonth+15)/24-2*tmpyear+tmpyear/4-tmpyear/100+tmpyear/400+day+1721119 ]
}

# Checks for correct arguements
[ \$# -ne 2 -a \$# -ne 3 ] && echo "usage: \$0 mon dd [yyyy]" && exit 1

year=\${3:-"2005"}  # Hardcoding stuff is BAD, but you don't want to use date
if [ \$year -lt 1940 ]; then
echo "Year can't be before 1940" && exit 1
fi

# Converts month to lower case
month=\$(echo \$1|tr '[A-Z]' '[a-z]') # yours was very wrong...

# Converts alpha month to interger
case \$month in
jan) mon=1;;
feb) mon=2;;
mar) mon=3;;
apr) mon=4;;
may) mon=5;;
jun) mon=6;;
jul) mon=7;;
aug) mon=8;;
sep) mon=9;;
oct) mon=10;;
nov) mon=11;;
dec) mon=12;;
*) echo "usage: \$0 mon dd [yyyy]" && exit 1;;
esac

# Add the number of days appropriate to the month.
case \$mon in
1|3|5|7|8|10|12) day=31;;
4|6|9|11) day=30;;
2)
if [ `expr \$year % 4` -eq 0 ]; then
if [ `expr \$year % 400` -eq 0 ]; then
day=29
elif [ `expr \$year % 100` -eq 0 ]; then
day=28  # overkill if all dates are 1901-2099
else
day=29
fi
else
day=28
fi
;;
esac

# If days entered > day then \$2 invalid
if [ \$2 -gt \$day ]; then
echo "Days in month incorrect" && exit 1
elif [ \$2 -le 0 ]; then  # minor paranioa... ;) Negative numbers and zero not allowed
echo "Days in month incorrect" && exit 1
fi

refday=\$( date2julian 1 1 1940 )      # 1st Jan 1940
myday=\$( date2julian \$2 \$mon \$year )

echo \$[ myday-refday ] days

0

Author Comment

ID: 13902815
bytta,

Thank you for all your help on this project!! It was all very helpful and I was finally able to put together a script that met all the requirements:

#! /bin/ksh
# Homework Lab 4 Question 7
# ./hw7 MMM DD YYYY

[ \$# -ne 2 -a \$# -ne 3 ] && (echo "usage: \$0 MON dd [yyyy]" && exit 1 )

clear

# Converts the alpha month to an integer
for arg in \$1            Ăź for loop doesn't loop â€“ it only executes ONCE, so it is unnecessary code
do
case \$1 in
JAN) mon=1
;;
FEB) mon=2
;;
MAR) mon=3
;;
APR) mon=4
;;
MAY) mon=5
;;
JUN) mon=6
;;
JUL) mon=7
;;
AUG) mon=8
;;
SEP) mon=9
;;
OCT) mon=10
;;
NOV) mon=11
;;
DEC) mon=12
;;
*) echo "Month \$1 not recognized" && exit 1
;;
esac
done

# New date conversion
let x1=0+(1461*(\$3+4800+(mon-14)/12))/4+(367*(mon-2-12*((mon-14)/12)))/12
let w1=0+(3*((mon+4900+(mon-14)/12)/100))/4
let x1=x1-w1+\$2-32075

if (( \$x1 > 2453752 ))
then
echo â€śThe date must be before DEC 31 2005â€ť
exit 1
fi

# Shows mathematical conversion for: Jan 1 1940
# let x2=0+(1461*(1940+4800+(1-14)/12))/4+(367*(1-2-12*((1 -14)/12)))/12
# let w2=0+(3*((1940+4900+(1-14)/12)/100))/4
# let x2=x2-w2+1-32075

let x2=2429645
let z=x1-x2

if (( \$z <= 0 ))
then
echo â€śThe date must be greater than JAN 1 1940â€ť
exit 1
else
echo \$z â€śdaysâ€ť
fi

Thanks again for all your hard work!
0

LVL 4

Expert Comment

ID: 13903958
This is a big NONO!
# Homework Lab 4 Question 7

Do we are NOT here to do your homework!
0

Author Comment

ID: 13905240
It was a homework assignment, but I still had to LEARN how to do the assignment. The problem with going to school online is that there is little support for figuring out the solutions. You get a few books, a few postings in the assignments page and other than that, youâ€™re on your own. It's not the same as taking a class in a traditional setting where you can get real feedback and ask real questions in a live setting. I actually posted my script to the class asking for assistance and got told that it was not allowed, that we just had to use logic and figure it out.

So if we don't learn how to solve the problem and can't ask questions or get advice from someone, how can we ever know what we're doing? I could very easily have a problem with the same type of criteria in the working world and if I never learned out to solve this assignment, or learned about the different types of calendars, commands, syntax usage, if-then-else and while statements, how would I ever know how to solve it at work? It would be different if I just posted the question and did nothing to learn it on my own, but I didn't do that. I spent hours taking everyone's suggestions, ideas and advice, used my own logic and put it all together.
0

Author Comment

ID: 13921109
If you look back through my postings you will see that I did post my work and researched all the information that was provided. I never expected anyone to "DO" my homework for me, but I feel like that's what I'm being accused of. And if I had thought I was doing anything wrong I never would have posted that it was a homework assignment in the first place.

Sorry this has turned into such a big issue. I spent literally hours working on this and feel like I put a significant amount of time and effort into the project. I also understand that you need to have policies to prevent people from posting assignments and just having someone else do ALL the work for them, but that was not what I was after here at all. I really want to learn the material, the scripting, why some things work and other don't, and just absorb the information in general.
0

## Featured Post

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When you do backups in the Solaris Operating System, the file system must be inactive. Otherwise, the output may be inconsistent. A file system is inactive when it's unmounted or it's write-locked by the operating system. Although the fssnap utilityâ€¦
I promised to write further about my project, and here I am.  First, I needed to setup the Primary Server.  You can read how in this article: Setup FreeBSD Server with full HDD encryption (http://www.experts-exchange.com/OS/Unix/BSD/FreeBSD/A_3660-Sâ€¦
Learn several ways to interact with files and get file information from the bash shell. ls lists the contents of a directory: Using the -a flag displays hidden files: Using the -l flag formats the output in a long list: The file command gives us morâ€¦
Learn how to get help with Linux/Unix bash shell commands. Use help to read help documents for built in bash shell commands.: Use man to interface with the online reference manuals for shell commands.: Use man to search man pages for unknown commandâ€¦
###### Suggested Courses
Course of the Month17 days, 8 hours left to enroll