我正在linux中使用awk命令将utc转换为本地时间,但是文件大小很大(> 30 gb),并且将花费一个多小时。
这是我的代码:
awk -F"," '{cmd="date -d \"$(date -d \""$1"\")-4hours\" \"+%Y%m%d_%H\"";cmd | getline datum; close(cmd); print $0 ","datum""}' data.txt
如何加快此命令的速度,或者有没有简单的方法可以在Linux中进行此转换?
Here is the sample of input:
utc,id
2018-03-31 16:00:49.425,4485
2018-04-1 17:01:19.425,30019
2018-05-31 18:01:49.425,15427
2018-08-20 19:01:55.425,17579
2018-09-2 20:02:31.425,23716
2018-10-15 21:03:34.425,24772
expected output:
utc,id,localtime
2018-03-31 16:00:49.425,4485,20180331_12
2018-04-1 17:01:19.425,30019,20180401_13
2018-05-31 18:01:49.425,15427,20180531_14
2018-08-20 19:01:55.425,17579,20180820_15
2018-09-2 20:02:31.425,23716,20180902_16
2018-10-15 21:03:34.425,24772,20181015_17
答案 0 :(得分:5)
您的原始解决方案运行缓慢的原因是由于系统调用了date
。用awk处理的每个记录/行都调用一个外部命令来执行日期转换。此类外部调用需要加载到内存中,然后执行,其输出需要由awk处理。如果我们可以在awk本身中进行实际的日期转换,则可以加快速度。
一般性评论:当您将日期和时间从UTC转换为本地时区时,必须考虑到1月1日所在的时区与8月1日所在的时区不同。这是由于白天-节约时间。下面的算法无法提供解决方案,因为OP刚刚要求将班次更改为4h或更改为当前时区。 (备注:适用于gawk 4.1.2或更高版本的解决方案将考虑DST)
下面,我将根据您使用的awk提出几种解决方案:
Gnu awk: gawk
的各种扩展之一是时间函数。此问题的两个有用的时间函数是mktime
和strftime
:
中的更多信息
mktime(datespec,[utc-flag])
:将日期格式为datespec
的字符串YYYY MM DD hh mm ss
转换为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或当地时区。
我们要将字段1从UTC转换为本地时区。由于我们不知道字段1的格式,因此我们假设存在函数convert_time(str)
,该函数将str
格式化为YYYY MM DD hh mm ss
可以接受的格式mktime
:< / p>
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\-42",yyyy,mm,dd,HH)
}
{ # 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