如何使用 BASH 脚本的 AWK 生成给定开始和结束日期的日期序列?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4351282/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to generate a sequence of dates given starting and ending dates using AWK of BASH scripts?
提问by Tony
I have a data set with the following format
我有以下格式的数据集
The first and second fields denote the dates (M/D/YYYY) of starting and ending of a study.
第一个和第二个字段表示研究开始和结束的日期 (M/D/YYYY)。
How one expand the data into the desired output format, taking into account the leap years using AWK or BASH scripts?
考虑到闰年使用 AWK 或 BASH 脚本,如何将数据扩展为所需的输出格式?
Your help is very much appreciated.
非常感激你的帮助。
Input
输入
7/2/2009 7/7/2009
2/28/1996 3/3/1996
12/30/2001 1/4/2002
Desired Output
期望输出
7/7/2009
7/6/2009
7/5/2009
7/4/2009
7/3/2009
7/2/2009
3/3/1996
3/2/1996
3/1/1996
2/29/1996
2/28/1996
1/4/2002
1/3/2002
1/2/2002
1/1/2002
12/31/2001
12/30/2001
采纳答案by Paused until further notice.
If you have gawk:
如果你有gawk:
#!/usr/bin/gawk -f
{
split(,s,"/")
split(,e,"/")
st=mktime(s[3] " " s[1] " " s[2] " 0 0 0")
et=mktime(e[3] " " e[1] " " e[2] " 0 0 0")
for (i=et;i>=st;i-=60*60*24) print strftime("%m/%d/%Y",i)
}
Demonstration:
示范:
./daterange.awk inputfile
Output:
输出:
07/07/2009
07/06/2009
07/05/2009
07/04/2009
07/03/2009
07/02/2009
03/03/1996
03/02/1996
03/01/1996
02/29/1996
02/28/1996
01/04/2002
01/03/2002
01/02/2002
01/01/2002
12/31/2001
12/30/2001
Edit:
编辑:
The script above suffers from a naive assumption about the length of days. It's a minor nit, but it could produce unexpected results under some circumstances. At least one other answer here also has that problem. Presumably, the datecommand with subtracting (or adding) a number of days doesn't have this issue.
上面的脚本对天的长度有一个天真的假设。这是一个小问题,但在某些情况下可能会产生意想不到的结果。至少这里的另一个答案也有这个问题。据推测,date减去(或增加)天数的命令没有这个问题。
Some answers require you to know the number of days in advance.
有些答案要求您提前知道天数。
Here's another method which hopefully addresses those concerns:
这是另一种希望解决这些问题的方法:
while read -r d1 d2
do
t1=$(date -d "$d1 12:00 PM" +%s)
t2=$(date -d "$d2 12:00 PM" +%s)
if ((t2 > t1)) # swap times/dates if needed
then
temp_t=$t1; temp_d=$d1
t1=$t2; d1=$d2
t2=$temp_t; d2=$temp_d
fi
t3=$t1
days=0
while ((t3 > t2))
do
read -r -u 3 d3 t3 3<<< "$(date -d "$d1 12:00 PM - $days days" '+%m/%d/%Y %s')"
((++days))
echo "$d3"
done
done < inputfile
回答by Bohdan
It can be done nicely with bash alone:
单独使用 bash 可以很好地完成它:
for i in `seq 1 5`;
do
date -d "2017-12-01 $i days" +%Y-%m-%d;
done;
or with pipes:
或使用管道:
seq 1 5 | xargs -I {} date -d "2017-12-01 {} days" +%Y-%m-%d
回答by camh
You can do this in the shell without awk, assuming you have GNU date (which is needed for the date -d @nnnform, and possibly the ability to strip leading zeros on single digit days and months):
您可以在没有 awk 的情况下在 shell 中执行此操作,假设您有 GNU 日期(date -d @nnn表单需要它,并且可能能够在个位数的日期和月份中去除前导零):
while read start end ; do
for d in $(seq $(date +%s -d $end) -86400 $(date +%s -d $start)) ; do
date +%-m/%-d/%Y -d @$d
done
done
If you are in a locale that does daylight savings, then this can get messed up if requesting a date sequence where a daylight saving switch occurs in between. Use -u to force to UTC, which also strictly observes 86400 seconds per day. Like this:
如果您在执行夏令时的语言环境中,那么如果请求日期序列在两者之间发生夏令时切换,这可能会变得一团糟。使用 -u 强制使用 UTC,它也严格遵守每天 86400 秒。像这样:
while read start end ; do
for d in $(seq $(date -u +%s -d $end) -86400 $(date -u +%s -d $start)) ; do
date -u +%-m/%-d/%Y -d @$d
done
done
Just feed this your input on stdin.
只需在标准输入上输入您的输入即可。
The output for your data is:
您的数据的输出是:
7/7/2009
7/6/2009
7/5/2009
7/4/2009
7/3/2009
7/2/2009
3/3/1996
3/2/1996
3/1/1996
2/29/1996
2/28/1996
1/4/2002
1/3/2002
1/2/2002
1/1/2002
12/31/2001
12/30/2001
回答by Jonathan Leffler
I prefer ISO 8601 format dates - here is a solution using them. You can adapt it easily enough to American format if you wish.
我更喜欢 ISO 8601 格式的日期 - 这是使用它们的解决方案。如果你愿意,你可以很容易地将它改编成美国格式。
AWK Script
AWK 脚本
BEGIN {
days[ 1] = 31; days[ 2] = 28; days[ 3] = 31;
days[ 4] = 30; days[ 5] = 31; days[ 6] = 30;
days[ 7] = 31; days[ 8] = 31; days[ 9] = 30;
days[10] = 31; days[11] = 30; days[12] = 31;
}
function leap(y){
return ((y %4) == 0 && (y % 100 != 0 || y % 400 == 0));
}
function last(m, l, d){
d = days[m] + (m == 2) * l;
return d;
}
function prev_day(date, y, m, d){
y = substr(date, 1, 4)
m = substr(date, 6, 2)
d = substr(date, 9, 2)
#print d "/" m "/" y
if (d+0 == 1 && m+0 == 1){
d = 31; m = 12; y--;
}
else if (d+0 == 1){
m--; d = last(m, leap(y));
}
else
d--
return sprintf("%04d-%02d-%02d", y, m, d);
}
{
d1 = ; d2 = ;
print d2;
while (d2 != d1){
d2 = prev_day(d2);
print d2;
}
}
Call this file: dates.awk
调用这个文件: dates.awk
Data
数据
2009-07-02 2009-07-07
1996-02-28 1996-03-03
2001-12-30 2002-01-04
Call this file: dates.txt
调用这个文件: dates.txt
Results
结果
Command executed:
执行的命令:
awk -f dates.awk dates.txt
Output:
输出:
2009-07-07
2009-07-06
2009-07-05
2009-07-04
2009-07-03
2009-07-02
1996-03-03
1996-03-02
1996-03-01
1996-02-29
1996-02-28
2002-01-04
2002-01-03
2002-01-02
2002-01-01
2001-12-31
2001-12-30
回答by nisetama
Another option is to use dateseq from dateutils (http://www.fresse.org/dateutils/#dateseq). -ichanges the input format and -fchanges the output format. -1must be specified as an increment when the first date is later than the second date.
另一种选择是使用 dateutils ( http://www.fresse.org/dateutils/#dateseq) 中的dateseq 。-i更改输入格式并-f更改输出格式。-1当第一个日期晚于第二个日期时,必须指定为增量。
$ dateseq -i %m/%d/%Y -f %m/%d/%Y 7/7/2009 -1 7/2/2009
07/07/2009
07/06/2009
07/05/2009
07/04/2009
07/03/2009
07/02/2009
$ dateseq 2017-04-01 2017-04-05
2017-04-01
2017-04-02
2017-04-03
2017-04-04
2017-04-05

