将 YYYY-MM-DD HH:MM:SS 转换为相对于 0 的秒数

Convert YYYY-MM-DD HH:MM:SS to seconds relative to 0

有一个 csv 文件,其中一行有 5 个字段,用逗号分隔:

2020-07-31 15:15:55,xx,yy,zz,t
2020-07-31 15:16:57,xx,yy,zz,t
2020-07-31 15:17:00,xx,yy,zz,t

并且我想将第一行作为0秒(相对时间),所以输出是这样的:

0,xx,yy,zz,t
62,xx,yy,zz,t
65,xx,yy,zz,t

我可以使用任何编程语言来完成,例如 bash、awk、sed、perl...并覆盖相同的文件或创建一个新文件。

perl -MTime::Piece -F, -lane '
    BEGIN {$, = ","}
    $t = Time::Piece->strptime(shift(@F), "%F %T")->epoch;
    if ($. == 1) {$start = $t}
    print $t - $start, @F;
' file

这是一个有效的部分答案,考虑到日期不会改变,因此被省略。

cat file.csv | awk -F ' ' '{print }'| awk -F ':|,' '{printf (*3600+*60+)}{print ","","","","}'

这将输出这个结果,它仍然没有休息第一个值,可以从文件中读取:

54955,xx,yy,zz,t
55017,xx,yy,zz,t
55020,xx,yy,zz,t

现在,由于所有行的值都相同,因此可以手动输入:

cat file.csv | awk -F ' ' '{print }'| awk -F ':|,' '{printf (*3600+*60+-54955)}{print ","","","","}'

这将给出所需的结果:

0,xx,yy,zz,t
62,xx,yy,zz,t
65,xx,yy,zz,t

*** 稍后添加:感谢这个线程得到了一种将时间转换为纪元的方法,这是绝对的: Convert date to epoch time using AWK in linux 所以它会保持这样:

cat file.csv | awk -F, '{ OFS = FS;command="date -d " "\""  "\""  " +%s";command | getline ;close(command);print}'
1596201355,xx,yy,zz,t
1596201417,xx,yy,zz,t
1596201420,xx,yy,zz,t

** 稍后再次补充: 保留第一个值的方法是使用这个 awk 表达式:

| awk -F, 'NR==1{pattern=}{printf (-pattern)}{print ","","","","}'

所以前面解释的2种方法将保持这样: 此案例仅适用于同一天:

cat file.csv | awk -F ' ' '{print }'| awk -F ':|,' '{printf (*3600+*60+)}{print ","","","","}' | awk -F, 'NR==1{pattern=}{printf (-pattern)}{print ","","","","}'

这(使用纪元)将考虑天数:

cat file.csv | awk -F, '{ OFS = FS;command="date -d " "\""  "\""  " +%s";command | getline ;close(command);print}' | awk -F, 'NR==1{pattern=}{printf (-pattern)}{print ","","","","}'

迄今为止的最佳解决方案:将考虑使用 epoch 的天数,并将适用于任何 awk 变体,包括 BSD 变体。它还检测有多少个字段,即使只有第一个字段也会工作:
cat file.csv | awk -F, '{ OFS = FS;command="date -d " "\""  "\""  " +%s";command | getline ;close(command);print}' | awk -F, 'NR==1{pattern=}{printf (-pattern)}{if (NF > 1){for (i = 2; i < NF; i += 1) printf ","$i; print ","$NF} else print ""}'

file.csv:

2020-07-31 15:15:55,xx,yy,zz,t
2020-07-31 15:16:57,xx,yy,zz,t
2020-07-31 15:17:00,xx,yy,zz,t
2020-07-31 15:17:23,xx,yy,zz,abc,009-%5
2020-07-31 15:18:00
2020-07-31 15:19:00,xx

结果:

0,xx,yy,zz,t
62,xx,yy,zz,t
65,xx,yy,zz,t
88,xx,yy,zz,abc,009-%5
125
185,xx

这是UNIX环境无法轻易处理的问题。 利用 teip.

$ teip -d, -f1 -- sh -c "date -f- +%s" < file.txt |
  awk -F, 'NR==1{n=}{=-n};4' OFS=,
0,xx,yy,zz,t
62,xx,yy,zz,t
65,xx,yy,zz,t

@anubhava 的原始回答(只有 2 个字段):

您可以将此 awkmktime 功能一起使用。 这将输出以逗号分隔的 2 个字段:

awk 'BEGIN {
   FS=OFS=","                 # set input and output field separators to comma
}
{
   gsub(/[-:]/, " ", )      # replace - and : with a space
   tm = mktime()            # convert date-time string to EPOCH value
   if (NR == 1)               # for 1st records store this value in first
      first = tm
   print (tm - first),      # print difference and 2nd field for each record
}' file

结果:

0,xx
62,xx
65,xx

由@smeterlink 改进

这将使用 NF 变量检测所有以逗号分隔的字段,因此即使只有第一个字段也能正常工作。这样可以混合不同数量字段的行:

get.awk:

BEGIN {
   FS=OFS=","                 # set input and output field separators to comma
}
{
   gsub(/[-:]/, " ", )      # replace - and : with a space
   tm = mktime()            # convert date-time string to EPOCH value
   if (NR == 1)               # for 1st records store this value in first
      first = tm
   {
      printf (tm - first)     # print difference
      if (NF > 1)             # print 2nd to last fields only if they exist
      {
         for (i = 2; i < NF; i += 1)
         printf ","$i
         print ","$NF
      }
      else
         print ""             # otherwise print newline after printf
   }
}

file.csv:

2020-07-31 15:15:55,xx,yy,zz,t
2020-07-31 15:16:57,xx,yy,zz,t
2020-07-31 15:17:00,xx,yy,zz,t
2020-07-31 15:17:23,xx,yy,zz,abc,009-%5
2020-07-31 15:18:00
2020-07-31 15:19:00,xx

结果:

awk -f get.awk file.csv
0,xx,yy,zz,t
62,xx,yy,zz,t
65,xx,yy,zz,t
88,xx,yy,zz,abc,009-%5
125
185,xx