输入
2012-07-24 10:05:08 AM
2012-07-26 10:13:58 AM
2012-07-24 10:13:58 AM
2012-07-24 10:57:50 AM
2012-07-24 11:15:03 AM
2012-07-24 11:26:08 PM
2012-07-25 11:26:08 PM
所需输出
2012-07-24 10:05:08 AM
2012-07-24 10:13:58 AM
2012-07-24 10:57:50 AM
2012-07-24 11:15:03 AM
2012-07-24 11:26:08 PM
2012-07-25 11:26:08 PM
2012-07-26 10:13:58 AM
代码我试过
sort -t ":" -k 1 -k 2 -k 3 Input.txt | sort -t " " -k 3
但我没有得到理想的输出。
有人可以提出任何建议吗?
我写了一段代码......但问题仍然存在......
代码
sed 's/ 12:/00:/g' Input.txt | sort -k 1,1 -k 3,3 -k 2,2 | sed 's/00:/12:/g'
首先将 12:43:01 AM 更改为 00:43:01 AM ....然后应用sort命令。
答案 0 :(得分:4)
假设您的数据存储在/ tmp / foo中,您可以将时间戳转换为具有GNU日期的数字可排序格式。例如:
date -f /tmp/foo '+%s' | sort |
while read; do
date -d "@$REPLY" "+%F %I:%M:%S %p"
done
这应该在所有情况下正确处理排序,特别是在所有AM时间应该在同一日期的所有PM时间之前到来的情况。例如,上午12:01现在列在晚上10点之前。
答案 1 :(得分:3)
除了12小时之外,字符串可以简单地按词汇顺序排序。
此解决方案使用Schwartzian Transform更改用于对字符串进行排序的键。它只会在以PM
结尾的任何字符串的小时字段中添加12,并按其排序。
use strict;
use warnings;
my @data = <DATA>;
chomp @data;
my @sorted = map $_->[0],
sort { $a->[1] cmp $b->[1] }
map { (my $dt = $_) =~ s/(\d\d)(?=:\d\d:\d\d PM)/$1+12/e; [$_, $dt] } @data;
print "$_\n" for @sorted;
__DATA__
2012-07-24 10:05:08 AM
2012-07-26 10:13:58 AM
2012-07-24 10:13:58 AM
2012-07-24 10:57:50 AM
2012-07-24 11:15:03 AM
2012-07-24 11:26:08 PM
2012-07-25 11:26:08 PM
<强>输出强>
2012-07-24 10:05:08 AM
2012-07-24 10:13:58 AM
2012-07-24 10:57:50 AM
2012-07-24 11:15:03 AM
2012-07-24 11:26:08 PM
2012-07-25 11:26:08 PM
2012-07-26 10:13:58 AM
<强>更新强>
正如斯特芬指出的那样,即使在调整上午/下午的时间后,午夜和中午仍然会阻止简单的字符串排序。
此程序使用核心Time::Piece
模块重新格式化ISO 8601格式2000-02-29T12:34:56
中的日期/时间,可以对词汇进行排序。
use strict;
use warnings;
use Time::Piece;
my @data = <DATA>;
chomp @data;
my @sorted = map $_->[0],
sort { $a->[1] cmp $b->[1] }
map { [ $_, toISO8601($_) ] } @data;
sub toISO8601 {
Time::Piece->strptime(@_, '%Y-%m-%d %I:%M:%S %p')->datetime;
}
print "$_\n" for @sorted;
__DATA__
2012-07-24 10:05:08 AM
2012-07-26 10:13:58 AM
2012-07-24 10:13:58 AM
2012-07-24 10:57:50 AM
2012-07-24 11:15:03 AM
2012-07-24 11:26:08 PM
2012-07-25 11:26:08 PM
2012-08-01 01:00:00 PM
2012-08-01 12:30:00 PM
2012-08-01 12:00:00 PM
2012-08-01 11:30:00 AM
2012-08-01 01:00:00 AM
2012-08-01 12:30:00 AM
2012-08-01 12:00:00 AM
<强>输出强>
2012-07-24 10:05:08 AM
2012-07-24 10:13:58 AM
2012-07-24 10:57:50 AM
2012-07-24 11:15:03 AM
2012-07-24 11:26:08 PM
2012-07-25 11:26:08 PM
2012-07-26 10:13:58 AM
2012-08-01 12:00:00 AM
2012-08-01 12:30:00 AM
2012-08-01 01:00:00 AM
2012-08-01 11:30:00 AM
2012-08-01 12:00:00 PM
2012-08-01 12:30:00 PM
2012-08-01 01:00:00 PM
答案 2 :(得分:2)
有点awk
病房,我承认......
<击> cat Input.txt | \ awk&#39; BEGIN {FS =&#34; [: - ]&#34;} {if($ 7 ==&#34; PM&#34;)$ 4 + = 12;打印$ 1&#34; - &#34; $ 2&#34; - &#34; $ 3&#34; &#34; $ 4#34;:&#34; $ 5#34;:&#34; $ 6#34; &#34; $ 7}&#39; | \ 排序| \ awk&#39; BEGIN {FS =&#34; [: - ]&#34;} {if($ 7 ==&#34; PM&#34;)$ 4- = 12;打印$ 1&#34; - &#34; $ 2&#34; - &#34; $ 3&#34; &#34; $ 4#34;:&#34; $ 5#34;:&#34; $ 6#34; &#34; $ 7}&#39; 击>
<击> 击><击> 撞击>
修改强>
cat Input.txt |\
awk 'BEGIN{FS="[: -]"}{if(length($4)==1) $4="0"$4 ;if($7 == "PM") $4+=12; else if($4 ==12)$4-=12; print $1"-"$2"-"$3" "$4":"$5":"$6" "$7}'|\
sort|\
awk 'BEGIN{FS="[: -]"}{if($7 == "PM") $4-=12; else if($4 ==0)$4+=12; print $1"-"$2"-"$3" "$4":"$5":"$6" "$7}'
但它有效......
说明:我使用awk
将时间格式转换为24小时,对其进行排序并将其转换回来。
修改:我将0
添加到只有一位数的小时,以便1:0:0
和12:0:0
排序正确。也适用于AM。
答案 3 :(得分:2)
使用Schartzian Transform和Date::Parse:
use strict;
use warnings;
use 5.010;
use Date::Parse;
my @data = <DATA>;
chomp @data;
my @sorted =
map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [$_, str2time($_)] } @data;
say for @sorted;
__DATA__
2012-07-24 11:15:03 AM
2012-07-24 11:26:08 PM
2012-07-25 01:26:08 PM
2012-07-25 12:26:08 PM
2012-07-25 01:26:08 AM
2012-07-25 12:26:08 AM
2012-07-25 11:26:08 AM
2012-07-25 11:26:08 PM
<强>输出:强>
2012-07-24 11:15:03 AM
2012-07-24 11:26:08 PM
2012-07-25 12:26:08 AM
2012-07-25 01:26:08 AM
2012-07-25 11:26:08 AM
2012-07-25 12:26:08 PM
2012-07-25 01:26:08 PM
2012-07-25 11:26:08 PM
答案 4 :(得分:1)
12:01 AM凌晨1点01分到来,所以我看不出使用排序会有什么帮助。
您需要转换为其他格式,例如无论何时何时,ISO 8601或秒 获得可以作为文本或数字进行比较的内容。 perl oneliner会做到这一点。
答案 5 :(得分:1)
您可以使用:
sed 's/ 12:/ 00:/'| LC_ALL="C" sort -k 1,1 -k 3 | sed 's/ 00:/ 12:/'
应该是非常快速的解决方案。
答案 6 :(得分:0)
有我的变体:
$sed 's|\([0-9]\+\)-\([0-9]\+\)-\([0-9]\+\) \([0-9]\+\):\([0-9]\+\):\([0-9]\+\) \([A-Z]\+\)|\1 \2 \3 \4 \5 \6 \7 \0|' input.txt | awk '{if($7=="AM"){$7="1";if($4==12){$4 = 0}}else{$7="0"};print}' | sort -n -k1 -k2 -k3 -k4 -k5 -k6 -k7 | cut -d' ' -f 8-
2012-07-24 10:05:08 PM
2012-07-24 10:13:58 AM
2012-07-24 10:57:50 AM
2012-07-24 11:15:03 AM
2012-07-24 11:26:08 PM
2012-07-25 11:26:08 PM
2012-07-26 10:13:58 AM
添加额外字段的主要想法,按它们排序并在排序后我将它们删除。排序数字很简单,但要对AM / PM进行排序,我将其转换为1/0位数以简化排序。
已更新:sed
+ awk
使用情况可由awk
替换:
awk -F'[-: ]' '{printf("%d %d %d %d %d %d %d %s\n", $1, $2, $3, ($4 == 12 && $7 == "AM" ? 0 : $4), $5, $6, $7 == "AM", $0)}' input.txt |
sort -n -k1 -k2 -k3 -k4 -k5 -k6 -k7 |
cut -d' ' -f 8-
更新:修复上午/下午问题
答案 7 :(得分:0)
这可能适合你(GNU sed):
sed 's/.*/echo -e "$(date -d"&" +%s)\t&"/e' file | sort -n | sed 's/.*\t//'
或:
date -f file +%s | paste - file | sort -n | sed 's/\S\+\s\+//'
答案 8 :(得分:-1)
最后我编码时没有使用任何外部模块。虽然它很长但是可以顺利地用于任何日期格式。
使用的技术:
<强>代码强>
my @input = `cat Input.txt`;
open (ts,">","tt.txt");
foreach my $i (@input)
{
chomp($i);
my $timestamp = `date --date "$i" +\%s`;
chomp($timestamp);
push (@time,$timestamp);
print ts "$timestamp\n";
}
close(ts);
open (ts,">","sort_time.txt");
my @sorted_time = join "\n",sort {$a<=>$b} @time;
chomp(@sorted_time);
print ts "@sorted_time\n";
close(ts);
my @input1= `cat sort_time.txt`;
open (ts,">","sort_timestamp.txt");
foreach my $st1 (@input1)
{
chomp($st1);
my $st2 = scalar localtime($st1);
chomp($st2);
print ts "$st2\n";
}
close(ts);
@input2 = `cat sort_timestamp.txt`;
open (ts,">","Output.txt");
foreach my $st2 (@input2)
{
chomp($st2);
$pro_time = `date --date "$st2" +\%Y-\%m-\%d~\%r | sed 's/~/ /g'`;
chomp($pro_time);
print ts "$pro_time\n";
}
close(ts);
`rm tt.txt sort_time.txt sort_timestamp.txt`;