将日志文件时间戳从 12 小时时间格式转换为 24 小时时间格式

问题描述 投票:0回答:3

我有许多大的、以空格分隔的 WhatsApp 聊天记录,我需要将时间戳从 12 小时时间格式转换为 24 小时时间格式。

这些文件95%的内容保持相同的行格式如下:

MM/DD/YY,|HH:MM|XM|-|participant:|chatText

但是,这些聊天记录中有一些实例没有保持如上所示的标准行格式。

这是日志示例:

5/30/22, 9:50 AM - person2: Good morning
5/30/22, 11:35 AM - person1: Hi, how are you?
5/30/22, 11:47 AM - person2: I am well
Transfer number: 3778324
Completed:
5/30/22, 12:55 PM - person1: https://mylink.com
5/30/22, 12:59 PM - person2: <Media omitted>
5/30/22, 9:46 PM - person1: thanks

以下是要求:

  1. 接受来自日志文件的输入
  2. 输出更改为就地或单独的输出文件
  3. 将第二个空格分隔位置的 HH:MM XM 的所有实例更改为 24 小时格式
  4. 不要对非标准格式的行进行任何更改
  5. 不想安装任何额外的开发环境

这是更改后的示例:

5/30/22, 09:50 - person2: Good morning
5/30/22, 11:35 - person1: Hi, how are you?
5/30/22, 11:47 - person2: I am well
Transfer number: 3778324
Completed:
5/30/22, 12:55 - person1: https://mylink.com
5/30/22, 12:59 - person2: <Media omitted>
5/30/22, 21:46 - person1: thanks

这是我到目前为止能想到的,但我不知道如何超越 HH 位置,我也不知道如何避免对非标准格式的行进行更改:

echo "5/30/22, 9:46 PM - person1: thanks"\ |awk -F' ' 'BEGIN{OFS=" "}{("date --date=\""$2 $3"\" +%H:$M") |getline $2;print }'

任何帮助将不胜感激!

bash awk sed timestamp logfile
3个回答
1
投票

使用任何 POSIX awk:

$ cat tst.awk
$1 ~ "^([0-9]{1,2}/){2}[0-9]{2},$" {
    split($2,t,":")
    if ( ($3 == "PM") && (t[1] < 12) ) {
        t[1] += 12
    }
    time = sprintf(" %02d:%02d ", t[1], t[2])
    sub(/ [0-9]{1,2}:[0-9]{2} [AP]M /,time)
}
{ print }

$ awk -f tst.awk file
5/30/22, 09:50 - person2: Good morning
5/30/22, 11:35 - person1: Hi, how are you?
5/30/22, 11:47 - person2: I am well
Transfer number: 3778324
Completed:
5/30/22, 12:55 - person1: https://mylink.com
5/30/22, 12:59 - person2: <Media omitted>
5/30/22, 21:46 - person1: thanks

上面使用

sub()
来更改
$0
而不是直接更改
$2
$3
这样它就不会更改以时间戳开头的行上的任何空白(制表符和/或空白链将是如果直接更改
$2
$3
,则转换为单个空格),例如用上面的脚本改变
$0

$ cat file1
5/30/22, 9:50 AM - person2: Good      morning

$ awk -f tst.awk file1
5/30/22, 09:50 - person2: Good      morning

vs如果直接改变

$2
(注意
Good
morning
之间空白的变化):

$ cat tst.awk
$1 ~ "^([0-9]{1,2}/){2}[0-9]{2},$" {
    split($2,t,":")
    if ( ($3 == "PM") && (t[1] < 12) ) {
        t[1] += 12
    }
    $2 = sprintf("%02d:%02d", t[1], t[2])
    sub(/ [AP]M /," ")
}
{ print }

$ awk -f tst.awk file1
5/30/22, 09:50 - person2: Good morning

0
投票

只是为了好玩,因为你标记了

sed
,这里有一个 GNU
sed
date
的解决方案。但是不要在大文件上使用它,它会比其他出色的
awk
解决方案慢得多:对于修改它的每一行,它都会使用 shell 执行一个
date
命令。

$ sed -E 'h;s!^(\S+),(\s+\S+\s+[AP]M\>).*!date -d "\1" +"%D, %R"!e;T;G;s!\n(\s*\S+){3}!!' file.log
05/30/22, 09:50 - person2: Good morning
05/30/22, 11:35 - person1: Hi, how are you?
05/30/22, 11:47 - person2: I am well
Transfer number: 3778324
Completed:
05/30/22, 12:55 - person1: https://mylink.com
05/30/22, 12:59 - person2: <Media omitted>
05/30/22, 21:46 - person1: thanks

替换命令的

e
标志用shell执行模式空间的内容,用输出替换模式空间。所以我们首先复制保留空间中的输入行(
h
),我们用
date, hour [AP]M <something>
替换
date -d "date hour [AP]M" +"%D, %R"
并执行感谢
e
标志。如果没有替换(非标准格式的行),我们将开始一个新的循环。否则我们将一个换行符和保留空间附加到模式空间 (
G
),然后我们删除旧的
date hour [AP]M
,只留下原始行的尾部。


0
投票

我会利用 GNU

AWK
按照以下方式完成这项任务,让
file.txt
内容成为

5/30/22, 9:50 AM - person2: Good morning
5/30/22, 11:35 AM - person1: Hi, how are you?
5/30/22, 11:47 AM - person2: I am well
Transfer number: 3778324
Completed:
5/30/22, 12:55 PM - person1: https://mylink.com
5/30/22, 12:59 PM - person2: <Media omitted>
5/30/22, 9:46 PM - person1: thanks

然后

awk '$3~/^[AP]M$/{split($2,arr,":");if($3=="PM"&&arr[1]<12){arr[1]+=12};$2=sprintf("%02d:%02d",arr[1],arr[2])}{print}' file.txt

给出输出

5/30/22, 09:50 AM - person2: Good morning
5/30/22, 11:35 AM - person1: Hi, how are you?
5/30/22, 11:47 AM - person2: I am well
Transfer number: 3778324
Completed:
5/30/22, 12:55 PM - person1: https://mylink.com
5/30/22, 12:59 PM - person2: <Media omitted>
5/30/22, 21:46 PM - person1: thanks

说明:对于第 3 个字段是 AM 或 PM 的行,如果第 3 个字段是

:
并且数组的第一个元素(即小时)是小于 12 将其增加 12,将第二个字段设置为
arr
,其中 HH 是小时,用零填充到宽度为 2,MM 是分钟,用零填充到宽度为 2。与是否进行此类更改无关
PM
线。如果您想了解有关
HH:MM
print
的更多信息,请阅读
String 函数(GNU Awk 用户指南)
。请注意,我没有设置
split
sprintf,因为默认值适用于呈现的任务。
(在 GNU Awk 5.1.0 中测试)

© www.soinside.com 2019 - 2024. All rights reserved.