17 ответов:
Если у вас есть GNU
date, Это позволяет печатать представление произвольной даты (). В этом случае преобразуйте даты в секунды с момента эпохи, вычитайте и разделите на 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".
Edit: выделение ответа в комментарии от @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
Я бы представил другое возможное решение в 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
это работает для меня:
A="2002-10-20" B="2003-11-22" echo $(( (`date -d $B +%s` - `date -d $A +%s`) / 86400 )) daysпечать
398 daysчто происходит?
- укажите допустимую строку времени в A и B
- использовать
date -dдля обработки строк времени- использовать
date %sдля преобразования строк времени в секунды с 1970 года (Unix epoche)- использовать расширение параметра bash вычесть секунд
- деление на секунды в секунду день (86400=60*60*24), чтобы получить разницу в днях
- ! DST не принимается во внимание ! Смотрите этот ответ на unix.stackexchange!
дайте этому попытку:
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()"
предположим, что мы rsync Oracle DB резервное копирование на третичный диск вручную. Затем мы хотим удалить старые резервные копии на диске. Итак, вот небольшой скрипт bash:
#!/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измените dirs и срок хранения ("30 дней") в соответствии с вашими потребностями.
используйте функции оболочки из 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
С помощью команды 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 ))чтобы проверить, если разница составляет более 23 дней
(( new_dt - old_dt > (23*86400) )) && echo Is more than 23 days
Comments