Я пытался решить этот вопрос в течение многих лет, я думал, что нашел более короткое решение, но мне пришлось вернуться к длинной истории.Эта функция возвращает правильное обозначение недели ISO:
/**
* calcweek("2018-12-31") => 1901
* This function calculates the production weeknumber according to the start on
* monday and with at least 4 days in the new year. Given that the $date has
* the following format Y-m-d then the outcome is and integer.
*
* @author M.S.B. Bachus
*
* @param date-notation PHP "Y-m-d" showing the data as yyyy-mm-dd
* @return integer
**/
function calcweek($date) {
// 1. Convert input to $year, $month, $day
$dateset = strtotime($date);
$year = date("Y", $dateset);
$month = date("m", $dateset);
$day = date("d", $dateset);
$referenceday = getdate(mktime(0,0,0, $month, $day, $year));
$jan1day = getdate(mktime(0,0,0,1,1,$referenceday[year]));
// 2. check if $year is a leapyear
if ( ($year%4==0 && $year%100!=0) || $year%400==0) {
$leapyear = true;
} else {
$leapyear = false;
}
// 3. check if $year-1 is a leapyear
if ( (($year-1)%4==0 && ($year-1)%100!=0) || ($year-1)%400==0 ) {
$leapyearprev = true;
} else {
$leapyearprev = false;
}
// 4. find the dayofyearnumber for y m d
$mnth = array(0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334);
$dayofyearnumber = $day + $mnth[$month-1];
if ( $leapyear && $month > 2 ) { $dayofyearnumber++; }
// 5. find the jan1weekday for y (monday=1, sunday=7)
$yy = ($year-1)%100;
$c = ($year-1) - $yy;
$g = $yy + intval($yy/4);
$jan1weekday = 1+((((intval($c/100)%4)*5)+$g)%7);
// 6. find the weekday for y m d
$h = $dayofyearnumber + ($jan1weekday-1);
$weekday = 1+(($h-1)%7);
// 7. find if y m d falls in yearnumber y-1, weeknumber 52 or 53
$foundweeknum = false;
if ( $dayofyearnumber <= (8-$jan1weekday) && $jan1weekday > 4 ) {
$yearnumber = $year - 1;
if ( $jan1weekday = 5 || ( $jan1weekday = 6 && $leapyearprev )) {
$weeknumber = 53;
} else {
$weeknumber = 52;
}
$foundweeknum = true;
} else {
$yearnumber = $year;
}
// 8. find if y m d falls in yearnumber y+1, weeknumber 1
if ( $yearnumber == $year && !$foundweeknum) {
if ( $leapyear ) {
$i = 366;
} else {
$i = 365;
}
if ( ($i - $dayofyearnumber) < (4 - $weekday) ) {
$yearnumber = $year + 1;
$weeknumber = 1;
$foundweeknum = true;
}
}
// 9. find if y m d falls in yearnumber y, weeknumber 1 through 53
if ( $yearnumber == $year && !$foundweeknum ) {
$j = $dayofyearnumber + (7 - $weekday) + ($jan1weekday - 1);
$weeknumber = intval( $j/7 );
if ( $jan1weekday > 4 ) { $weeknumber--; }
}
// 10. output iso week number (YYWW)
return ($yearnumber-2000)*100+$weeknumber;
}
Я обнаружил, что мое короткое решение пропустило 2018-12-31, так как оно вернуло 1801 вместо 1901. Поэтому мне пришлось вставить это длинноеверная версия.