#!/bin/ksh

ME=${0##*/}

set -A DAYS 31 28 31 30 31 30 31 31 30 31 30 31

typeset -Z2 MM
typeset -Z2 DD
typeset -Z4 YY
typeset -Z2 YR
typeset -Z3 DayOfYear
typeset -i LeapCount
typeset -i JUL

LEAP=0
JUSTDAY=0
YEARDAY=0
NOCENTURY=0
NOYEAR=0
VERIFY=0
SORTORDER=0

ExitUsage()
{
        print "usage: $ME [-D [-c]|-d|-v] mmdd[[cc]yy]"
        print ""
        print "       generates julian value"
        print "       if yy is omitted, defaults to current year"
        print "       if cc is omitted, year assumed to fall"
        print "           between 1915 and 2014 inclusive"
        print "       use = to specify today's date"
        print ""
        print "   or: $ME [-s ] [-d|-c|-y] -j julianVal"
        print "       $ME [-s ] [-c|-y] -J [[cc]yy]ddd"
        print ""
        print "       generates gregorian date"
        print "       default output format is mmddccyy"
        print ""
        print "OPTIONS:  -d   day of year only"
        print "          -D   year & day of year (ccyyddd)"
        print "          -c   omit century"
        print "          -y   omit year"
        print "          -v   validate only"
        print "          -s   output in sort order (year first)"
        print
        exit 0
}

ExitErr()
{
        (( VERIFY )) || print "${ME}: [00$1] invalid date"
        exit 1
}

CheckLeapYear()
{
    (( (YY%4 == 0 && YY%100 != 0) || YY%400 == 0 )) && LEAP=1
}

##########################################################################
## begin main entry
##

while (( $# > 0 )); do
        case $1 in
                -j )    break ;;
                -J )    break ;;

                -v )    VERIFY=1
                                shift ;;

                -d )    JUSTDAY=1
                                shift ;;

                -D )    YEARDAY=1
                                shift ;;

                -c )    NOCENTURY=1
                                shift ;;

                -y )    NOYEAR=1
                                shift ;;

                -s )    SORTORDER=1
                                shift ;;

                -* )    ExitUsage ;;

                * )             break ;;
        esac
done

(( $# < 1 )) && ExitUsage

if [[ $1 = -J ]]; then
        (( $# < 2 )) && ExitUsage
        shift
        arg=$1
        JUL=arg
        (( JUL < 1 )) && ExitErr 0

        if (( ${#arg} == 3 )); then
                YY=$(date '+%Y')
        else
                (( YY=JUL/1000 ))
                if (( YY < 20 )); then
                        (( YY+=2000 ))
                else
                        (( YY+=1900 ))
                fi
                (( JUL%=1000 ))
        fi

        CheckLeapYear
        (( YR=YY%100 ))

        (( JUL > 365+LEAP )) && ExitErr 6

        (( LEAP )) && (( DAYS[1]=29 ))
        (( MM=1 ))
        while (( JUL > DAYS[MM-1] )); do
                (( JUL-=DAYS[MM-1] ))
                (( MM+=1 ))
        done
        (( DD=JUL ))

        if (( NOYEAR )); then
                print "$MM$DD"

        elif (( SORTORDER )); then
                if (( NOCENTURY )); then
                        print "$YR$MM$DD"
                else
                        print "$YY$MM$DD"
                fi

        else
                if (( NOCENTURY )); then
                        print "$MM$DD$YR"
                else
                        print "$MM$DD$YY"
                fi
        fi

elif [[ $1 = -j ]]; then
        (( $# < 2 )) && ExitUsage
        shift
        YY=1
        JUL=$1
        (( JUL < 1 )) && ExitErr 0

        while (( JUL > 146097 )); do
                (( YY+=400 ))
                (( JUL-=146097 ))
        done
        while (( JUL > 36524 )); do
                (( YY+=100 ))
                (( JUL-=36524 ))
        done
        while (( JUL > 1461 )); do
                (( YY+=4 ))
                (( JUL-=1461 ))
        done
        while (( JUL > 365 )); do
                (( YY+=1 ))
                (( JUL-=365 ))
        done
        CheckLeapYear
        (( YR=YY%100 ))
        DayOfYear=$JUL

        (( LEAP )) && (( DAYS[1]=29 ))
        (( MM=1 ))
        while (( JUL > DAYS[MM-1] )); do
                (( JUL-=DAYS[MM-1] ))
                (( MM+=1 ))
        done
        (( DD=JUL ))

        if (( JUSTDAY )); then
                print $DayOfYear

        elif (( NOYEAR )); then
                print "$MM$DD"

        elif (( SORTORDER )); then
                if (( NOCENTURY )); then
                        print "$YR$MM$DD"
                else
                        print "$YY$MM$DD"
                fi

        else
                if (( NOCENTURY )); then
                        print "$MM$DD$YR"
                else
                        print "$MM$DD$YY"
                fi
        fi

else
        if [[ $1 = '=' ]]; then
                DATE=$(date +%m%d)
        else
                DATE=$(print $1 | sed s/[^0-9]//g)
        fi

        VerLEN=${#DATE}
        if (( ${#DATE} == 8 )); then
                (( YY=DATE % 10000 ))
                (( DATE/=10000 ))

        elif (( ${#DATE} == 6 )); then
                (( YY=DATE % 100 ))
                if (( YY < 20 )); then
                        (( YY+=2000 ))
                else
                        (( YY+=1900 ))
                fi
                (( DATE/=100 ))

        elif (( ${#DATE} == 4 )); then
                YY=$(date +%Y)
        else
                ExitErr 1
        fi
        CheckLeapYear

        (( MM=DATE / 100 ))
        (( DD=DATE % 100 ))

        (( MM < 1 || MM > 12 )) && ExitErr 2
        (( DD < 1 )) && ExitErr 3
        if (( LEAP == 1 && MM == 2 )); then
                (( DD > 29 )) && ExitErr 4
        else
                (( DD > DAYS[MM-1] )) && ExitErr 5
        fi

        if (( VERIFY )); then
                (( VerLEN > 4 )) && exit 0
                (( NOCENTURY )) && exit 0
                exit 1
        fi

        (( X=YY - 1 ))
        (( LeapCount=(X / 400) * 97 ))
        (( X%=400 ))
        (( LeapCount+=(X / 100) * 24 ))
        (( X%=100 ))
        (( LeapCount+=(X / 4) ))

        (( JUL=(YY-1) * 365 ))
        (( JUL+=LeapCount ))

        DayOfYear=0
        X=1
        while (( X < MM )); do
                (( DayOfYear+=DAYS[X-1] ))
                (( X+=1 ))
        done
        (( LEAP == 1 && MM > 2 )) && (( DayOfYear+=1 ))
        (( DayOfYear+=DD ))

        (( JUL+=DayOfYear ))

        if (( JUSTDAY )); then
                print $DayOfYear
        elif (( YEARDAY )); then
                if (( NOCENTURY )); then
                        (( YR=YY % 100 ))
                        print "$YR$DayOfYear"
                else
                        print "$YY$DayOfYear"
                fi
        else
                print $JUL
        fi
fi

##
## end of file ################################################################


