我有一个大约有10MM记录的文件。这是我的dateSample src文件:
0000000566 2017/01/01 0
0000000055 2017/01/01 0
0000000109 2017/01/01 1
0000000940 2017/01/01 0
0000000566 2017/01/01 1
0000000055 2017/01/01 1
0000000109 2017/01/01 2
我基本上需要减去日期中月份的最后一个整数值,并打印没有整数的新值,因此:
0000000566 2017/01/01
0000000055 2017/01/01
0000000109 2016/12/01
0000000940 2017/01/01
0000000566 2016/12/01
0000000055 2016/12/01
0000000109 2016/11/01
我一直遇到日期问题(或测试时在macOS上使用gdate)并且在过去几天一直在徒劳地搜索。
它要么加前缀0,要么删除m和d值:
awk '{ print (gdate -d $2 +"%Y/%m/%d") }' <$src
或以零为后缀并减去年份中的整数:
awk '{ print (gdate -d $2 +-$3 months +"%Y/%m/%d") }' <$src
或将整个东西混合在一起仍然是不正确的:
awk '{ print gdate -d (gdate -d $2 +"%Y/%m/%d") +-$3 months +"%Y/%m/%d" }' <$src
我发现了以下优秀的回复: Increment date with AWK for few days and months 这正是我想要的,但它运行得非常慢,我假设是因为命令中的命令。
这是当前的awk(我正在使用gdate,因为我现在正在运行macOS BSD):
awk '{ cmd=" gdate -d \"$(gdate -d \""$2"\")+\"-"$3"\"months\" \"+%Y/%m/%d\" ";
cmd | getline fmtDate; close(cmd);
print $1, fmtDate
}' <$src
所以我基本上需要以高效的方式输出
提前感谢任何指导/重写。
干杯
答案 0 :(得分:2)
如果您的awk
支持time functions mktime
和strftime
(这是GNU扩展程序),您可以这样做:
awk -F'[ /]' '{print $1 " " strftime("%Y/%m/%d", mktime($2" "($3-$5)" "$4" 0 0 0"))}' file
首先,我们将日期转换为Unix时间戳。 mktime
仅以"YYYY MM DD HH MM SS"
格式接受日期,这就是我们需要手动构建日期的原因。但它会自动执行规范化,并且会很快将"2017 -1 1 0 0 0"
转换为与"2016 11 1 0 0 0"
相同的时间戳。
之后我们只需要将时间戳转换为&#34; y / m / d&#34;格式并打印出来。
或者,您可以手动执行日期算术&#34;&#34;在简单的情况下,不需要日期标准化 - 如果该月的日期总是<= 28
。 (对于28
以上的日期,如31
,您还需要在下面的脚本中添加剪辑/限制或溢出,但是您必须照顾闰年等。)< / p>
#!/usr/bin/awk -f
BEGIN {
FS = "[ /]";
}
{
mm = $2 * 12 + ($3 - 1) - $5;
y = int(mm / 12);
m = mm % 12 + 1;
d = $4;
printf("%s %04d/%02d/%02d\n", $1, y, m, d);
}
所以,这个想法很简单。我们将空格和斜线分开,因此我们可以将年/月转换为总月数(12 * y + m
)。然后我们从最后一列中减去月份,并通过divmod
操作将总月数转换回年/月。
输出:
$ ./script.awk file
0000000566 2017/01/01
0000000055 2017/01/01
0000000109 2016/12/01
0000000940 2017/01/01
0000000566 2016/12/01
0000000055 2016/12/01
0000000109 2016/11/01
答案 1 :(得分:1)
由于您正在操作日期,因此最好在shell中执行此操作:
while read -r str date n; do
echo "$str $(date -d "$(date -d $date) -$n months" '+%Y/%m/%d')"
done < file
0000000566 2017/01/01
0000000055 2017/01/01
0000000109 2016/12/01
0000000940 2017/01/01
0000000566 2016/12/01
0000000055 2016/12/01
0000000109 2016/11/01
答案 2 :(得分:1)
尝试一种更简单的方法来解决这个问题。
awk 'BEGIN{
split("01,02,03,04,05,06,07,08,09,10,11,12", month,",")
}
{
split($2, array,"/");
if(array[2]<=$3){
array[2]=array[2]+12-$3;
array[1]=array[1]-1
}
else{
array[2]-$3
};
print $1,array[1]"/"array[2]"/"array[3]
}
' Input_file