he tratado de resolver esta cuestión desde hace años, pensé que encontró una solución más corto, pero tenía para volver a la larga historia. Esta función devuelve el derecho ISO semana notación:
/**
* 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;
}
descubrí que mi solución a corto perdió el 31/12/2018, ya que devolvió 1801 en lugar de 1901. Por lo tanto, tuvo que poner en esta versión larga, que es correcto.
Solo para agregar, no olvides configurar la zona horaria, usando PHP.ini o vía date_default_timezone_set ('Asia/Singapur'); – fedmich