Reputation: 61
I have a requirement where I need to kick off certain processes on end of every month. I am getting the date as an Input from previous process and date is in Julian format (for e.g. 2020105 CCYYDDD). I need to check if the date passed is month end. I'm thinking of 2 options:
In either cases, please guide me to some materials I can refer.
I'm aware I can get the current date using echo $(date '+%Y-%m-%d')
and then check if its the last day of the month. But I need to strongly consider the Julian date that is coming as the input to my process as it is being sent by the Business.
Thanks in advance for the help.
Upvotes: 0
Views: 516
Reputation: 241701
If you have Gnu date, you can use the following function:
next_day_of_month () {
date -d "${1:0:4}-01-01 $((10#${1:4:3})) days" +%-d
}
which takes a Julian date in the format you specify, and computes the day of the month of the following day.
If you want a pure bash solution (which, despite the fact that it calls no external utilities, is seriously slow), you can use the following.
There is a not-very-complicated formula which can be used to compute the month corresponding to the day number, but it requires the count of days starting with the previous March 1, rather than with January 1. Correcting the day number in that way requires knowing whether the year is a leap year or not, which makes things just a tad more complicated.
Anyway, here it is. [Note 1]
# Compute the month number (1-12) corresponding to a day in
# in "Julian" format YYYYJJJ (001 == Jan. 1; 365/6 == Dec. 31)
# Yes, I know it's full of magic numbers.
month_for_julian_day () {
local -i y=${1:0:4} j=10#${1:4:3} march1=60
if (( y % 400 == 0 )) || ! (( y % 100 == 0 )) && (( y % 4 == 0)); then
march1=61
fi
if (( j >= march1 )); then j=j-march1; else j=j+305; fi
local -i m=(j*5+461)/153
if (( m > 12 )); then m=m-12; fi
echo $m
}
To make use of this, it would be handy to have
# Advance a Julian date to the next day.
# Note: this one doesn't wrap around. Because of the way it's used
# here, that doesn't matter.
julian_next() { printf "%s%03d" ${1:0:4} $((10#${1:4:3})); }
Then you can define
# Succeeds if the Julian date is the last day of a month
is_last_day_of_month() {
(( $(month_for_julian_day $j) != $(month_for_julian_day $(next_julian $j)) ))
}
#
starts a comment. That's not true. #
only starts a comment if it's the first character in a word. In this case, the assignment j=10#${1:4:3}
forces the last three digits of the supplied date to be interpreted in base 10.Upvotes: 1