自固定日期起计算天数的脚本

时间:2014-08-25 22:14:07

标签: shell date

我需要的是一个脚本(最好是shell),它计算自固定日期以来经过的天数 - 比如2014年8月16日。

我认为可以使用

 date +%j

命令,自8月16日起减去229是今年的229天。 然而,1月1日这个剧本将变得毫无用处......

我完全迷失了,因为我不知道脚本编写的第一件事,但我认为有人可能会帮忙。

4 个答案:

答案 0 :(得分:1)

如果你有GNU date且你的固定日期是2014-08-16,你可以使用:

$ old=$(date +'%s' -d '2014-08-16')
$ new=$(date +'%s')
$ echo $(( ($new - $old) / 86400 ))
9
$

Qualcunocomment中指出并非所有日子都有86400秒。

这是正确的;大多数日子有86400秒,但有些有90000秒,有些有82800秒(当你因为夏令时和标准时间之间的切换而获得或减少一小时)。漫长的日子不会引起问题;短的那些。我更喜欢提供日期(以天为单位)'计算而不是时间(以秒为单位)'计算这些,但我不知道这样做的标准Unix实用程序。

但是,我们可以强制date来处理它,方法是确保较早的日期与午夜一起作为(隐含)时间,而较晚的日期在午夜之后至少一小时使用明确的时间。除了极少数例外情况(例如几年前一个国家跨越国际日期变更线 - 而且我不会尝试处理它!),最多只有一个小时的净时区切换两个约会。假设两个日期相隔三年。中间两年,从标准时间切换到切换,净结果为零;最重要的是一个开关。这会导致命令看起来像这样:

#!/bin/bash
#
# Calculate days between two dates using GNU date command
# Allow for time zone switches

arg0=$(basename "$0" .sh)
DATE=/usr/gnu/bin/date

case $# in
1)  old="$1"; new=$($DATE +"%Y-%m-%d");;
2)  old="$1"; new="$2";;
*)  echo "Usage: $arg0 old [new]" >&2; exit 1;;
esac

case "$old" in
[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]) : OK;;
*) echo "$arg0: $old does not match YYYY-mm-dd" >&2; exit 1;;
esac

case "$new" in
[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]) : OK;;
*) echo "$arg0: $new does not match YYYY-mm-dd" >&2; exit 1;;
esac

if [[ "$old" > "$new" ]]
then t="$old"; old="$new"; new="$t"
fi

# Faulty
old_secs=$($DATE +'%s' -d "$old")
new_secs=$($DATE +'%s' -d "$new")
echo $(( ($new_secs - $old_secs) / 86400 ))

# Safe
old_secs=$($DATE +'%s' -d "$old")
new_secs=$($DATE +'%s' -d "$new 12:00:00")
echo $(( ($new_secs - $old_secs) / 86400 ))

示例输出(显示差异):

$ bash delta-days.sh 2014-03-01 2014-03-31
29
30
$ bash delta-days.sh 2000-03-01 2014-03-31
5142
5143
$ bash delta-days.sh 2014-03-01 2000-03-31
5083
5083
$

答案 1 :(得分:0)

在bash shell中:

then=$(date -j -f "%Y-%m-%d" "2014-8-16" +%s)
now=$(date +%s)
echo $(($now/86400-$then/86400))

date命令中,选项j表示您要显示指定的日期(而不是尝试将系统日期设置为它);选项f是输入日期的格式,“+”选项是输出日期的格式。格式%s是当前纪元的秒数​​,即自1970/1/1 00:00 UTC以来。

答案 2 :(得分:0)

如果您只使用年份和年份数字,则可以使用此公式计算日序列号:

number = (year-1)/4*(4*365+1) + (year-1)%4*365 + day   # integer arithmetic

在像这样的shell脚本中使用(与去年相比):

$ year=$(date +%Y)
$ day=$(date +%j)
$ now=$((($year-1)/4*1461+($year-1)%4*365+day))
$ then=$(((2013-1)/4*1461+(2013-1)%4*365+230))
$ echo $then $now
735113 735485
$ echo $(($now-$then))
372

这个公式只知道常见的闰年(每四年一次),而不是像1900年,2100年,2200年这样没有飞跃的年份。也就是说,它可能是2100年开始的休假日。

答案 3 :(得分:0)

对于perl(从CPAN安装),有一个非常完整的DateTime模块,可以满足您的目的:

perl -MDateTime  -E '
  $base = DateTime->new(year=>2014, month=>8, day=>16); 
  $now = DateTime->today; 
  $next_year = DateTime->new(year=>2015, month=>8, day=>16); 
  say $base->delta_days($now)->in_units("days");
  say $base->delta_days($next_year)->in_units("days");
'
10
365