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