17

我们知道,每年每个月的最大天数如下:

Jan - 31 days
Feb - 28 days / 29 days (leap year)
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days

如何让 bash 在不使用if elseorswitchwhile循环的情况下返回当前年份的值(每个月的最后一天)?

4

11 回答 11

48

我的看法:

for m in {1..12}; do
  date -d "$m/1 + 1 month - 1 day" "+%b - %d days"; 
done

解释一下:对于第一次迭代,当 m=1 时,-d参数是“1/1 + 1 个月 - 1 天”,“1/1”被解释为 1 月 1 日。所以 1 月 1 日 + 1 个月 - 1 天是 1 月 31 日。下一次迭代“2/1”是 2 月 1 日,加上一个月减去一天得到 2 月 28 日或 29 日。依此类推。

于 2012-09-12T10:42:38.477 回答
16
cat <<EOF
Jan - 31 days
Feb - `date -d "yesterday 3/1" +"%d"` days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
EOF
于 2012-09-12T05:27:33.073 回答
7

假设您允许“for”,那么 bash 中的以下内容

for m in {1..12}; do
    echo $(date -d $m/1/1 +%b) - $(date -d "$(($m%12+1))/1 - 1 days" +%d) days
done

产生这个

 Jan - 31 days
 Feb - 29 days
 Mar - 31 days
 Apr - 30 days
 May - 31 days
 Jun - 30 days
 Jul - 31 days
 Aug - 31 days
 Sep - 30 days
 Oct - 31 days
 Nov - 30 days
 Dec - 31 days

注意:我删除了对cal

对于那些喜欢琐事的人:

Number months from 1 to 12 and look at the binary representation in four
bits {b3,b2,b1,b0}.  A month has 31 days if and only if b3 differs from b0.
All other months have 30 days except for February.

因此,除了 2 月,此方法有效:

for m in {1..12}; do
    echo $(date -d $m/1/1 +%b) - $((30+($m>>3^$m&1))) days
done

结果:

Jan - 31 days
Feb - 30 days (wrong)
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days
于 2012-09-12T05:20:36.213 回答
7
cal $(date +"%m %Y") |
awk 'NF {DAYS = $NF}; END {print DAYS}'

这使用标准cal实用程序来显示指定的月份,然后运行一个简单的 Awk 脚本来仅提取最后一天的数字。

于 2016-04-08T21:45:14.480 回答
3

返回该月中的天数,以补偿闰年二月的变化,而不使用循环或使用 if 语句,并且只调用 date 一次。

此代码测试日期以查看请求年份的 2 月 29 日是否有效,如果有效,则更新日期偏移字符串中的第二个字符。month 参数选择相应的子字符串并将月差添加到 28。

function daysin()
{
   s="303232332323"                                        # normal year
   date -d "2/29/$2" > /dev/null 2>&1 && s="313232332323"  # leap year
   echo $[ ${s:$[$1-1]:1} + 28 ]
}

daysin $1 $2                                               #daysin [1-12] [YYYY]
于 2016-01-08T00:58:46.077 回答
3

尝试使用此代码

date -d "-$(date +%d) days  month" +%Y-%m-%d
于 2017-03-04T10:56:36.827 回答
2

在具有BSD 日期功能的 Mac 上,您可以执行以下操作:

for i in {2..12}; do date -v1d -v"$i"m -v-1d "+%d"; done

快速说明

-v代表调整。我们将日期调整为:

-v1d代表该月的第一天

-v"$i"m定义月份,例如(-v2m对于二月)

-v-1d减去一天(所以我们得到上个月的最后一天)

"+%d"打印月份中的哪一天

for i in {2..12}; do date -v1d -v"$i"m -v-1d "+%d"; done
31
28
31
30
31
30
31
31
30
31
30

您当然可以添加年份。请参阅手册页中的示例(上面的链接)。

于 2017-07-16T07:04:36.093 回答
1

内容script.sh

#!/bin/bash
begin="-$(date +'%-m') + 2"
end="10+$begin"

for ((i=$begin; i<=$end; i++)); do
    echo $(date -d "$i month -$(date +%d) days" | awk '{ printf "%s - %s days", $2, $3 }')
done

结果:

Jan - 31 days
Feb - 29 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
于 2012-09-12T06:08:52.320 回答
0
for m in $(seq 1 12); do cal  $(date +"$m %Y") | grep -v "^$" |tail -1|grep -o "..$"; done
  • 从 1 到 12 迭代(对于...)
  • 打印每个月的日历表(cal...)
  • 从输出中删除空行(grep -v ...)
  • 打印表格中的最后一个数字(尾部...)

没有意义,避免使用cal,因为是POSIX要求的,所以应该有

于 2016-07-04T11:46:07.163 回答
0

已接受答案的变体以显示“昨天”的使用

$ for m in {1..12}; do date -d "yesterday $m/1 + 1 month" "+%b - %d days"; done
Jan - 31 days
Feb - 28 days
Mar - 31 days
Apr - 30 days
May - 31 days
Jun - 30 days
Jul - 31 days
Aug - 31 days
Sep - 30 days
Oct - 31 days
Nov - 30 days
Dec - 31 days

这个怎么运作?

在添加 1 个月后显示日期“月/1”的昨天日期

于 2018-08-09T03:58:40.850 回答
0

我需要这个几次,所以当 PHP 中带有简单的 bash 时不是,所以我使用它直到抛出错误“无效的算术运算符”,甚至在拼写检查中出现冲突(“mt”代表月份,“yr”代表年份)

last=$(echo $(cal ${mt} ${yr}) | awk '{print $NF}')

所以这很好用......

### get last day of month
#
# implement from PHP
# src: https://www.php.net/manual/en/function.cal-days-in-month.php
#
if [ $mt -eq 2 ];then
    if [[ $(bc <<< "${yr} % 4") -gt 0 ]];then
        last=28
    else
        if [[ $(bc <<< "${yr} % 100") -gt 0 ]];then
            last=29
        else
            [[ $(bc <<< "${yr} % 400") -gt 0 ]] && last=28 || last=29
        fi
    fi
else
    [[ $(bc <<< "(${mt}-1) % 7 % 2") -gt 0 ]] && last=30 || last=31
fi
于 2021-07-31T11:00:42.803 回答