Awk 如何在合并的日期和时间中添加1小时

Awk 如何在合并的日期和时间中添加1小时,awk,Awk,我有一个逗号分隔的输入文件,有7列,其中: 第3列是yyyymmdd格式的日期 第4列是格式为HHMMSS的时间。 我想通过在合并日期-时间格式中添加一小时来更新这两列。这意味着: 如果HH=23,则在我们移动到第二天时更新这两列。 下面是我的一次尝试,包括输入和预期输出 评论:正如在下面的评论中指出的,我没有访问GNU awk的权限。所以我的尝试失败了,因为我使用了时间函数strftime 预期产出: 使用系统命令将1天添加到第3列 awk ' BEGIN { FS=OFS="," } {

我有一个逗号分隔的输入文件,有7列,其中:

第3列是yyyymmdd格式的日期 第4列是格式为HHMMSS的时间。 我想通过在合并日期-时间格式中添加一小时来更新这两列。这意味着:

如果HH<23,只更新第四列 如果HH>=23,则在我们移动到第二天时更新这两列。 下面是我的一次尝试,包括输入和预期输出

评论:正如在下面的评论中指出的,我没有访问GNU awk的权限。所以我的尝试失败了,因为我使用了时间函数strftime

预期产出:


使用系统命令将1天添加到第3列

awk '
BEGIN { FS=OFS="," }
{
    if($4<230000)
        $4=sprintf("%06d",$4+10000)
    else {
         $4=sprintf("%06d",$4-230000)
         date="$( date -d '19500101')";
         #print strftime("%Y%m%d",$3);
         #$3+=86400


         # # GNU date
         # $3 = strftime("%Y%m%d", (24*3600)+mktime(substr($3,1,4)" "substr($3,5,2)" "substr($3,7)" 00 00 00"))

         # BSD date
         $3=((sprintf("date -j -v+1d -f \"%%Y%%m%%d\" %s \"+%%Y%%m%%d\"", $3) | getline line) > 0 ? line: "INVALID DATE" )
    }
    print
 }' Test.txt
更新

不再使用日期命令。结合@ExpertNoob1的答案

awk '
BEGIN { FS=OFS="," }
{
    if($4<230000)
        $4=sprintf("%06d",$4+10000)
    else {
         $4=sprintf("%06d",$4-230000)
         date="$( date -d '19500101')";
         #print strftime("%Y%m%d",$3);
         #$3+=86400
         $3 = strftime("%Y%m%d", (24*3600)+mktime(substr($3,1,4)" "substr($3,5,2)" "substr($3,7)" 00 00 00"))
    }
    print
 }' Test.txt

如果没有可用的GNU awk扩展,我想这可能是您真正想要的

#!/usr/bin/awk -f

BEGIN {
  OFS=FS=","
  split("31 28 31 30 31 30 31 31 30 31 30 31", days, " ")
}

{
  # Add one hour to the current time
  $4=sprintf("%06d", $4 + 10000 )

  # Is this a leap year?
  year=substr($3,1,4)
  if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
    days[2]=29
  } else {
    days[2]=28
  }
}

# too many hours
$4 >= 240000 {
  $3=$3 + int($4/240000)           # add days for sets of 24 hours
  $4=sprintf("%06d", $4 % 24000 )  # reduce time to < 24 hours

  # too many days
  if (substr($3,7,2) > days[substr($3,5,2)+0]) {
    $3=sprintf( "%04d%02d%02d", substr($3,1,4), substr($3,5,2)+1, substr($3,7,2)-days[substr($3,5,2)+0] )

    # too many months
    if (substr($3,5,2) > 12) {
      $3=sprintf( "%04d%02d%02d", substr($3,1,4)+1, substr($3,5,2)-12, substr($3,7,2) )
    }
  }
}

# print the line
1
这将逐步解决从最小单位到最大单位的重大超支问题。它显然可以被压缩一点;事情分散开来供评论

如果我们有太多的小时,我们将它们作为天添加到日期的一部分。 如果当前月份的天数过多,则增加该月的天数。 如果一年有太多的月份,我们会增加一年。 似乎在处理你的数据。以及几闰年前后的日期+时间。我没有进一步测试它


请注意,它没有考虑DST转换或闰秒。

看起来我没有仔细阅读您的情况。正如一些人有益地指出的,这是使用GNU awk的替代解决方案

  #!/usr/bin/awk -f

    BEGIN { FS=OFS="," }
    {
        if($4<230000)
            $4=sprintf("%06d",$4+10000)
        else
           {
             $4=sprintf("%06d",$4-230000)
             year=substr($3, 1,4)
             month=substr($3, 5,2)
             day=substr($3, 7,2)
             dstr=year " " month " " day " 00 00 00"
             dstamp=mktime(dstr)
             dstamp+=86400
             $3=strftime("%Y%m%d",dstamp)
            }
            print
     }

您能否澄清4美元是什么,以及您的代码应该如何使用它?这是一天中的一段时间,还是一段持续时间?时区或夏令时是一个问题吗?请注意使用并避免迄今为止的shell调用。使用mktime将所有内容转换为秒。按要求执行操作添加86400秒以添加一天,并使用strftime将秒转换回一天。另外,strftime需要秒,而不是日期格式YYYYMMDD,因此您将收到错误的日期/时间。@Sameer,请提供有关$3的信息它是否表示YYYYMMDD,$4它是否表示hhmms,输出部分是否表示预期的输出,如果是,您希望如何获得它。我问这个问题的原因是,当前代码添加了各种打印语句,我在您的输出中没有看到这些语句。@Sameer您没有使用GNU awk,并且应该切换到POSIX,因为它给出了错误的结果,如果我有类似20180930的日期,它将返回20180931,但我想要20181001没有问题,我得到的日期:未识别标志:-用法:日期[-u][+字段描述符]此error@Sameer您正在使用哪个版本的date命令?能否运行date-version进行确认?我们应该看到第一行,如date GNU coreutilsdate-u Mon Sep 17 14:39:48 GMT 2018 date-版本不是工作日期-版本日期:未识别标志:-用法:日期[-u][+字段描述符]我不明白为什么这被认为是有效的解决方案,因为它不可能是。它利用了gnu awk和gnu core-utils。这利用了mktime,因此是gnu awk,OP没有访问gnu工具的权限。否则是一个好的解决方案!函数mktime在POSIX awk中也不可用。我喜欢你的假设,即此脚本仍然可以使用在2100年。@kvantour,你永远不会知道,是吗
brew install coreutils
awk '
BEGIN { FS=OFS="," }
{
    if($4<230000)
        $4=sprintf("%06d",$4+10000)
    else {
         $4=sprintf("%06d",$4-230000)
         date="$( date -d '19500101')";
         #print strftime("%Y%m%d",$3);
         #$3+=86400
         $3 = strftime("%Y%m%d", (24*3600)+mktime(substr($3,1,4)" "substr($3,5,2)" "substr($3,7)" 00 00 00"))
    }
    print
 }' Test.txt
$3 = strftime("%Y%m%d", (24*3600)+mktime(substr($3,1,4)" "substr($3,5,2)" "substr($3,7)" 00 00 00"))
#!/usr/bin/awk -f

BEGIN {
  OFS=FS=","
  split("31 28 31 30 31 30 31 31 30 31 30 31", days, " ")
}

{
  # Add one hour to the current time
  $4=sprintf("%06d", $4 + 10000 )

  # Is this a leap year?
  year=substr($3,1,4)
  if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
    days[2]=29
  } else {
    days[2]=28
  }
}

# too many hours
$4 >= 240000 {
  $3=$3 + int($4/240000)           # add days for sets of 24 hours
  $4=sprintf("%06d", $4 % 24000 )  # reduce time to < 24 hours

  # too many days
  if (substr($3,7,2) > days[substr($3,5,2)+0]) {
    $3=sprintf( "%04d%02d%02d", substr($3,1,4), substr($3,5,2)+1, substr($3,7,2)-days[substr($3,5,2)+0] )

    # too many months
    if (substr($3,5,2) > 12) {
      $3=sprintf( "%04d%02d%02d", substr($3,1,4)+1, substr($3,5,2)-12, substr($3,7,2) )
    }
  }
}

# print the line
1
  #!/usr/bin/awk -f

    BEGIN { FS=OFS="," }
    {
        if($4<230000)
            $4=sprintf("%06d",$4+10000)
        else
           {
             $4=sprintf("%06d",$4-230000)
             year=substr($3, 1,4)
             month=substr($3, 5,2)
             day=substr($3, 7,2)
             dstr=year " " month " " day " 00 00 00"
             dstamp=mktime(dstr)
             dstamp+=86400
             $3=strftime("%Y%m%d",dstamp)
            }
            print
     }
1039,1018,20180915,010000,0,0,A
1039,1018,20180915,020000,0,0,A
1039,1018,20180915,030000,0,0,A
1039,1018,20180915,040000,0,0,A
1039,1018,20180916,010000,0,0,A