A = "2002-20-10"
B = "2003-22-11"
Как найти разницу в днях между двумя датами?
A = "2002-20-10"
B = "2003-22-11"
Как найти разницу в днях между двумя датами?
Ответы:
Если у вас есть GNU date
, он позволяет распечатать представление произвольной даты ( -d
опция). В этом случае преобразуйте даты в секунды с момента EPOCH, вычтите и разделите на 24 * 3600.
Или нужен переносной способ?
echo "( `date -d $B +%s` - `date -d $A +%s`) / (24*3600)" | bc -l
Способ bash - конвертируйте даты в формат% y% m% d, а затем вы можете сделать это прямо из командной строки:
echo $(( ($(date --date="031122" +%s) - $(date --date="021020" +%s) )/(60*60*24) ))
%y%m%d
формате. Например, gnu date примет %Y-%m-%d
формат, используемый OP. В общем, ISO-8601 - хороший выбор (и формат OP является одним из таких форматов). Форматы с двузначным годом лучше избегать.
days_diff=$(( (`date -d $B +%s` - `date -d "00:00" +%s`) / (24*3600) ))
. обратите внимание, что $days_diff
это будет целое число (т.е. без десятичных знаков)
date
установки. Это работает для GNU date
. Он не работает с POSIX date
. Вероятно, это не проблема для большинства читателей, но стоит отметить.
%Y-%m-%d
, пока мы не введем August 2.0
и October 2.0
формат OP является %Y-%d-%m
. Соответствующий xkcd: xkcd.com/1179
tl; dr
date_diff=$(( ($(date -d "2015-03-11 UTC" +%s) - $(date -d "2015-03-05 UTC" +%s)) / (60*60*24) ))
Осторожно! Многие из решений bash здесь не работают для диапазонов дат, которые охватывают дату начала летнего времени (где применимо). Это связано с тем, что конструкция $ ((math)) выполняет операцию «пол» / усечения над результирующим значением, возвращая только целое число. Позвольте мне проиллюстрировать:
Летнее время в США началось 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 - это час, потерянный после перехода на летнее время.
Так как же это сделать правильно?
Я бы предложил использовать вместо этого:
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) ))
Это также должно быть безопасным для секунды координации, если вы всегда вычитаете более раннюю дату из более поздней, поскольку секунды координации будут только увеличивать разницу - усечение эффективно округляется до правильного результата.
echo $(( ($(date --date="2015-03-11 UTC" +%s) - $(date --date="2015-03-05 UTC" +%s) )/(60*60*24) ))
которая возвращает 6 вместо 5.
И в питоне
$python -c "from datetime import date; print (date(2003,11,22)-date(2002,10,20)).days"
398
bash
и shell
, поэтому я думаю, мы можем предположить, что мы говорим о системе * nix. Внутри таких систем echo
и date
надежно присутствуют, а вот питона нет.
Это работает для меня:
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)Если опция -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`
Вот версия 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!
A="2002-20-10"; B="2003-22-11"
echo $(((`date -jf "%Y-%d-%m" "$B" +%s` - `date -jf "%Y-%d-%m" "$A" +%s`)/86400))
, то есть заключить оба формата и переменные в двойные кавычки, иначе может произойти сбой в другом формате даты (например, %b %d, %Y
/ Jul 5, 2017
)
Даже если у вас нет даты 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
Использование команды 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
Вот мой рабочий подход с использованием zsh. Проверено на OSX:
# Calculation dates
## A random old date
START_DATE="2015-11-15"
## Today's date
TODAY=$(date +%Y-%m-%d)
# Import zsh date mod
zmodload zsh/datetime
# Calculate number of days
DIFF=$(( ( $(strftime -r %Y-%m-%d $TODAY) - $(strftime -r %Y-%m-%d $START_DATE) ) / 86400 ))
echo "Your value: " $DIFF
Результат:
Your value: 1577
По сути, мы используем функцию strftime
reverse ( -r
) для преобразования нашей строки даты обратно в метку времени, а затем производим наши вычисления.
Я бы предложил другое возможное решение на Ruby. Похоже, это самый маленький и чистый на данный момент:
A=2003-12-11
B=2002-10-10
DIFF=$(ruby -rdate -e "puts Date.parse('$A') - Date.parse('$B')")
echo $DIFF
date
или какой-либо язык сценариев), и я искренне думаю, что Ruby - хороший вариант . Это очень короткое решение, в котором не используются нестандартные библиотеки или другие зависимости. На самом деле, я думаю, что вероятность того, что Ruby будет установлена, выше, чем дата GNU.
Используйте функции оболочки из 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
в 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
Предполагается, что месяц равен 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])
}
Попробуйте:
perl -e 'use Date::Calc qw(Delta_Days); printf "%d\n", Delta_Days(2002,10,20,2003,11,22);'
Предположим, мы вручную выполняем синхронизацию резервных копий 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
Измените каталоги и срок хранения («30 дней») в соответствии с вашими потребностями.
Для MacOS sierra (возможно, из Mac OS X yosemate),
Чтобы получить время эпохи (секунды с 1970 года) из файла и сохранить его в переменной:
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
echo $(date +%d/%h/%y) date_today
echo " The other date is 1970/01/01"
TODAY_DATE="1970-01-01"
BEFORE_DATE=$(date +%d%h%y)
echo "THE DIFFERNS IS " $(( ($(date -d $BEFORE_DATE +%s) - $(date -d $TODAY_DATE +%s)) )) SECOUND
используйте его, чтобы получить дату сегодня и вашу секунду с нужной даты. если вы хотите, чтобы это было дни, просто разделите его на 86400
echo $(date +%d/%h/%y) date_today
echo " The other date is 1970/01/01"
TODAY_DATE="1970-01-01"
BEFORE_DATE=$(date +%d%h%y)
echo "THE DIFFERNS IS " $(( ($(date -d $BEFORE_DATE +%s) - $(date -d $TODAY_DATE +%s))/ 86400)) SECOUND