Micheal Perr
Micheal Perr

Reputation: 1895

Converting Dates in Shell

How can I convert one date format to another format in a shellscript?

Example:

the old format is

MM-DD-YY HH:MM

but I want to convert it into

YYYYMMDD.HHMM

Upvotes: 2

Views: 898

Answers (4)

shellter
shellter

Reputation: 37258

 myDate="21-12-11 23:59"
 #fmt is DD-MM-YY HH:MM
 outDate="20${myDate:6:2}${myDate:3:2}${myDate:0:2}.${myDate:9:2}${myDate:12:2}00"

 case "${outDate}" in 
    2[0-9][0-9][0-9][0-1][0-9][0-3][0-9].[0-2][0-9][0-5][[0-9][0-5][[0-9] ) 
      : nothing_date_in_correct_format 
    ;; 
    * ) echo bad format for ${outDate} >&2
    ;; 
 esac

Note that if you have a large file to process, then the above is an expensive(ish) process. For filebased data I would recommend something like

 cat infile
 ....|....|21-12-11 23:59|22-12-11 00:01| ...|

 awk '
    function reformatDate(inDate) {
       if (inDate !~ /[0-3][0-9]-[0-1][0-9]-[0-9][0-9] [0-2][0-9]:[0-5][[0-9]/) {
         print "bad date format found in inDate= "inDate
         return -1
       }
       # in format assumed to be DD-MM-YY HH:MM(:SS)
       return (2000 + substr(inDate,7,2) ) substr(inDate,4,2) substr(inDate, 1,2) \
              "." substr(inDate,10,2) substr(inDate,13,2) \
               ( substr(inDate,16,2) ?  substr(inDate,16,2) : "00" )
    }
    BEGIN {       
       #add or comment out for each column of data that is a date value to convert
       # below is for example, edit as needed.
       dateCols[3]=3
       dateCols[4]=4
       # for awk people, I call this the pragmatic use of associative arrays ;-)

       #assuming pipe-delimited data for columns
       #....|....|21-12-11 23:59|22-12-11 00:01| ...|
       FS=OFS="|"
    }
    # main loop for each record
    {
       for (i=1; i<=NF; i++) {
         if (i in dateCols) {
            #dbg print "i=" i "\t$i=" $i
            $i=reformatDate($i)
         }
       }
       print $0
    }' infile

output

....|....|20111221.235900|20111222.000100| ...|

I hope this helps.

Upvotes: 0

glenn jackman
glenn jackman

Reputation: 246744

Take advantage of the shell's word splitting and the positional parameters:

date="12-31-11 23:59"
IFS=" -:"
set -- $date
echo "20$3$1$2.$4$5"  #=> 20111231.2359

Upvotes: 2

Vasiliy Sharapov
Vasiliy Sharapov

Reputation: 1057

There is a good answer down already, but you said you wanted an alternative in the comments, so here is my [rather awful in comparison] method:

read sourcedate < <(echo "12-13-99 23:59");
read sourceyear < <(echo $sourcedate | cut -c 7-8);
if [[ $sourceyear < 50 ]]; then
read fullsourceyear < <(echo -n 20; echo $sourceyear);
else
read fullsourceyear < <(echo -n 19; echo $sourceyear);
fi;
read newsourcedate < <(echo -n $fullsourceyear; echo -n "-"; echo -n $sourcedate | cut -c -5);
read newsourcedate < <(echo -n $newsourcedate; echo -n $sourcedate | cut -c 9-14);
read newsourcedate < <(echo -n $newsourcedate; echo :00);
date --date="$newsourcedate" +%Y%m%d.%H%M%S

So, the first line just reads a date in, then we get the two-digit year, then we append it to '20' or '19' based on if it's less than 50 (so this would give you years from 1950 to 2049 - feel free to shift the line). Then we append a hyphen and the month and date. Then we append a space and the time, and lastly we append ':00' as the seconds (again feel free to make your own default). Lastly we use GNU date to read it in (since it's been standardized now) and print it in a different format (which you can edit).

It's a lot longer and uglier than cutting up the string, but having the format in the last line may be worth it. Also you could shorten it significantly with the shorthand you just learned in the first answer.

Good luck.

Upvotes: 0

Michael Krelin - hacker
Michael Krelin - hacker

Reputation: 143061

Like "20${D:6:2}${D:0:2}${D:3:2}.${D:9:2}${D:12:2}00", if the old date in the $D variable.

Upvotes: 2

Related Questions