Getting a list of week numbers between two dates

Recently, I was working on a PHP application that needed to show weekly summaries in the period of one month. Then, January came and I found myself looking at 48 weeks instead of the expected 4 to 5.

This is the piece of code that I used in a Twig template.

{% set weeks = firstDayOfMonth|date('W') .. lastDayOfMonth|date('W') %}

What the above does, is to use a date called firstDayOfMonth (containing January 1st), get the week number and use Twig’s range operator to count up to the week number belonging to the lastDayOfMonth (January 31st).

Looks good, right? You’d expect January 1st to be in the first week of the year and it would count up to week number 5. Or not?

Unfortunately, and I knew this, January 1st 2022 was in week number 52 of 2021. What happened next was that Twig’s range operator would count down from 52 to 5, which is definitely the opposite of what I would want to show!

The fix? What I should have done was to move the business logic outside of twig, and leverage PHP’s native, and incredible, DatePeriod class. With it, I can get a series of dates for every week between the start of the month and the start of the next month:

$period = new DatePeriod(
    new DateInterval('P1W'), $startOfMonth->modify('+1 month')

Sidebar: if you are doing some serious Date/Time magic, consider looking into You’ll thank me later.

And with this list of dates, I can loop through each and convert them to a week number. This will automatically wrap around the year, and thus provide a list matching 52, 1, 2, 3, 4 and 5 (yes, January 2022 is spread across 6 weeks!).

$weekNumbers = array_map(
    static fn(DateTimeInterface $startOfWeek): int => (int)$startOfWeek->format('W'),

Sidebar: Please take note of the typecast to int and the use of iterator_to_array to ensure we can map an Iterator of DateTime objects into an array of integers.

And there you have it, a neat list of week numbers as integers given a period!

Leave a Reply

Your email address will not be published. Required fields are marked *