Подсчитать число понедельников в интервале между датами

zahhar

двинутый новичок
Подсчитать число понедельников в интервале между датами

Коллеги, подскажите пожалуйста наиболее простой/эффективный алгоритм подсчета числа определенного для недели (понедельника, вторника, ...) в заданном диапазоне дат.

Например, в диапазоне [7.6.2005-29.6.2005] встречается 3 понедельника. Как опредлить это программно?

Заранее благодарю.
 

Фанат

oncle terrible
Команда форума
может быть, ты сначала попробуешь написать не простой не эффективный?
а потом мы вместе его оптимизируем
 

rotoZOOM

ACM maniac
zahhar узнай день недели левой границы. Потом посчитай сколько дней в твоем интервале, а дальше все просто.
 

Popoff

popoff.donetsk.ua
посчитать количество чисел, кратных 7, в интервале от 1 до n можно по формуле: floor(n/7). известно, что 01.01.0001 - понедельник. зная количество дней m от 01.01.0001 до заданной даты (считаем, что для 01.01.0001 m=1; алгоритм быстрого подсчета этого числа не составит труда найти в интернете), можно посчитать, сколько всего понедельников прошло от начала эры: floor((m+6)/7). зная количество понедельников от начала эры до первой даты (x1) и до второй даты (x2), количество понедельников между этими двумя датами можно посчитать по формуле x2-x1.
 

zahhar

двинутый новичок
Фанат
Не простой и не эффективный -- это простой перебор.
Например:
PHP:
<?
function count_dow_in_range($startdate,$enddate,$dow) {
/*$startdate -- unix timestamp, левая граница интервала
$enddate -- unix timestamp, правая граница интервала
$dow -- искомый день недели аналогично формату ф-ции date('w'), где вс=0, сб=6 */

  $i=0; /*счетчик искомого дня недели*/
  while($startdate<=$enddate) { 
     if(date('w',$startdate)==$dow) $i++;
     $startdate+=86400;
  }
  return $i;
}

echo count_dow_in_range(strtotime("2005-12-01"),strtotime("2006-01-17"),0); /*число воскресений с 1 декабря 2005 года по 17 января 2006 года*/
?>
 

Фанат

oncle terrible
Команда форума
а это у тебя, небось, из мускуля дата берётся?
 

zahhar

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

Фанат

oncle terrible
Команда форума
просто в мускуле есть функция to_days, с которой было бы проще проще. но раз всё равно писать, то используй алгоритм rotoZOOM
 

zahhar

двинутый новичок
вот только я не врублюсь, как в его алгоритме дальше действовать. как, зная, что в интервале 61 день и начало интервала приходится на вторник, узнать число воскресений в нем?
 

zahhar

двинутый новичок
об этом я догадался. число полных недель=минимальное число искомого дня недели. далее в некоторых случаях надо сделать поправку +1 в зависимости от остатка. а вот как интерпретировать остаток?
 

Фанат

oncle terrible
Команда форума
rotoZOOM
узнай день недели левой границы
а точнее - его номер.
его даёт тебе функция date

вообще, сесть, руками поэкспериментировать - это полчаса.
давно бы уже сам делал, чем на форкме каждую строчку спрашивать
 

rotoZOOM

ACM maniac
zahhar зная количество дней между двумя датами, вычиляешь количество полных недель (как сказал Фанат).
$diff - это разница в днях
$pol=$diff/7;
Далее смотришь остаток от деления на 7.
$ost=$diff%7;
И если твой день недели существует на промежутке от
[$номер_дня_недели_левой_границы ; $номер_дня_недели_левой_границы+$ost], то прибавляешь еще 1, но это тут надо уже четко определить, что значит "заданный диапазон": включая/невключая левую/правую границу, от этого будет зависеть прибавление последней единички.

Popoff точно 01.01.0001 - это понедельник ? у меня вторник получился.
 

ech

Новичок
PHP:
function monthWeekDays($month) {
    $date = strtotime("01." . $month);
    $cur_day = date("N", $date) - 1;
    $day_count = date("t", $date);
   
    $entire_count =  $day_count % 7;
    $day_count -= $entire_count * 7;
   
    $result = array_fill(0, 7, $entire_count);
    while ( $day_count != 0 ) {
        $result[$cur_day]++;
        $day_count--;
        $cur_day++;
        if ( $cur_day == 7 ) $cur_day = 0;
    }
   
    return $result;
}
Такая функция вышла, для расчета количества дней недели в месяце, может быть глупо конечно для одного месяца это использовать, но можно подобно сделать для периода.
 

Breeze

goshogun
Команда форума
Партнер клуба
@ech, ты на дату вопроса смотрел, диггер ты наш новоявленный?
 

Вурдалак

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

Breeze

goshogun
Команда форума
Партнер клуба
Дело не в закрытии, а в том, что, спустя 12 лет, автору топика этот ответ нафиг не сдался.
 

Вурдалак

Продвинутый новичок
Ну и? Есть проблема — некропостинг. Есть решение — автоматическое закрытие старых тем.
 

Adelf

Administrator
Команда форума
далеко не каждый смотрит на даты прежде чем написать ответ. так что некропостинг не бог весть что :)
Честно говоря лень искать сякие автозакрывалки старых тем. тем более, что есть вероятность, что кто-то даже сильно опоздав может предложить хорошее решение, которое поможет кому-то.
 

Вурдалак

Продвинутый новичок
Я просто не помню на своей памяти, чтобы «хорошее решение» когда-либо было аргументом. Обычно любая подобная тема заканчивается закидываем помидорами некропостера. Ну так если это технически несложно решается, то решите, чо. Или не жалуйтесь на некропостинг.

Что касается тех случаев, когда кому-то есть что сказать, то в принципе ничего не мешает создать новую дискуссию, сославшись на старую тему.

Либо можно взять за правило модераторам разделять темы вручную, перекинув посты некропостера в отдельный тред со ссылкой на старую.
 
Сверху