11

In BASH shell scripting or using gdate, given a date like "Oct 2011" how do I convert to a year-month number format? Output should be "2011-10", for example.

7 Answers 7

21
mydate="Oct 2011" date --date="$(printf "01 %s" $mydate)" +"%Y-%m" 

The parse_datetime interface for GNU date (which is what the example uses) has lots of rules. the Oct 2011 form of the date isn't one of them, so you prepend a "01 " to the front of it and date likes it.

Sign up to request clarification or add additional context in comments.

2 Comments

This didn't work for me, I had to put quotes around $mydate such that the second line reads date --date="$(printf "01 %s" "$mydate")" +"%Y-%m" as otherwise Oct 2011 becomes Oct2011
simple question to make sure I'm not missing anything but, in your example, what's the advantage of using printf ? I'v tried as date --date="01 $mydate" +"%Y-%m" which seems to yield the same result but maybe I'm oversimplifying just to run into some corner cases later.
11
read mon year <<< "Oct 2012" date -d "$mon 1 $year" "+%Y-%m" 

Result:

2012-10 

3 Comments

You can even skip the read command, as "1 Oct 2012" is an accepted input format for date: dateStr="Oct 2012"; date -d "1 $dateStr" "+%Y-%m"
a little more explanation would be nice, like with the 1 in between $mon and $year and the + in front of %Y.
I figured out the 1 after $mon is like a flag that says 'use the abbreviated month'. the + is when using an option to specify date(s), any non-option argument must be a format string beginning with '+'
5

You can convert the month to a number by finding the position of the name string:

#!/bin/bash month=Oct months="JanFebMarAprMayJunJulAugSepOctNovDec" tmp=${months%%$month*} month=${#tmp} monthnumber $((month/3+1)) printf "%02d\n" $monthnumber 

The output of the script above is:

10 

Your specific string you could code:

#!/bin/bash mydate="Oct 2011" monthnumber() { month=$1 months="JanFebMarAprMayJunJulAugSepOctNovDec" tmp=${months%%$month*} month=${#tmp} monthnumber=$((month/3+1)) printf "%02d\n" $monthnumber } arr=(`echo ${mydate}`); month=$(monthnumber ${arr[0]}) year=$(echo ${arr[1]}) echo "$year-$month" 

The output would be:

2011-10 

Comments

4
case "`date | awk '{print $2 }'`" in Jan) MON="01" ;; Feb) MON="02" ;; Mar) MON="03" ;; Apr) MON="04" ;; May) MON="05" ;; Jun) MON="06" ;; Jul) MON="07" ;; Aug) MON="08" ;; Sep) MON="09" ;; Oct) MON="10" ;; Nov) MON="11" ;; Dec) MON="12" ;; esac echo $MON 

Comments

2

I'm not sure if there is a shorter way of doing this, but here is one way. This is by no means fool proof. You can improve this by adding other checks to input and make the comparison case insensitive.

#!/bin/ksh ### Validate input if [ $# -eq 0 ] then echo "Usage: $0 InputMonYYYY" echo "Example: $0 \"Oct 2011\"" exit 1 fi ### Read input INPUTSTR=$1 MON_STR=`echo $INPUTSTR |cut -d' ' -f1` YYYY_STR=`echo $INPUTSTR |cut -d' ' -f2` if [[ "$MON_STR" = "Jan" ]] then MON_NUM=01 elif [[ "$MON_STR" = "Feb" ]] then MON_NUM=02 elif [[ "$MON_STR" = "Mar" ]] then MON_NUM=03 elif [[ "$MON_STR" = "Apr" ]] then MON_NUM=04 elif [[ "$MON_STR" = "May" ]] then MON_NUM=05 elif [[ "$MON_STR" = "Jun" ]] then MON_NUM=06 elif [[ "$MON_STR" = "Jul" ]] then MON_NUM=07 elif [[ "$MON_STR" = "Aug" ]] then MON_NUM=08 elif [[ "$MON_STR" = "Sep" ]] then MON_NUM=09 elif [[ "$MON_STR" = "Oct" ]] then MON_NUM=10 elif [[ "$MON_STR" = "Nov" ]] then MON_NUM=11 elif [[ "$MON_STR" = "Dec" ]] then MON_NUM=12 fi echo ${YYYY_STR}-${MON_NUM} 

1 Comment

mon=(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) echo ${mon[3]}
2

Bash4 supports hash-tables (answer by Jim is the correct one though).

Example

#!/bin/bash declare -A months=( ["Jan"]="01" ["Feb"]="02" ) mydate="Jan 2011" echo ${mydate:4:8}-"${months["${mydate:0:3}"]}" 

Output:

2011-01 

Comments

1

Let's kick this dead horse. If you don't care about invalid month names you can use this function I've written which is quite short (and only does 1 exec) but expects a month to be valid english 3-chars lower or upper case and only requires GNU sed and bash:

m2n() { echo $((-10+$(sed 's/./\U&/g;y/ABCEGLNOPRTUVY/60AC765A77ABB9/;s/./+0x&/g'<<<${1#?}) ));} 

For your example I'd do:

read m y <<<"$@"; echo "$y-`m2n $m`" 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.