8

I'm looking for a straight Unix commands to get first Sunday of next month, first Monday of next month, first Tuesday of next month, first Wednesday of next month etc.

  1. I will need them in the complete date format ( time is not mandatory )

  2. I can get numbers like 2, 3, 4 etc. As I don't want only numbers, I will need them in date format (includes day, month, year)

    $ NEXT_MONTH=`date +'%m %Y' -d 'next month'`
    $ echo $NEXT_MONTH
    04 2017
    
    $ NEXT_SUNDAY=`cal $NEXT_MONTH | awk 'NF==7 && !/^Su/{print $1;exit}'`
    $ echo $NEXT_SUNDAY
    2
    
  3. I will need these dates to send notifications for the email group.

Ex: I could get the first Saturday of next month as below.

$ firstofmonth=$(date -d '+1 months' '+%Y%m01')
20170401

$ firstsaturday=$(date -d "$firstofmonth" '+%Y-%m')-$((7 - \
                $(date -d "$firstofmonth" '+%u')     ))    
2017-04-1
11

In ksh93:

$ printf '%(%F)T\n' 'next month, first Monday'
2017-04-03

bash, since 4.2 now supports a %(<format)T in its printf buitin, but not the ability to parse this kind of date expression.

If you had to use bash and wanted to use that %(<format>)T, you could still do it without forking with something like:

printf -v code '%(
  t=$((%s + (12 - %-H) * 60 * 60))
  increment=$((8 - %u))
  current_month=%m)T' -1
eval "$code"
until
  t=$((t + increment * 24 * 60 * 60)) # next Monday around mid-day
  printf -v code '%(date=%F month=%m)T' "$t"
  eval "$code"
  [ "$month" != "$current_month" ] # until be get to next month
do
  increment=7 # the first increment is the number of days
              # til Monday. Next increments are just a week.
done
echo "$date"
  • #!/bin/bash . I'm getting the below error in bash $ printf '%(%F)T\n' 'next month, first Monday' -bash: printf: `(': invalid format character – Hima Mar 6 '17 at 14:36
  • 1
    @Hima, I did say in ksh93. bash is an unfinished clone of ksh (with some features of (t)csh and zsh and even a few of its own). Recent versions of bash have added support for printf '%(format)T' from ksh93, but not the ability to parse this kind of date specifications. Replace your she-bang with #! /path/to/ksh93 -. – Stéphane Chazelas Mar 6 '17 at 15:01
  • "bash is an unfinished clone of ksh" -- I have always felt that way. – Tim Kennedy Mar 6 '17 at 17:52
  • @Stephene, I tried with below command to get next month last saturday $ cal 04 2017 | awk 'NF <= 7 { print $6 }' | grep -v "^$" | tail -1 28 It displays the number 28, but I'm looking for the complete date 04/28/2017, plz suggestm if it possible with it. – Hima Mar 6 '17 at 21:36
9

Assuming GNU date (for that -d you're using yourself), and a zsh-like shell for {1..7}:

$ for i in {1..7} ; do \
    LC_ALL=C date '+%Y-%m-%d %a' -d "$(date +%Y%m0${i}) next month" ; \
  done | awk '/Mon/ {print $1}'
2017-04-03

Replace the awk Mon with whatever weekday is required (use LC_ALL=C to get English month names regardless of the user's locale). Also, might be better to store this into a variable if you will be re-querying for each day of the week:

$ days=$(for i in {1..7} ; do \
           LC_ALL=C date '+%Y-%m-%d %a' -d "$(date +%Y%m0${i}) next month" ; \
         done)

$ for i in Mon Tue Wed Thu Fri Sat Sun ; do \
    echo "${days}" | awk "/${i}/"'{print $1}' ; \
  done
2017-04-03
2017-04-04
2017-04-05
2017-04-06
2017-04-07
2017-04-01
2017-04-02
  • In bash also, this code returns the next month first Sun, Mon, Wed, Thus, Fri, Sat. Thank you. I think, I can modify this command to get next month last Sun, Mon, Wed etc. Let me try this. – Hima Mar 6 '17 at 14:41
  • Hi, I tried the below command to get next month last saturday $ cal 04 2017 | awk 'NF <= 7 { print $6 }' | grep -v "^$" | tail -1 It displays the number 28, but I'm looking for the complete date like 04/28/2017, plz suggest if it possible. – Hima Mar 7 '17 at 14:35
  • " for i in {1..7}; do date '+%Y-%m-%d %a' -d "$(date +%Y%m01 -d '2 months') ${i} days ago"; done | awk '/Sat/ {print $1}' " - this will give 2017-04-29, which is the last Saturday of the next month. This code goes 2 months forward, to the first day of that month, and then goes back 1-7 days to get the last 7 days day data for the previous month. I would personally avoid using cal as I have tried the other examples here and none work at all on my version (CentOS 6). – parkamark Mar 7 '17 at 14:50
2

PHP actually makes it pretty easy to parse dates with textual input, if it's available on your system.

Example:

bash-[522]$ php -qr 'date_default_timezone_set("UTC"); echo date("d-m-Y\n", strtotime("first monday of next month"));'
03-04-2017

I have this function in my .bashrc:

get_date ()
{
    text="$*";
    php -qr "date_default_timezone_set(\"UTC\"); echo date(\"d-m-Y\n\", strtotime(\"$text\"));"
}

Which I can use as:

bash-[523]$ get_date first monday of next month
03-04-2017

Edit Adding option to use cal

Almost every system that has bash will have cal. The calendar program. You can get a list of the date for the first of each week day by running a combination of cal, date, and awk, as follows:

 cal -hN $(date -d 'next month' +%b' '%Y) | grep -v $(date -d 'next month' +%b) | awk -v date=$(date -d 'next month' +%Y-%m-) '{ printf "%s: "date"%02i\n", $1, $2; }'

Which will give you the following output:

Su: 2017-04-02
Mo: 2017-04-03
Tu: 2017-04-04
We: 2017-04-05
Th: 2017-04-06
Fr: 2017-04-07
Sa: 2017-04-01

Change $2 to $NF in the awk statement to get the date of the last occurence of each day in a month.

  • Its not working in bash, $ php -qr 'date_default_timezone_set("UTC"); echo date("d-m-Y\n", strtotime("first monday of next month"));' -bash: php: command not found. please let me know the way to get it done in bash as well. and also, the command to get next month last Sun thru Sat. I did tried it, some how it throws errors. thanks ..!! – Hima Mar 6 '17 at 16:20
  • The means you don't have php installed. I have updated with an example that uses the cal, date, and awk commands. – Tim Kennedy Mar 6 '17 at 17:51
  • I tried this command and throws an error. Thank you.!! $ cal -hN $(date -d 'next month' +%b' '%Y) | grep -v $(date -d 'next month' +%b) | awk -v date=$(date -d 'next month' +%Y-%m-) '{ printf "%s: "date"%02i\n", $1, $2; }' cal: invalid option -- h usage: cal [-13smjyV] [[month] year] – Hima Mar 6 '17 at 19:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.