A = "2002-20-10"
B = "2003-22-11"
Как найти разницу в днях между двумя датами?
A = "2002-20-10"
B = "2003-22-11"
Как найти разницу в днях между двумя датами?
Если у вас есть GNU date
, он позволяет печатать представление произвольной даты (-d
).
В этом случае преобразуйте даты в секундах с EPOCH, вычтите и разделите на 24 * 3600.
Или вам нужен переносимый способ?
Способ bash - преобразовать даты в формат% y% m% d, а затем вы можете сделать это прямо из командной строки:
echo $(( ($(date --date="031122" +%s) - $(date --date="021020" +%s) )/(60*60*24) ))
И в python
$python -c "from datetime import date; print (date(2003,11,22)-date(2002,10,20)).days"
398
Остерегайтесь! Многие из решений bash здесь нарушены для диапазонов дат, которые охватывают дату начала летнего времени (где это применимо). Это связано с тем, что конструкция $((math)) выполняет операцию "floor" /truncation по полученному значению, возвращая только целое число. Позвольте мне проиллюстрировать:
DST начался 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) ))
Это также должно быть безопасным вторым шагом при условии, что вы всегда вычитаете более раннюю дату из более поздней, поскольку секунды прыжка будут только добавлять к разнице - усечение эффективно округляется до правильного результата.
Здесь версия 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!
Если опция -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`
Даже если у вас нет даты 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
Это работает для меня:
A="2002-10-20"
B="2003-11-22"
echo $(( ($(date -d $B +%s) - $(date -d $A +%s)) / 86400 )) days
Печать
398 days
Что происходит?
date -d
для обработки временных строкdate %s
для преобразования временных строк в секунды с 1970 года (unix epoche)Я бы представил другое возможное решение в Ruby. Похоже, это самый маленький и самый красивый из них:
A=2003-12-11
B=2002-10-10
DIFF=$(ruby -rdate -e "puts Date.parse('$A') - Date.parse('$B')")
echo $DIFF
на unix вы должны установить даты GNU. вам не нужно отклоняться от bash. вот зачеркнутое решение, рассматривающее дни, просто чтобы показать шаги. он может быть упрощен и расширен до полных дат.
DATE=$(echo `date`)
DATENOW=$(echo `date -d "$DATE" +%j`)
DATECOMING=$(echo `date -d "20131220" +%j`)
THEDAY=$(echo `expr $DATECOMING - $DATENOW`)
echo $THEDAY
Попробуйте:
perl -e 'use Date::Calc qw(Delta_Days); printf "%d\n", Delta_Days(2002,10,20,2003,11,22);'
Другая версия Python:
python -c "from datetime import date; print date(2003, 11, 22).toordinal() - date(2002, 10, 20).toordinal()"
Используйте функции оболочки из http://cfajohnson.com/shell/ssr/ssr-scripts.tar.gz; они работают в любой стандартной оболочке Unix.
date1=2012-09-22
date2=2013-01-31
. date-funcs-sh
_date2julian "$date1"
jd1=$_DATE2JULIAN
_date2julian "$date2"
echo $(( _DATE2JULIAN - jd1 ))
Смотрите документацию на http://cfajohnson.com/shell/ssr/08-The-Dating-Game.shtml
Предположим, что мы вручную создаем резервные копии Oracle DB на третичном диске вручную. Затем мы хотим удалить старые резервные копии на этом диске. Итак, вот небольшой bash script:
#!/bin/sh
for backup_dir in {'/backup/cmsprd/local/backupset','/backup/cmsprd/local/autobackup','/backup/cfprd/backupset','/backup/cfprd/autobackup'}
do
for f in `find $backup_dir -type d -regex '.*_.*_.*' -printf "%f\n"`
do
f2=`echo $f | sed -e 's/_//g'`
days=$(((`date "+%s"` - `date -d "${f2}" "+%s"`)/86400))
if [ $days -gt 30 ]; then
rm -rf $backup_dir/$f
fi
done
done
Измените сроки и срок хранения ( "30 дней" ) в соответствии с вашими потребностями.
Использование команды mysql
$ echo "select datediff('2013-06-20 18:12:54+08:00', '2013-05-30 18:12:54+08:00');" | mysql -N
Результат: 21
ПРИМЕЧАНИЕ. В расчетах используются только части даты значений
Ссылка: http://dev.mysql.com/doc/refman/5.6/en/date-and-time-functions.html#function_datediff
Это предполагает, что месяц составляет 1/12 года:
#!/usr/bin/awk -f
function mktm(datespec) {
split(datespec, q, "-")
return q[1] * 365.25 + q[3] * 365.25 / 12 + q[2]
}
BEGIN {
printf "%d\n", mktm(ARGV[2]) - mktm(ARGV[1])
}
Для MacOS sierra (возможно, из Mac OS X yosemate),
Чтобы получить время эпохи (секунды с 1970 года) из файла и сохранить его в var:
old_dt=`date -j -r YOUR_FILE "+%s"`
Чтобы получить время эпохи текущего времени
new_dt=`date -j "+%s"`
Чтобы вычислить разницу выше двух эпох
(( diff = new_dt - old_dt ))
Чтобы проверить, превышает ли diff более 23 дней
(( new_dt - old_dt > (23*86400) )) && echo Is more than 23 days
Это самое простое, что мне удалось начать работать с 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