如何找到两个日期之间的天数差异?

Tre*_*ree 71 bash shell date

A ="2002-20-10"
B ="2003-22-11"

如何找到两个日期之间的天数差异?

tec*_*ker 57

bash方式 - 将日期转换为%y%m%d格式,然后您可以直接从命令行执行此操作:

echo $(( ($(date --date="031122" +%s) - $(date --date="021020" +%s) )/(60*60*24) ))
Run Code Online (Sandbox Code Playgroud)

  • 这不一定需要日期为'%y%m%d`格式.例如,gnu date将接受OP使用的'%Y-%m-%d`格式.一般来说,ISO-8601是一个不错的选择(OP的格式是一种这样的格式).最好避免使用2位数年份的格式. (9认同)
  • 对于今天**的差异,人们可能喜欢使用`days_diff = $(((\`date -d $ B +%s \` - \`date -d"00:00"+%s \` )/(24*3600)))`.请注意`$ days_diff`将是一个整数(即没有小数) (2认同)
  • 为了避免混淆:OP 的格式**不是** `%Y-%m-%d`,直到我们引入 `August 2.0` 和 `October 2.0` OP 的格式是 `%Y-%d-%m`。相关xkcd:https://xkcd.com/1179/ (2认同)

小智 29

如果你有GNU date,它允许打印任意日期(-d选项)的表示.在这种情况下,将日期转换为自EPOCH以来的秒数,减去并除以24*3600.

或者你需要一种便携式的方式?

  • 为了lazyweb的缘故,我认为这就是user332325的意思:```echo'(`date -d $ B +%s` - `date -d $ A +%s`)/(24*3600)"| bc -l``` (11认同)
  • 在这种情况下,可移植性是什么意思? (2认同)

Fre*_*ent 17

而在python中

$python -c "from datetime import date; print (date(2003,11,22)-date(2002,10,20)).days"
398
Run Code Online (Sandbox Code Playgroud)

  • @Anubis OP指定的标签为`bash`和`shell`,所以我认为我们可以假设我们正在谈论一个*nix系统.在这样的系统中,`echo`和`date`可靠地存在,但python不是. (5认同)
  • @mc0e 在这种情况下,没有什么总是存在的 (3认同)
  • @mouviciel并非如此。Python并不总是存在。 (2认同)
  • @ mc0e是的,这很有意义。尽管python2在大多数* nix系统中都可用,但是对于低端设备(嵌入式等),我们将只能依靠主要工具生存。 (2认同)

eva*_*n_b 17

小心!这里的许多bash解决方案都被打破了日期范围,这些日期范围跨越了夏令时开始的日期(如果适用).这是因为$((math))构造对结果值执行'floor'/ truncation操作,仅返回整数.让我说明一下:

DST于今年3月8日在美国开始,所以我们使用的日期范围包括:

start_ts=$(date -d "2015-03-05" '+%s')
end_ts=$(date -d "2015-03-11" '+%s')
Run Code Online (Sandbox Code Playgroud)

让我们看看我们用双括号得到的东西:

echo $(( ( end_ts - start_ts )/(60*60*24) ))
Run Code Online (Sandbox Code Playgroud)

返回'5'.

使用'bc'更精确地执行此操作会给我们带来不同的结果:

echo "scale=2; ( $end_ts - $start_ts )/(60*60*24)" | bc
Run Code Online (Sandbox Code Playgroud)

返回'5.95' - 缺少的0.05是DST切换时的丢失小时数.

那么应该如何正确完成呢?
我建议改用:

printf "%.0f" $(echo "scale=2; ( $end_ts - $start_ts )/(60*60*24)" | bc)
Run Code Online (Sandbox Code Playgroud)

在这里,'printf'舍入'bc'计算的更准确的结果,给我们正确的日期范围'6'.

编辑:在下面的@ hank-schultz的评论中突出显示答案,我最近一直在使用它:

date_diff=$(( ($(date -d "2015-03-11 UTC" +%s) - $(date -d "2015-03-05 UTC" +%s) )/(60*60*24) ))
Run Code Online (Sandbox Code Playgroud)

只要您总是从后一个日期中减去较早的日期,这也应该是闰秒安全,因为闰秒只会增加差异 - 截断有效地向下舍入到正确的结果.

  • 相反,如果你指定开始和结束的时区(并确保它们是相同的),那么你也不再有这个问题,如:`echo $((($(date --date =" 2015-03-11 UTC"+%s) - $(date --date ="2015-03-05 UTC"+%s))/(60*60*24)))`,返回6,而不是5. (4认同)

jsc*_*sse 14

这对我有用:

A="2002-10-20"
B="2003-11-22"
echo $(( ($(date -d $B +%s) - $(date -d $A +%s)) / 86400 )) days
Run Code Online (Sandbox Code Playgroud)

印刷

398 days
Run Code Online (Sandbox Code Playgroud)

怎么了?

  1. AB 中提供有效的时间字符串
  2. 使用date -d处理时间字符串
  3. 使用date %s时间转换字符串秒自1970年以来(UNIX悬搁)
  4. 使用bash参数扩展减去秒
  5. 除以每天的秒数 (86400=60*60*24) 得到天数的差异
  6. !不考虑夏令时!在unix.stackexchange看到这个答案!


Ruc*_*chi 7

如果选项 -d 在您的系统中有效,这是另一种方法。有一个警告,它不会考虑闰年,因为我已经考虑了每年 365 天。

date1yrs=`date -d "20100209" +%Y`
date1days=`date -d "20100209" +%j`
date2yrs=`date +%Y`
date2days=`date +%j`
diffyr=`expr $date2yrs - $date1yrs`
diffyr2days=`expr $diffyr \* 365`
diffdays=`expr $date2days - $date1days`
echo `expr $diffyr2days + $diffdays`
Run Code Online (Sandbox Code Playgroud)


nic*_*kl- 7

为方便起见,这是MAC OS X版本.

$ A="2002-20-10"; B="2003-22-11";
$ echo $(((`date -jf %Y-%d-%m $B +%s` - `date -jf %Y-%d-%m $A +%s`)/86400))
Run Code Online (Sandbox Code Playgroud)

的nJoy!


gle*_*man 5

即使您没有 GNU date,您也可能安装了 Perl:

use Time::Local;
sub to_epoch {
  my ($t) = @_; 
  my ($y, $d, $m) = ($t =~ /(\d{4})-(\d{2})-(\d{2})/);
  return timelocal(0, 0, 0, $d+0, $m-1, $y-1900);
}
sub diff_days {
  my ($t1, $t2) = @_; 
  return (abs(to_epoch($t2) - to_epoch($t1))) / 86400;
}
print diff_days("2002-20-10", "2003-22-11"), "\n";
Run Code Online (Sandbox Code Playgroud)

398.041666666667由于夏令时,这将返回398 天零 1 小时。


这个问题又出现在我的提要上。这是使用 Perl 捆绑模块的更简洁的方法

days=$(perl -MDateTime -le '
    sub parse_date { 
        @f = split /-/, shift;
        return DateTime->new(year=>$f[0], month=>$f[2], day=>$f[1]); 
    }
    print parse_date(shift)->delta_days(parse_date(shift))->in_units("days");
' $A $B)
echo $days   # => 398
Run Code Online (Sandbox Code Playgroud)