From 1af44b858ccb658d5e137aa8c1327366fe3a7da6 Mon Sep 17 00:00:00 2001 From: campbell-m <87438215+campbell-m@users.noreply.github.com> Date: Wed, 1 Nov 2023 17:48:12 +0000 Subject: [PATCH] Use the IntlCalendar extension if possible to find the first day of the week in the user's locale. The week numbers in MRBS are based on the week number in the locale, which won't necessarily be the ISO week number. --- web/functions_table.inc | 5 +++-- web/index.php | 8 ++++---- web/js/datepicker.js.php | 4 ++-- web/lib/MRBS/DateTime.php | 34 ++++++++++++++++++++++++++++++++++ web/systemdefaults.inc.php | 18 ++++++++++-------- 5 files changed, 53 insertions(+), 16 deletions(-) diff --git a/web/functions_table.inc b/web/functions_table.inc index 9c49ec70f4..f85ee611af 100644 --- a/web/functions_table.inc +++ b/web/functions_table.inc @@ -1586,6 +1586,7 @@ function month_room_table_innerhtml(string $view, int $view_all, int $year, int global $weekstarts, $view_week_number, $show_plus_link, $monthly_view_entries_details; global $enable_periods, $morningstarts, $morningstarts_minutes; global $prevent_booking_on_holidays, $prevent_booking_on_weekends; + global $timezone; // Check that we've got a valid, enabled room if (is_null(get_room_name($room)) || !is_visible($room)) @@ -1668,8 +1669,8 @@ function month_room_table_innerhtml(string $view, int $view_all, int $year, int 'area' => $area, 'room' => $room); - // If it's a Monday (the start of the ISO week), show the week number - if ($view_week_number && (($weekcol + $weekstarts)%DAYS_PER_WEEK == 1)) + // If it's the first day of the week, show the week number + if ($view_week_number && (($weekcol + $weekstarts)%DAYS_PER_WEEK == DateTime::firstDayOfWeek($timezone, get_mrbs_locale()))) { $vars['view'] = 'week'; $query = http_build_query($vars, '', '&'); diff --git a/web/index.php b/web/index.php index c7cc0d4187..38542e18dc 100644 --- a/web/index.php +++ b/web/index.php @@ -329,7 +329,7 @@ function get_calendar_nav(string $view, int $view_all, int $year, int $month, in function get_date_heading(string $view, int $year, int $month, int $day) : string { - global $datetime_formats, $display_timezone, + global $datetime_formats, $display_timezone, $timezone, $weekstarts, $view_week_number; $html = ''; @@ -344,9 +344,9 @@ function get_date_heading(string $view, int $year, int $month, int $day) : strin break; case 'week': - // Display the week number if required, provided the week starts on Monday, - // otherwise it's spanning two ISO weeks and doesn't make sense. - if ($view_week_number && ($weekstarts == 1)) + // Display the week number if required, provided the MRBS week starts on the first day + // of the week, otherwise it's spanning two weeks and doesn't make sense. + if ($view_week_number && ($weekstarts == DateTime::firstDayOfWeek($timezone, get_mrbs_locale()))) { $html .= '' . get_vocab('week_number', datetime_format($datetime_formats['week_number'], $time)) . diff --git a/web/js/datepicker.js.php b/web/js/datepicker.js.php index 1e5b3de761..79576fd703 100644 --- a/web/js/datepicker.js.php +++ b/web/js/datepicker.js.php @@ -337,8 +337,8 @@ function (date) { } else { - - config.weekNumbers = ; + + config.weekNumbers = ; } flatpickr('input[type="date"]', config); diff --git a/web/lib/MRBS/DateTime.php b/web/lib/MRBS/DateTime.php index 4d57107b98..4f6b3f9783 100644 --- a/web/lib/MRBS/DateTime.php +++ b/web/lib/MRBS/DateTime.php @@ -2,6 +2,7 @@ declare(strict_types=1); namespace MRBS; +use IntlCalendar; use MRBS\ICalendar\RFC5545; use UnexpectedValueException; @@ -33,6 +34,39 @@ public static function createFromFormat($format, $datetime, ?\DateTimeZone $time return new static($parent->format('Y-m-d\TH:i:s.u'), $parent->getTimezone()); } + + // Returns the first day of the week (0 = Sunday) for a given timezone and locale. + // If $timezone is null, the default timezone will be used. + // If $locale is null, the default locale will be used. + // The method relies on the IntlCalendar class. If it doesn't exist, or there's an error, + // the method assumes that the week starts on a Monday. + public static function firstDayOfWeek(?string $timezone = null, ?string $locale = null) : int + { + $default = 1; // Monday + + if (!class_exists('\\IntlCalendar')) + { + return $default; + } + + $calendar = IntlCalendar::createInstance($timezone, $locale); + if (!isset($calendar)) + { + trigger_error("Could not create IntlCalendar for timezone '$timezone' and locale '$locale'", E_USER_WARNING); + return $default; + } + + $first_day = $calendar->getFirstDayOfWeek(); + if ($first_day === false) + { + trigger_error($calendar->getErrorMessage(), E_USER_WARNING); + return $default; + } + + return $first_day - 1; // IntlCalendar::DOW_SUNDAY = 1, so we need to subtract 1 + } + + // TODO: replace usages of byday_to_day() with this method // TODO: make $relative an object? // Sets the day to $relative, where relative is an RFC5545 relative day, diff --git a/web/systemdefaults.inc.php b/web/systemdefaults.inc.php index aa6b0f4bb9..d05ba7dfbf 100644 --- a/web/systemdefaults.inc.php +++ b/web/systemdefaults.inc.php @@ -436,11 +436,18 @@ // of 12. $monthly_view_entries_details = "both"; -// To show ISO week numbers in the main calendar, set this to true. The week -// numbers are only displayed if you set $weekstarts to 1 (Monday), i.e. the -// start of the ISO week. +// To show week numbers in the main calendar, set this to true. The week +// numbers are only displayed if you set $weekstarts to start on the first +// day of the week in your locale and area's timezone. (This assumes that +// the PHP IntlCalendar class is available; if not, the week is assumed to +// start on Mondays, ie the ISO stanard.) $view_week_number = false; +// To display week numbers in the mini-calendars, set this to true. The week +// numbers are only displayed if you set $weekstarts to the start of the week. +// See the comment about when the week starts above. +$mincals_week_numbers = false; + // Whether or not the mini-calendars are displayed. (Note that mini-calendars are only // displayed anyway if the window is wide enough.) $display_mincals = true; @@ -450,11 +457,6 @@ // provided the window is high enough. $display_mincals_above = false; -// To display week numbers in the mini-calendars, set this to true. The week -// numbers are only displayed if you set $weekstarts to 1 (Monday), i.e. the -// start of the ISO week. -$mincals_week_numbers = false; - // To display the endtime in the slot description, eg '09:00-09:30' instead of '09:00', set // this to true. $show_slot_endtime = false;