重新格式化日期字符串

重新格式化日期字符串

我试图弄清楚如何重新格式化充满格式错误的日期的文件。来源看起来像这样:

{"_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

jq,node:

cat /tmp/what \
| jq '.timestamp' \
| while read line ; do \
  node -e "console.log(new Date($line).toISOString())" ;\
  done

还可以使用单个 Node.js 程序来处理整个文件以提高性能,但这可能过于深入 JS 领域。 (如果您想了解详细信息,请Ping。)

答案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

相关内容