1

quick (and probably stupid) question this morning:

I have data being fed to my script that looks like this:

03:00P - Doctor appointment.
07:00P - Scheduled entry.
10:30A - Another entry.
11:00A - Daytime medication is due.
11:00P - Nighttime medication is due.
11:30P - Staff meeting.

Now I can't change the source of the data, and the output needs to look the same, but I need to sort it properly. Any ideas on fixing this?

Thanks!

Micha
  • 5,117
  • 8
  • 34
  • 47
user2646340
  • 33
  • 1
  • 1
  • 4
  • 1
    You manage to avoid the interesting times: `12:05A - Just past midnight and long before 11:00A` and `12:05P - Just past midday and long before 11:00P`. The accepted answer does not handle those times correctly. – Jonathan Leffler Aug 02 '13 at 16:19
  • You might find the information in [Convert 12-hour date/time to 24-hour date/time](http://stackoverflow.com/questions/440061/convert-12-hour-date-time-to-24-hour-date-time/440110#440110) useful in dealing with the issue. I think you're likely to find that preprocessing with Perl or Awk or Python to add a column containing the AM/PM time converted into 24-hour notation, then sorting on the 24-hour column, and then (if necessary) removing it is likely to be 'best', unless there's a built-in option to `sort` to handle AM/PM time sorting. – Jonathan Leffler Aug 02 '13 at 16:40

3 Answers3

1

Tell sort to first sort on the sixth character, then on the first to fifth:

sort -k1.6,1.6 -k1.1,1.5
choroba
  • 231,213
  • 25
  • 204
  • 289
0

If you take the A or P from the time and place it it front of the time, it sorts correctly just using the normal sort command. So maybe something like this:

awk '{print substr($1,6), $0}' < input  | sort | cut -d' ' -f2-

The awk command generates output like this:

P 03:00P - Doctor appointment.
P 07:00P - Scheduled entry.
A 10:30A - Another entry.
A 11:00A - Daytime medication is due.
P 11:00P - Nighttime medication is due.
P 11:30P - Staff meeting.

Which we then sort, and then strip the prefix.

larsks
  • 277,717
  • 41
  • 399
  • 399
0

Here is a solution based on a simple Perl script derived from the answer to Convert 12-hour date/time to 24-hour date/time.

Source s12.pl

#!/usr/bin/env perl
use strict;
use warnings;

sub time_12h_to_24h
{
    my($t12) = @_;
    my($hh,$mm,$ampm) = $t12 =~ m/^(\d\d?):(\d\d?)\s*([AP]M?)/i;
    $hh = ($hh % 12) + (($ampm =~ m/AM?/i) ? 0 : 12);
    return sprintf("%.2d:%.2d", $hh, $mm);
}

while (<>)
{
    my($time_12h, $entry) = split / - /;
    my $time_24h = time_12h_to_24h($time_12h);
    print "$time_24h $time_12h - $entry";
}

Note that the code accepts both { AM, PM } and { A, P } and is neutral between upper-case and lower-case for the AM/PM indicator, and ignores spaces between the time and AM/PM indicator.

Input data

This data sets contains rows for 12:05A and 12:05P as well as the data from the question.

03:00P - Doctor appointment.
07:00P - Scheduled entry.
10:30A - Another entry.
11:00A - Daytime medication is due.
11:00P - Nighttime medication is due.
11:30P - Staff meeting.
12:05A - Just past midnight and long before 11:00A.
12:05P - Just past midday and long before 11:00P.

Double-filtered output

$ perl s12.pl data | sort | sed 's/^..:.. //'
12:05A - Just past midnight and long before 11:00A.
10:30A - Another entry.
11:00A - Daytime medication is due.
12:05P - Just past midday and long before 11:00P.
03:00P - Doctor appointment.
07:00P - Scheduled entry.
11:00P - Nighttime medication is due.
11:30P - Staff meeting.
$

Unfiltered output

$ perl s12.pl data | sort
00:05 12:05A - Just past midnight and long before 11:00A.
10:30 10:30A - Another entry.
11:00 11:00A - Daytime medication is due.
12:05 12:05P - Just past midday and long before 11:00P.
15:00 03:00P - Doctor appointment.
19:00 07:00P - Scheduled entry.
23:00 11:00P - Nighttime medication is due.
23:30 11:30P - Staff meeting.
$

Note that by placing the key column (24 hour time column) first in the output, the sort command is simplified (and, in general, it speeds up the sort too).

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278