shell 按每个月正确减少日期

whlutmcx  于 2023-02-09  发布在  Shell
关注(0)|答案(4)|浏览(130)

我有一个简单的代码,它是工作,但不是预期的。我的代码的主要目的是减少给定日期,直到目标日期2012 - 01 - 31,
但结果是:

2017-10-28
2017-09-28
2017-08-28
2017-07-28
2017-06-28
2017-05-28
2017-04-28
2017-03-28
2017-02-28
2017-01-28
2016-12-28
2016-11-28
2016-10-28
2016-09-28
2016-08-28
2016-07-28
2016-06-28
2016-05-28
2016-04-28
2016-03-28
2016-02-28
2016-01-28
...

代码:

#!/bin/bash

d=2017-10-31
while [ "$d" != 2012-01-31 ]; do 
  echo $d
  d=$(date -I -d "$d -1 month")
done

我真的希望正确的月份到位像:

2017-10-31
2017-09-30
2017-08-31
2017-07-31
2017-06-30
2017-05-31
2017-04-30
2017-03-31
2017-02-28
2017-01-31
2016-12-31
2016-11-30
2016-10-31
2016-09-30
2016-08-31
2016-07-31
2016-06-30
2016-05-31
2016-04-30
2016-03-31
2016-02-29
2016-01-31
...

我怎样才能做到这一点?

vaqhlq81

vaqhlq811#

它更容易生成月初和做一些小技巧,以获得月底没有检查日期

$ d=2017-10-31; bd=$(date -I -d "$d +1 month");   
  while [ $d != 2012-01-31 ];        
  do 
      bd=$(date -I -d "$bd - 1 month");           
      d=$(date -I -d "$bd - 1 day");  
      echo $d;
  done

2017-10-31
2017-09-30
2017-08-31
2017-07-31
...  
2016-07-31
2016-06-30
2016-05-31
2016-04-30
2012-03-31
2012-02-29
2012-01-31
pgky5nke

pgky5nke2#

也许可以减去当前月份中的天数,而不是减去月份(这种行为是众所周知的

!/bin/bash

d=2017-10-31
while [ "$d" != 2012-01-31 ]; do
  echo $d
  days_in_month==$(cal $(date +"%m %Y" -d $d) | awk 'NF {DAYS = $NF}; END {print DAYS}')
  d=$(date -I -d "$d $days_in_month day ago")
done
f3temu5u

f3temu5u3#

假设您的开始日期总是一个月中的最后一天,如果您使用以下算法,则可以让date负责计算每月的天数:

date = date +1 day -1 month -1 day

也就是说,先将日期翻转到下个月的1日,然后减去一个月得到当月的1日,最后减去1日得到上个月的最后一天。
例如:

#!/bin/bash
d=2017-10-31
while [ "$d" != 2012-01-31 ]; do 
    echo $d
    d=$(date -I -d "$(date -I -d "$(date -I -d "$d +1 day") 1 month ago") 1 day ago")
done

注意使用1 day ago代替-1 day,因为后者可以被date解释为时区(已知的陷阱)。
或者,您可以手动将日期设置为01(使用shell的参数扩展来删除后缀${d%-*}),然后用date减去1 day

d=2017-10-31
while [ "$d" != 2012-01-31 ]; do 
    echo $d
    d=$(date -I -d "${d%-*}-01 1 day ago")
done

输出为(在两种情况下):

2017-10-31
2017-09-30
2017-08-31
2017-07-31
2017-06-30
2017-05-31
2017-04-30
...
fiei3ece

fiei3ece4#

另一个类似randomir的答案是使用关系词yesterday代替day ago

d=2017-10-31
while [ "$d" != 2012-01-31 ]; do 
    echo $d
    d=$(date -I -d "${d%-*}-01 yesterday")
done

相关问题