4

I am creating a script that collects information from the previous month used for reporting:

So far I have the below variables:

#I used an array to get the previous month. 
set -A months Dec Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov
x=`date +%m`  
y=`expr $x - 1`
year=`date +%Y`
month=`perl -MPOSIX=strftime -le '@t = localtime; $t[3] = 1; $t[4]--;print strftime("%m", @t)'`
month_abv=`echo ${months[$y]}`

Variable output:

year=2017
month=04
month_abv=Apr

All I need now is the last day of the previous month.

1
  • 1
    Both Linux and HP-UX at the same time?
    – ilkkachu
    Commented May 9, 2017 at 9:22

5 Answers 5

5

You could calculate one day before the first day of this month, using GNU date:

date -d "$(date +"%Y-%m-01") - 1 day" +"%F"

or using dateutils's dateadd:

dateadd "$(date +"%Y-%m-01")" "-1d"

or a bit tricky dateutils usage. Round to the last 31th month day. (Documented behavior which works even for months with less than 31 days.)

$ dateround --next today -31d
2017-04-30
$ dateround --next "2016-03-10" -31d
2016-02-29
5
  • These are often not available on HP-UX. Commented May 9, 2017 at 21:24
  • 1
    The reason why I did not use date -d, because it does not work in HPUX unfortunately Commented May 10, 2017 at 12:10
  • @ChristopherKarsten I know. My solution is about either installing "dateutils" or "GNU date". There is no single operating systems on the planet where dateutils is installed by default. But nevertheless there are people who use it ... ;)
    – rudimeier
    Commented May 10, 2017 at 12:25
  • @rudimeier, have anyone installed dateutils on HP-UX? I don't seem to find any matches on Google.
    – saulius2
    Commented Sep 3, 2020 at 7:09
  • @saulius2 It should be possible to build dateutils from the the released source tarballs: bitbucket.org/hroptatyr/dateutils/downloads , if something does not work, the author will be happy about a bug-report/question: github.com/hroptatyr/dateutils/issues
    – rudimeier
    Commented Sep 7, 2020 at 15:46
2

The way I went about getting the last day of the previous month is:

cal $month $year | awk 'NF {DAYS = $NF}; END {print DAYS}'

Using the varaible placeholders I am able to get the previous months calander and printing the last day of the month:

cal 04 2017 | awk 'NF {DAYS = $NF}; END {print DAYS}'

Output:

30

If there is an easier way or shorter way please, I am open to all suggestions.

2

Try:

eval "$(
  LC_ALL=C perl -MPOSIX -le '
    @t = localtime;
    $t[3]=0; # set day to 0 (day before the first)
    print strftime q(year=%Y month=%m day=%d month_abv="%b"), @t'
)"

perl constructs some shell code (like year=2017 month=04 day=30 month_abv="Apr") which we then evaluate into the current shell (assuming a POSIX shell).

LC_ALL=C is to force the month_abv to be in English regardless of the locale. Remove it if you'd rather it be in the user's locale.

That day=0 trick works with the strftime() of GNU, FreeBSD and Solaris, but I don't know how portable it is outside of that.

To get the first day, of the previous month, replace $t[3]=0 with $t[3]=1; $t[4]-- which for me works even if run in January but again, I'm not sure how portable it is.

3
  • I know this nice strftime, mktime and struct tm behavior. But I always wondered whether this is documented somewhere in perl or POSIX documentation. I could only find it for glibc (man mktime).
    – rudimeier
    Commented May 9, 2017 at 14:48
  • @rudimeier, I can't say the POSIX specification is very clear on that. values[...] shall not be restricted to the ranges described in <time.h>, but that's not saying how the time should be calculated if you use 1234 as the day of the month number or a negative month. Commented May 9, 2017 at 15:05
  • Interesting, in POSIX 2003 was "components are not restricted" instead of shall. Sounds somehow weaker now.
    – rudimeier
    Commented May 9, 2017 at 16:05
2

The below seems to work OK for me on ksh88 (thanks to Stéphane Chazelas for some assistance with this)

#! /bin/ksh
eval "$(date +'y=%Y m=%m')"
echo "Current month = $m"
echo "Current year = $y"

#get previous month (and year of previous month)
if [[ $((m-1)) -gt 0 ]]
then
    p_m=$((m-1))
    p_m_y=$((y))
else
    p_m=12
    p_m_y=$((y-1))
fi
echo "p_m = $p_m"
echo "p_m_y = $p_m_y"

#get first/last day of previous month
p_m_from=01.${p_m}.${p_m_y}
p_m_to=$(cal $p_m $p_m_Y | grep -v ^$ | tail -1 | sed 's/^.* \([0-9]*\)$/\1/').${p_m}.${p_m_y}
echo "Previous month runs from $p_m_from to $p_m_to"
1
0

To find previous month follow this:

date -d "-1 months" +%Y/%-m/%-d

This will give you: 2018/2/22 while it is 2018/3/22.

date -d "-1 days" +%Y/%-m/%-d

Will give you: 2018/3/21

You can add or subtract as many months or days you like. If you subtract enough months it will go to last year.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .