Я думаю, что на ваш вопрос уже был дан более чем адекватный ответ, но, возможно, было бы полезно явно указать, что при наличии указателя на функцию
void (*pf)(int foo, int bar);
два вызова
pf(1, 0);
(*pf)(1, 0);
абсолютно эквивалентны во всех отношениях по определению. Выбор, который использовать, зависит от вас, хотя это хорошая идея, чтобы быть последовательным. В течение долгого времени я предпочитал (*pf)(1, 0)
, потому что мне казалось, что он лучше отражает тип pf
, однако в последние несколько лет я перешел на pf(1, 0)
.
Возможно, это можно сделать быстрее ...
Это было ОЧЕНЬ интересно писать код.
Обратите внимание, что $ direction
равно 1 для вперед и -1 для назад, чтобы упростить задачу :)
Кроме того, $ day
начинается со значения 1 для понедельника и заканчивается на 7 для воскресенья.
function get_date($month, $year, $week, $day, $direction) {
if($direction > 0)
$startday = 1;
else
$startday = date('t', mktime(0, 0, 0, $month, 1, $year));
$start = mktime(0, 0, 0, $month, $startday, $year);
$weekday = date('N', $start);
if($direction * $day >= $direction * $weekday)
$offset = -$direction * 7;
else
$offset = 0;
$offset += $direction * ($week * 7) + ($day - $weekday);
return mktime(0, 0, 0, $month, $startday + $offset, $year);
}
Я тестировал его на нескольких примерах и, кажется, работает всегда, обязательно перепроверьте его. хотя;)
Версия, не зависящая от языка:
Чтобы получить первый конкретный день месяца, начните с первого дня месяца: гггг-мм-01. Используйте любую доступную функцию, чтобы указать число, соответствующее дню недели. Вычтите это число из дня, который вы ищете; например, если первый день месяца - среда (2), и вы ищете пятницу (4), вычтите 2 из 4, оставив 2. Если ответ отрицательный, добавьте 7. Наконец, добавьте это к первому из месяц; для моего примера первая пятница будет третьей.
Чтобы получить последнюю пятницу месяца, найдите первую пятницу следующего месяца и вычтите 7 дней.
strtotime () может вам помочь. например,
<?php
$tsFirst = strtotime('2009-04-00 next friday');
$tsLast = strtotime('2009-05-01 last friday');
echo date(DATE_RFC850, $tsFirst), " | ", date(DATE_RFC850, $tsLast);
печатает Friday, 03-Apr-09 00:00:00 CEST | Friday, 24-Apr-09 00:00:00 CEST
Вы можете использовать mktime , чтобы получить временную метку unix первого дня месяца:
$firstOfMonth = mktime(0, 0, 0, $month, 1, $year);
Когда у вас есть дата первого дня определенного месяца, это легко получить день недели для этой даты, используя date :
$weekday = date("N", $firstOfMonth);
Оттуда довольно легко просто сделать шаг вперед, чтобы узнать дату, которая вам нужна.
Просто узнайте, какой первый и последний день месяца, о котором идет речь (т.е. 1 мая 2009 г. - пятница, а 31 мая 2009 г. - воскресенье). Я считаю, что большинство функций PHP используют понедельник. = 0, воскресенье = 6, следовательно, пятница = 4, поэтому вы знаете, что воскресенье (6) - пятница (4) = 2, затем 31-2 = 29, то есть последняя пятница этого месяца приходится на 29-е число. Для первой пятницы, если число отрицательное, добавьте 7, если число равно 0, месяц начинается в пятницу.
Нет необходимости в вычислениях или циклах - это очень просто сделать с помощью strtotime ():
Найти N-е или последнее вхождение определенного дня определенного месяца:
/////////////////////////////////////////////////////////////////
// Quick Code
/////////////////////////////////////////////////////////////////
// Convenience mapping.
$Names = array( 0=>"Sun", 1=>"Mon", 2=>"Tue", 3=>"Wed", 4=>"Thu", 5=>"Fri", 6=>"Sat" );
// Specify what we want
// In this example, the Second Monday of Next March
$tsInMonth = strtotime('March');
$Day = 1;
$Ord = 2;
// The actual calculations
$ThisMonthTS = strtotime( date("Y-m-01", $tsInMonth ) );
$NextMonthTS = strtotime( date("Y-m-01", strtotime("next month", $tsInMonth) ) );
$DateOfInterest = (-1 == $Ord)
? strtotime( "last ".$Names[$Day], $NextMonthTS )
: strtotime( $Names[$Day]." + ".($Ord-1)." weeks", $ThisMonthTS );
/////////////////////////////////////////////////////////////////
// Explanation
/////////////////////////////////////////////////////////////////
// Specify the month of which we are interested.
// You can use any timestamp inside that month, I'm using strtotime for convenience.
$tsInMonth = strtotime('March');
// The day of interest, ie: Friday.
// It can be 0=Sunday through 6=Saturday (Like 'w' from date()).
$Day = 5;
// The occurrence of this day in which we are interested.
// It can be 1, 2, 3, 4 for the first, second, third, and fourth occurrence of the day in question in the month in question.
// You can also use -1 to fine the LAST occurrence. That will return the fifth occurrence if there is one, else the 4th.
$Ord = 3;
////////////////////////////////////////////////////////////////
// We now have all the specific values we need.
// The example values above specify the 3rd friday of next march
////////////////////////////////////////////////////////////////
// We need the day name that corresponds with our day number to pass to strtotime().
// This isn't really necessary = we could just specify the string in the first place, but for date calcs, you are more likely to have the day number than the string itself, so this is convenient.
$Names = array( 0=>"Sun", 1=>"Mon", 2=>"Tue", 3=>"Wed", 4=>"Thu", 5=>"Fri", 6=>"Sat" );
// Calculate the timestamp at midnight of the first of the month in question.
// Remember $tsInMonth is any date in that month.
$ThisMonthTS = strtotime( date("Y-m-01", $tsInMonth ) );
// Calculate the timestamp at midnight of the first of the FOLLOWING month.
// This will be used if we specify -1 for last occurrence.
$NextMonthTS = strtotime( date("Y-m-01", strtotime("next month", $tsInMonth) ) );
// Now we just format the values a bit and pass them to strtotime().
// To find the 1,2,3,4th occurrence, we work from the first of the month forward.
// For the last (-1) occurence,work we work back from the first occurrence of the following month.
$DateOfInterest = (-1 == $Ord) ?
strtotime( "last ".$Names[$Day], $NextMonthTS ) : // The last occurrence of the day in this month. Calculated as "last dayname" from the first of next month, which will be the last one in this month.
strtotime( $Names[$Day]." + ".($Ord-1)." weeks", $ThisMonthTS ); // From the first of this month, move to "next dayname" which will be the first occurrence, and then move ahead a week for as many additional occurrences as you need.
function get_date($month, $year, $week, $day) {
# $month, $year: current month to search in
# $week: 0=1st, 1=2nd, 2=3rd, 3=4th, -1=last
# $day: 0=mon, 1=tue, ..., 6=sun
$startday=1; $delta=0;
if ($week < 0) {
$startday = date('t', mktime(0, 0, 0, $month, 1, $year)); # 28..31
$delta=1;
}
$start = mktime(0, 0, 0, $month, $startday, $year);
$dstart = date('w', $start)-1; # last of the month falls on 0=mon,6=sun
$offset=$day-$dstart; if ($offset<$delta){$offset+=7;}
$newday=$startday+$offset+($week*7);
return mktime(0, 0, 0, $month, $newday, $year);
}
Это работает для меня и основано на версии, не зависящей от языка :-) Очень плохо, мне нужно было сделать эту дельта-вещь (поскольку, если последний день месяца является желаемым днем недели, нам не нужно вычитать 7)