更改 csv 文件的日期和时间格式,而不使用 date -d

更改 csv 文件的日期和时间格式,而不使用 date -d

我有一个.csv文件包含

Data1|Data2|10/24/2017 8:10:00 AM

我想更改第 3 列的日期和时间格式,如下所示:

10/24/2017 8:10:00 AM(12 小时)到20171024 08:10:00(24 小时)。

不使用-d

答案1

一个纯粹的 awk 解决方案(不分叉命令date):

awk -F'|' -vOFS='|' '
function fail() {
        printf "Bad data at line %d: ", NR
        print
        next
    }
    {
        if (split($3, date_time, " ") != 3) fail()
        if (split(date_time[1], date, "/") != 3) fail()
        if (split(date_time[2], time, ":") != 3) fail()
        if (time[1] == 12) time[1] = 0
        if (date_time[3] == "PM") time[1] += 12
        $3 = sprintf("%.4d%.2d%.2d %.2d:%.2d:%.2d", date[3], date[1], date[2], time[1], time[2], time[3])
        print
    }'
  • -F'|'将输入行在竖线处分成$1$2$3等...
  • split($3, date_time, " ")将日期/时间字段分为三部分:日期、时间和 AM/PM 指示器。如果没有三块,则发出错误消息并跳过该行。
  • split(date_time[1], date, "/")将日期分为月、日和年。
  • split(date_time[2], time, ":")将时间分为小时、分钟和秒。
  • 按小时做一些数学计算;例如,12:42 AM 是 24 小时制的 00:42。当然 PM 会增加 12 个小时。
  • 重新sprintf组合年、月、日、小时、分钟和秒,并在必要时添加前导零。将此分配为$3使用重新格式化的日期/时间重建输入行;然后我们打印它。
  • 特征:如果输入的字段超过三个;例如,

    Data1|Data2|10/24/2017 8:10:00 AM|Data4|Data5
    

    该脚本将保留这些额外的字段。


用法:  一些小的变化:

  • 键入上面的多行命令,然后在最后一行的末尾(紧接在 后面}')输入要处理的文件的名称。您(当然)可以*.csv在此处使用通配符(例如,)作为文件名的补充或替代。
  • 与上面相同,但是之后}',说<和一个文件名。 (通过这种方式,您一次只能处理一个文件。)
  • 创建脚本文件。 
    • 第一行应该是#!/bin/sh. (或者,如果您愿意,您可以使用#!/bin/bash 或 #!/usr/bin/env bash。对这些不同“she-bang”线路之间的差异以及它们的相对优点和反迹象的讨论超出了本问题的范围,但您可以找到很多如果你搜索的话,就该主题进行讨论。)
    • 然后将上面的代码从第2行开始。
    • 在最后一行的末尾(紧接在 之后}'),输入 "$@" (包括引号)。
    • 保存文件。我们假设您调用该脚本gman
    • 类型chmod +x gman
    • 键入./gman后跟文件名和/或通配符列表,或者<和一个文件名。

答案2

这是一种方法(假设infile是您的 CSV 文件):

#!/bin/bash

IFS='|'
while read data1 data2 datestr 
do
    newdatestr=$(date -d"$datestr" +"%Y%m%d %T")
    printf "%s|%s|%s\n" "$data1" "$data2" "$newdatestr"
done < infile

答案3

AWK

保存存档a.awk

BEGIN{
    FS="|"
    OFS = FS
}
{
    "date -d '"$3"' +'%Y%m%d %T' " | getline l
    $3 = l
    print $0
}

并使用您的 csv 文件运行它:

awk -f a.awk file.csv

例如输出为:

Data1|Data2|20171024 08:10:00
Data1|Data2|20171024 20:10:00
Data1|Data2|20171024 20:10:00
Data1|Data2|20171024 20:14:00
Data1|Data2|20171024 20:14:00
Data1|Data2|20171024 20:11:00
Data1|Data2|20171024 20:10:06
Data1|Data2|20171024 20:10:06
Data1|Data2|20171024 08:10:50

以此为例:

Data1|Data2|10/24/2017 8:10:00 AM
Data1|Data2|10/24/2017 8:10:00 PM
Data1|Data2|10/24/2017 8:10:00 AM
Data1|Data2|10/24/2017 8:14:00 PM
Data1|Data2|10/24/2017 8:10:00 AM
Data1|Data2|10/24/2017 8:11:00 PM
Data1|Data2|10/24/2017 8:10:06 PM
Data1|Data2|10/24/2017 8:10:00 PM
Data1|Data2|10/24/2017 8:10:50 AM

答案4

使用 GNU date(但不是date -d)和类似的 shellbash可以理解进程替换:

$ cat file
Data1|Data2|10/24/2017 8:10:00 AM
Data1|Data2|10/24/2017 8:10:00 AM
Data1|Data2|10/24/2017 8:10:00 AM
Data1|Data2|10/24/2017 8:10:00 AM
Data1|Data2|10/24/2017 8:10:00 AM
$ paste -d '|' <( cut -d '|' -f -2 file ) <( date -f <( cut -d '|' -f 3 file ) +'%Y%m%d %T' )
Data1|Data2|20171024 08:10:00
Data1|Data2|20171024 08:10:00
Data1|Data2|20171024 08:10:00
Data1|Data2|20171024 08:10:00
Data1|Data2|20171024 08:10:00

调用date从命令中读取日期,该命令从给定文件中cut提取第三个- 分隔列。|它每行输入输出一个重新格式化的日期。

然后使用将其与前两列粘贴在一起paste

这样做的缺点是它读取文件两次,但只调用date一次(并且没有-d)。

相关内容