Как найти разницу в днях между двумя датами? - PullRequest
65 голосов
/ 09 февраля 2011

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

Как найти разницу в днях между двумя датами?

Ответы [ 18 ]

57 голосов
/ 05 августа 2011

Способ bash - конвертируйте даты в формат% y% m% d, а затем вы можете сделать это прямо из командной строки:

echo $(( ($(date --date="031122" +%s) - $(date --date="021020" +%s) )/(60*60*24) ))
25 голосов
/ 09 февраля 2011

Если у вас есть GNU date, это позволяет напечатать представление произвольной даты (опция -d).В этом случае конвертируйте даты в секунды после EPOCH, вычитайте и делите на 24 * 3600.

Или вам нужен переносной способ?

16 голосов
/ 12 марта 2015

Берегись! Многие из решений bash здесь разбиты на диапазоны дат, которые охватывают дату, когда начинается летнее время (где применимо). Это связано с тем, что конструкция $ ((math)) выполняет операцию 'floor' / усечение над полученным значением, возвращая только целое число. Позвольте мне проиллюстрировать:

Летнее время началось 8 марта этого года в США, поэтому давайте использовать диапазон дат, охватывающий:

start_ts=$(date -d "2015-03-05" '+%s')
end_ts=$(date -d "2015-03-11" '+%s')

Давайте посмотрим, что мы получим с двойными скобками:

echo $(( ( end_ts - start_ts )/(60*60*24) ))

Возвращает «5».

Выполнение этого с использованием 'bc' с большей точностью дает нам другой результат:

echo "scale=2; ( $end_ts - $start_ts )/(60*60*24)" | bc

Возвращает «5,95» - пропущенные 0,05 являются потерянным часом после переключения DST.

Так, как это должно быть сделано правильно?
Я бы предложил использовать это вместо:

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

Здесь «printf» округляет более точный результат, вычисленный как «bc», давая нам правильный диапазон дат «6».

Редактировать: выделение ответа в комментарии от @ hank-schultz ниже, которое я использовал в последнее время:

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

Это также должно быть безопасным с високосной секундой, если вы всегда вычитаете более раннюю дату из более поздней, поскольку високосные секунды будут только увеличивать разницу - усечение эффективно округляет до правильного результата.

16 голосов
/ 18 ноября 2011

А в питоне

$python -c "from datetime import date; print (date(2003,11,22)-date(2002,10,20)).days"
398
7 голосов
/ 27 декабря 2012

Вот версия 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))

NJoy!

4 голосов
/ 09 февраля 2011

Даже если у вас нет даты GNU, вероятно, у вас установлен 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";

Это возвращает 398.041666666667 - 398 дней и один час из-за перехода на летнее время.


Вопрос вернулся к моей ленте.Вот более краткий метод, использующий модуль 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
4 голосов
/ 09 февраля 2011

Если опция -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`
3 голосов
/ 09 апреля 2018

Это работает для меня:

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

Печать

398 days

Что происходит?

  1. Укажите правильную строку времени в A и B
  2. Используйте date -d для обработки временных строк
  3. Используйте date %s для преобразования строк времени в секунды с 1970 года (unix epoche)
  4. Используйте расширение параметра bash для вычитания секунд
  5. делите на секунды в день (86400 = 60 * 60 * 24), чтобы получить разницу в днях
  6. ! DST не учитывается! Смотрите этот ответ на unix.stackexchange !
1 голос
/ 10 февраля 2011

Я бы отправил другое возможное решение в Ruby. Похоже, это самый маленький и чистый на сегодняшний день:

A=2003-12-11
B=2002-10-10
DIFF=$(ruby -rdate -e "puts Date.parse('$A') - Date.parse('$B')")
echo $DIFF
1 голос
/ 22 января 2019

Это самое простое, с чем мне удалось поработать над Centos 7:

OLDDATE="2018-12-31"
TODAY=$(date -d $(date +%Y-%m-%d) '+%s')
LINUXDATE=$(date -d "$OLDDATE" '+%s')
DIFFDAYS=$(( ($TODAY - $LINUXDATE) / (60*60*24) ))

echo $DIFFDAYS
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...