您原来的解决方案之所以慢是因为系统调用date。您使用 awk 处理的每条记录/行都会调用一个外部命令来执行日期转换。这样的外部调用需要被加载到内存中,执行并且它的输出需要被awk处理。如果我们可以在 awk 本身中进行实际的日期转换,我们可以加快速度。
一般性评论:当您将日期和时间从 UTC 转换为您当地的时区时,您必须考虑到 1 月 1 日与 8 月 1 日处于不同的时区。这是由于日光-节约时间。下面的算法没有提供解决方案,因为 OP 只是要求转移 4 小时,或者转移到他当前的时区。 (备注: gawk 4.1.2 或更高版本的解决方案将考虑 DST)
下面我介绍了几种解决方案,您可以根据使用的 awk 使用它们:
Gnu awk:gawk 的各种扩展之一是时间函数。这个问题的两个有用的时间函数是mktime和strftime:
mktime(datespec,[utc-flag]):这会将 YYYY MM DD hh mm ss 形式的日期规范字符串 datespec 转换为 Unix 纪元时间,即自 1970 年 1 月 1 日 UTC 以来的总秒数。从 gawk-4.2.1 开始,您可以使用 utc-flag 来指示 datespec 是否为 UTC。在 gawk-4.2.1 之前,它采用本地时区。
strftime(format,timestamp,[utc-flag]):这会将纪元时间timestamp 转换为格式化字符串(与date 命令的格式相同)。您可以使用utc-flag 指示返回的时间应该是UTC 或本地时区。
更多信息在GNU awk manual
我们希望将字段 1 从 UTC 转换为本地时区。由于我们不知道字段1的格式,我们假设存在一个函数convert_time(str),它将str格式化为YYYY MM DD hh mm ss可以被mktime接受的格式:
gawk 4.1.2 或更新版本:
$ awk 'BEGIN{FS=OFS=","}
{ # convert $1 into YYYY MM DD hh mm ss
datestring=convert_time($1)
# convert datestring (as UTC) into epoch
datum=mktime(datestring,1)
# convert epoch into string (local TZ)
datum=strftime("\042%Y%m%d_%H\042",datum)
# print and append
print $0,datum
}' data.txt
在 gawk 4.1.2 之前:这里我们不能使用 utc-flag,所以我们强制 awk 在 UTC 中工作:
$ TZ=UTC awk 'BEGIN{FS=OFS=","}
{ # convert $1 into YYYY MM DD hh mm ss
datestring=convert_time($1)
# convert datestring (as UTC) into epoch
datum=mktime(datestring)
# perform TZ correction
datum-=4*3600;
# convert epoch into string (local TZ)
datum=strftime("\042%Y%m%d_%H\042",datum)
# print and append
print $0,datum
}' data.txt
POSIX awk:如果您没有 GNU awk,但有任何其他 awk,则不能使用这些时间函数,因为它们是 GNU awk 特定的。但是可以实现它们:
awk '
# Algorithm from "Astronomical Algorithms" By J.Meeus
function mktime_posix(datestring, a,t) {
split(datestring,a," ")
if (a[1] < 1970) return -1
if (a[2] <= 2) { a[1]--; a[2]+=12 }
t=int(a[1]/100); t=2-t+int(t/4)
t=int(365.25*a[1]) + int(30.6001*(a[2]+1)) + a[3] + t - 719593
return t*86400 + a[4]*3600 + a[5]*60 + a[6]
}
function strftime_posix(epoch, JD,yyyy,mm,dd,HH,MM,SS,A,B,C,D,E ) {
if (epoch < 0 ) return "0000 00 00 00 00 00.000000"
JD=epoch; SS=JD%60; JD-=SS; JD/=60; MM=JD%60;
JD-=MM; JD/=60; HH=JD%24; JD-=HH; JD/=24;
JD+=2440588
A=int((JD - 1867216.25)/(36524.25))
A=JD+1+A-int(A/4)
B=A+1524; C=int((B-122.1)/365.25); D=int(365.25*C); E=int((B-D)/30.6001)
dd=B-D-int(30.6001*E)
mm = E < 14 ? E-1 : E - 13
yyyy=mm>2?C-4716:C-4715
return sprintf("\042%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%06.3f",yyyy,mm,dd,HH,MM,SS)
}
{ # convert $1 into YYYY MM DD hh mm ss
datestring=convert_time($1)
# convert datestring (as UTC) into epoch
datum=mktime_posix(datestring)
# perform TZ correction
datum-=4*3600;
# convert epoch into string (local TZ)
datum=strftime_posix(datum)
# print and append
print $0,datum
}' data.txt