A calendar written with IntlCalendar class

Code
<?php

// Berlin - Germany
$c IntlCalendar::createInstance('Europe/Berlin''de_DE');
$renderer = new CalendarMonthRenderer(new IntlDateFormatter('de_DE'nullnull));
echo 
$renderer->render(new CalendarMonth($c));

// USA - New York
$c IntlCalendar::createInstance('America/New_York''en_US');
$renderer = new CalendarMonthRenderer(new IntlDateFormatter('en_US'nullnull));
echo 
$renderer->render(new CalendarMonth($c));


/**
 * This code snippet is no copy and paste example. It has no error
 * handling and isn't generic or clean written enough to be used in 
 * production.
 */
class CalendarMonth
{
    private 
$calendar;
    private 
$now;
    
    const 
DAY IntlCalendar::FIELD_DATE;
    const 
MONTH IntlCalendar::FIELD_MONTH;
    const 
DOW_LOCAL IntlCalendar::FIELD_DOW_LOCAL;
    
    public function 
__construct(IntlCalendar $calendar)
    {
        
$this->calendar $calendar;
        
$this->now $calendar->getTime();
    }
    
    public function 
getNow()
    {
        return 
$this->now;
    }
    
    public function 
createStructure()
    {
        
$calendar $this->calendar;
        
        
// beginning of the week
        
$calendar->set(self::DAY$calendar->getMinimum(self::DAY));
        
$dayOfWeek $calendar->get(self::DOW_LOCAL);
        
$month $calendar->get(self::MONTH);
        
$calendar->add(self::DAY, -($dayOfWeek 1));

        
$structure = [];
        
$week = [];
        while (
$calendar->get(self::MONTH) <= $month || 
            !
$this->isNewWeek($calendar)
        ) {
            if (
$this->isNewWeek($calendar)) {
                
$week = [];
            }
            
            
$week[] = $calendar->getTime();
            
            if (
$this->isEndOfWeek($calendar)) {
                
$structure[] = $week;
                if (
$calendar->get(self::MONTH) != $month) {
                    break;
                }
            }
            
            
$calendar->add(self::DAY1);
        }
        
        return 
$structure;
    }
    
    private function 
isNewWeek(IntlCalendar $c)
    {
        return 
=== $c->get(self::DOW_LOCAL);
    }
    
    private function 
isEndOfWeek(IntlCalendar $c)
    {
        return 
=== $c->get(self::DOW_LOCAL);
    }
}

class 
CalendarMonthRenderer
{
    private 
$formatter;
    
    public function 
__construct(IntlDateFormatter $formatter)
    {
        
$this->formatter $formatter;
    }
    
    public function 
render(CalendarMonth $calendar)
    {
        
$days $weekdays '';
        foreach (
$calendar->createStructure() as $pos => $week) {
            
$days .= '<tr>';
            foreach(
$week as $day) {
                if (
=== $pos) {
                    
$weekdays .= '<td>' $this->format($day 1000'E') . '</td>';
                }
            
                
$days .= '<td align="right">' $this->format($day 1000'd') . '</td>';
            }
            
$days .= '</tr>';
        }
        
        
$caption '<caption>' $this->format($calendar->getNow() / 1000'LLLL') . '</caption>';
        
        return 
'<table border="1">' $caption '<tr>' $weekdays '</tr>' $days '</table>';
    }
    
    private function 
format($c$format)
    {
        
$this->formatter->setPattern($format);
        return 
$this->formatter->format($c);
    }
}
Result
März
Mo.Di.Mi.Do.Fr.Sa.So.
26272829123
45678910
11121314151617
18192021222324
25262728293031
March
MonTueWedThuFriSatSun
26272829123
45678910
11121314151617
18192021222324
25262728293031
1234567
Used Versions
PHP 8.2, Laminas MVC 3.2, Symfony 5.2, Laravel 8.28, PHPUnit 9.5, Doctrine ORM 2.8