8

As the headline says, PHP's date("W") function gives back the calendar week (for the current day). Unfortunatly it gives back 52 or 53 for the first day(s) of most years. This is, in a simple thinking way, correct, but very annoying, as January 1st of 2012 is not calendar week 52, it's NOT a calendar week of the current year. Most calendars define this as week 0 or week 52 of the previous year.

This is very tricky when you group each day of the year by their calendar week: 1st of January 2012 and 31st of December 2012 are both put into the same calendar week group.

So my question is: Is there a (native) year-sensitive alternative to PHP's date("W") ?

EDIT: I think I wrote the first version of this question in a very unclear way, so this is my edit: I'm searching for a function that gives back the correct calendar week for the first day(s) of the year. PHP's date("W") gives back 52 for the 1st of January 2012, which is "wrong". It should be 0 or null. According to official sources, the first calendar week of a year starts on the first monday of the year. So, if the first day of a year is not a monday, it's not week 1 ! It's week 0. The wikipedia article says

If 1 January is on a Monday, Tuesday, Wednesday or Thursday, it is in week 01. If 1 January is on a Friday, Saturday or Sunday, it is in week 52 or 53 of the previous year.

This becomes tricky as the last days of the year are also in week 52/53. date("W") does not divide into current year and previous year.

Sliq
  • 15,937
  • 27
  • 110
  • 143
  • INFO: The "beginning of a week" is different depending on culture and country. For example, in Northern America the week starts on SUNDAY (!). What the hell is wrong with you US people, the week simply doesn't start on Sunday ? ;) Afaik there are also countries that define Wednesday as "first day of week". – Sliq Dec 30 '13 at 16:49
  • 1
    btw a similiar issue is now the **highest voted comment on PHP's date doc page**: http://php.net/manual/de/function.date.php#106974 – Sliq Jul 26 '14 at 18:29

4 Answers4

12

This solution converts the excess of december to week 53 and everything in january prior to week 1 to week 0.

$w=(int)date('W');
$m=(int)date('n');
$w=$w==1?($m==12?53:1):($w>=51?($m==1?0:$w):$w);

echo "week $w in ".date('Y');

2013-12-31 ==> week 53 in 2013

2014-01-01 ==> week 1 in 2014

2015-12-31 ==> week 52 in 2015

2016-01-01 ==> week 0 in 2016

And a small test run, so you can see for yourself ;-)

$id=array(25,26,27,28,29,30,31,1,2,3,4,5,6,7,8);        
for($iy=2013;$iy<2067;++$iy){foreach($id as $k=>$v){if($k<7){$im=12;}else{$im=1;}
if($k==7){++$iy;echo '====<br>';}$tme=strtotime("$im/$v/$iy");
echo date('d-m-Y',$tme),'  * *  ';
//THE ACTUAL CODE =================
    $w=(int)date('W',$tme);
    $m=(int)date('n',$tme);
    $w=$w==1?($m==12?53:1):($w>=51?($m==1?0:$w):$w);
//THE ACTUAL CODE =================
echo '<b>WEEK: ',$w,' --- ','YEAR: ',date('Y',$tme),'</b><br>';}--$iy;
echo '----------------------------------<br>';}
Michel
  • 4,076
  • 4
  • 34
  • 52
2

Is there a (native) year-sensitive alternative to PHP's date("W") ?

No, there isn't.

According to official sources, the first calendar week of a year starts on the first monday of the year.

I'm not sure what official sources you're referring to.

PHP's date("W") returns the week number according to ISO 8601. As an international standard, ISO 8601 counts as one of possibly many "official sources". If its definition of week numbers doesn't fit your application, you're free to use anything else you like.

If you use a non-standard definition of "first week of the year", or if you use an official source that's not widely recognized, expect to have to write your own function to replace date("W"). (I'm pretty sure you'll need to write a function.)

The date 2012-01-01 was a Sunday. ISO 8601, Wikipedia, and php agree that the ISO week number for 2012-01-01 is 52.

ISO 8601 doesn't define a week 0.

So, if the first day of a year is not a monday, it's not week 1 !

Neither ISO nor Wikipedia say that. ISO 8601 defines week number 1 as the week that has the year's first Thursday in it. For 2012, the first Thursday was on Jan 5, so week number 1 was Jan 2 to Jan 8. 2012-01-01 was in the final week of the previous year, in terms of ISO weeks.

If you want something different, you can play with arithmetic, division, and so on. (Try dividing date("z") by 7, for example.) Or you can store that data in a database, and have your weeks any way you like.

If you're dealing with accounting periods, I'd almost certainly store that data in a table in a database. It's pretty easy to generate that kind of data with a spreadsheet.

The text of data in a table is much easier to audit than the text of a php function, no matter how simple that function is. And the data is certain to be the same for any program that accesses it, no matter what language it's written in. (So if your database someday has programs written in 5 different languages accessing it, you don't have to write, test, and maintain 5 different functions to get the week number.)

Mike Sherrill 'Cat Recall'
  • 91,602
  • 17
  • 122
  • 185
  • Well, you just repeated what I said. Jan 1 2012 might be week 52 (of year 2011), but it's totally useless in nearly every financial or technical calculation. This is why I asked for a YEAR-SENSITIVE VERSION OF DATE(). I did not say that date() is incorrect. To make even more clear what's the problem: If you get the week for every single day of the year, you will run into serious trouble, because jan 1st and dec 31 are both in "week 52". – Sliq Aug 01 '12 at 17:22
  • by the way: Please stop believing every single line Wikipedia says ! It's just a public site where everybody can copy/paste everything. Wikipedia is not an official source. And the english site's content is not equal to all other languages & countries. For example there are different financial definition of a week, in the "inch" countries it starts on sunday, afaik. – Sliq Aug 01 '12 at 17:26
  • "I did not say that date() is incorrect." Well, you said, "PHP's date("W") gives back 52 for the 1st of January 2012, which is 'wrong'. It should be 0 or null." But it's not wrong, and it's not "wrong". It's performing its documented behavior correctly according to an international standard. (shrug) – Mike Sherrill 'Cat Recall' Aug 01 '12 at 18:03
  • "If you get the week for every single day of the year, you will run into serious trouble, because jan 1st and dec 31 are both in 'week 52'." Whether that's troublesome is entirely application-dependent. Clearly it's bothering your application, so you should probably write a function (or store data in a table) to use instead of `date("W")`. – Mike Sherrill 'Cat Recall' Aug 01 '12 at 18:07
1
$d = new DateTime('first monday january '.date('Y'));
echo $d->format("W");
ARIF MAHMUD RANA
  • 5,026
  • 3
  • 31
  • 58
  • Sorry, but this is not what I was searching for. – Sliq Jul 26 '12 at 13:58
  • Yes, this gives back the week of the first monday of the year, which is ALWAYS week 1. I'm searching for a function that gives back the correct week for the first day of 2012 (which would be 0 or null, not 52) – Sliq Jul 26 '12 at 14:01
  • I've never heard of a "0th" week number, "1st" seems correct to me. – nickb Jul 26 '12 at 14:03
  • @Panique - the function should return 0/null until a week/monday starts? – FatalError Jul 26 '12 at 14:05
  • @nickb ;) I rewrote the Question. January 1st of 2012 is NOT week 52, but date("W") says so. I should be week 0 or null, because the first week of 2012 starts on monday, the 2nd of january. That's the official way to define calendar weeks, at least around most countries (with exceptions for US and UK) – Sliq Jul 26 '12 at 14:05
  • @FatalError Exact ! This is the official (european?) definition of a calendar week. – Sliq Jul 26 '12 at 14:12
1

Google brought me here, and I wanted to post the following to help others like me...

I am in the US, and use DayPilot, and it works as follows:

  1. Week starts on Sun, not Mon.
  2. Jan 1st is always Week 1.
  3. If Jan 1st is not a Sunday, Week 1 is less than 7 days.

This all makes a lot of since to me!

Here is my PHP function to copy that behavior:

      function ProperWeekNum($inDate)
       {$outNum = $inDate->format('W');
        //Make week start on Sunday
        if ($inDate->format('D') == 'Sun') {$outNum++;}
        //Fix begining of year 
        if (($outNum >= 52) && ($inDate->format('M') == 'Jan')) {$outNum = 1;}
        //Fix WEEK #1 is 1-day (Sat)
        else //...without this 2022 was off by 1 all year
         {$jan1st = new DateTime($inDate->format('Y').'-01-01');
          if ($jan1st->format('D') == 'Sat') {$outNum++;}
         }
        //Return without leading zero
        return ltrim($outNum, '0');
       }

I use the function as follows, so when I click on DayPilot, my custom popup's Week # always matches DayPilot's Week #:

      $weeknum = ProperWeekNum($startdate);
      if ($weeknum != ProperWeekNum($enddate))
         {$weeknum .= '-'.ProperWeekNum($enddate);}

Probably won't help the OP, but hopefully it helps someone.