我试图弄清楚如何重新格式化充满格式错误的日期的文件。来源看起来像这样:
{"_id":"","timestamp":"Mon Apr 20 08:30:55 +0000 2015"}
{"_id":"","timestamp":"Mon Apr 20 08:32:25 +0000 2015"}
{"_id":"","timestamp":"Mon Apr 20 08:35:39 +0000 2015"}
类似这样的条目大约有300万个。我需要将时间戳格式化为 ISO-8601 格式,即: YYYY-MM-DDTHH:mm:ss.mmm<+/-Offset>
我已经尝试过这个,它有效:
date -d "Mon Apr 20 08:35:39 +0000 2015" +%FT%T%z
因为我显然不会手动浏览所有 300 万个条目,所以我考虑使用 sed 来实现此目的:
cat input.json | sed "s|\"timestamp\":\"\(.*\)\"|\"timestamp\":\"$(date -d \1 +%FT%T%z)\"|g" > output.json
但是,每次都会打印相同(错误)的输出,即2015-05-08T01:00:00+0000
。 这里有没有人能帮我解决这个难题?
答案1
可以用于sed
此目的,但awk
更自然:
awk -F'"' -v OFS='"' '$8 {cmd="date -d \""$8"\" +%FT%T%z"; cmd | getline $8; close(cmd)} 1' input.json
{"_id":"","timestamp":"2015-04-20T01:30:55-0700"}
{"_id":"","timestamp":"2015-04-20T01:32:25-0700"}
{"_id":"","timestamp":"2015-04-20T01:35:39-0700"}
上图显示了 -7:00 小时的偏移量。这反映了系统的默认时区。更改 shell 变量TZ
将更改默认值。
怎么运行的
-F'"' -v OFS='"'
这将输入和输出字段分隔符设置为
"
。$8 {cmd="date -d \""$8"\" +%FT%T%z"; cmd | getline $8; close(cmd)}
作为
"
字段分隔符,日期是字段号 8。这将使用正确的date
命令创建字符串,然后运行命令将输出捕获到更新的字段 8 中。前面的out
$8
意味着只有在字段 8 存在非空值时才会运行此部分。例如,这允许空行不受干扰地通过。1
这是 awk 对“打印这一行”的神秘简写。
处理额外的双引号
由于我们使用"
作为字段分隔符。假设"
时间戳之前有可变数量的。在这种情况下,我们需要将时间戳称为倒数第二个字段 ,$(NF-1)
而不是第八个字段$8
。在这种情况下:
awk -F'"' -v OFS='"' '$8 {cmd="date -d \""$(NF-1)"\" +%FT%T%z"; cmd | getline $(NF-1); close(cmd)} 1' input.json
将自定义格式添加到日期字段
$ awk -F'"' -v OFS='"' '$8 {cmd="date -d \""$(NF-1)"\" +%FT%T%z"; cmd | getline $(NF-1); close(cmd);$(NF-1)="{$date:" $(NF-1) "}"} 1' input.json
{"_id":"","timestamp":"{$date:2015-04-20T01:30:55-0700}"}
{"_id":"","timestamp":"{$date:2015-04-20T01:32:25-0700}"}
{"_id":"","timestamp":"{$date:2015-04-20T01:35:39-0700}"}
答案2
答案3
如果您可以保证输入的格式与您所显示的完全一样,那么您可以完全在sed
.这有点暴力:
sed \
-e 's/"timestamp":"... Jan/"timestamp":"01/' \
-e 's/"timestamp":"... Feb/"timestamp":"02/' \
-e 's/"timestamp":"... Mar/"timestamp":"03/' \
-e 's/"timestamp":"... Apr/"timestamp":"04/' \
-e 's/"timestamp":"... May/"timestamp":"05/' \
-e 's/"timestamp":"... Jun/"timestamp":"06/' \
-e 's/"timestamp":"... Jul/"timestamp":"07/' \
-e 's/"timestamp":"... Aug/"timestamp":"08/' \
-e 's/"timestamp":"... Sep/"timestamp":"09/' \
-e 's/"timestamp":"... Oct/"timestamp":"10/' \
-e 's/"timestamp":"... Nov/"timestamp":"11/' \
-e 's/"timestamp":"... Dec/"timestamp":"12/' \
-e 's/"timestamp":"\(..\) \(..\) \(..:..:..\) \(.....\) \(....\)"/"timestamp":"\5-\1-\2T\3\4"/' \
input.json > output.json
它将月份名称替换为月份名称,然后分割(现在)全数字日期字符串,并按所需顺序将各个部分重新组合在一起。如果要添加.000
毫秒,请将其插入到\3
和之间\4
。