Invalid date when posting calendar event with default french format
Description
We enabled the calendar feature on our forum. It worked fine, until an "Invalid date" error appeared when posting an event past the 12th of the month… which is almost certainly a parsing error of french date format (dd/mm/YYYY instead of american mm/dd/YYYY).
Changing the forum default date format to "%d %B %Y, %H:%M:%S" fixed the problem, but now the calendar date picker displays dates as "24 Novembre 20…" (long french format that does not fit in the box). Also manually typing the date into the picker using french short format dd/mm/YYYY causes the "Invalid date" error. Users of our forum are all french and I expect them to input "invalid dates" frequently.
Expected behaviour :
- picking the date using the date picker component should allow to send the form with a date format that can be parsed by the server
- manually entering the date should be disallowed or mark the field as invalid if the typed value can’t be parsed
- french users (and locales with similar date formats) should be able to input dates in a short, familiar format
Steps to reproduce
- Enable calendar on an smf forum with french translation
- Post an event with a date past the 12th of the month (25th of december 2022) OR type directly the date in usual french format (25/12/2022) => the date picker is not marked as invalid, the preview works, but submitting the event leads to an "Invalid date" error page
Environment (complete as necessary)
- Version/Git revision: 2.1.2
- Database Type: mysql
- Database Version:
- PHP Version: 7.3
Additional information/references
Don’t every brother support input type="date" nowadays?
Changing the forum default date format to "%d %B %Y, %H:%M:%S" fixed the problem, but now the calendar date picker displays dates as "24 Novembre 20…" (long french format that does not fit in the box).
As you have already discovered, the accepted input format for dates is determined by the display format for dates.
If the full month name doesn't fit in the input field, try changing %B to %b in the date display format.
Using %b is a marginal improvement: the user still faces an unusual date picker and can face unexpected behavior by typing the date directly.
As a quickfix I removed the id="event_time_input" of the form div in the Post and Calendar templates, replaced <input type="text"…/> with type="date" / type="time" and replaced the $context['event']['start_date_orig']) values with $context['event']['start_date']).
This replaces the jquery date picker with the modern built-in one, which is properly localized and sends value in ISO format. The UX is as expected.
That will work if the user's browser supports <input type="date">. But that isn't supported by all the browsers that SMF supports, so we can't rely on it. In a future version we will be able to, but not yet.
Do we have a list of browsers somewhere? IE is not supported anymore afaik and the date type support is strong.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date#browser_compatibility -> ✔️
In the case of Russian, I replaced $context['event']['start_date_orig'] and $context['event']['end_date_orig'] with $context['event']['start_date'] and $context['event']['end_date'], respectively. I also changed the convertDateToEnglish function slightly, since we don't use "am" and "pm" in dates:
function convertDateToEnglish($date)
{
global $txt, $context;
if ($context['user']['language'] == 'english')
return $date;
$replacements = array_combine(array_map('strtolower', $txt['months_titles']), array(
'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December'
));
$replacements += array_combine(array_map('strtolower', $txt['months_short']), array(
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
));
$replacements += array_combine(array_map('strtolower', $txt['days']), array(
'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
));
$replacements += array_combine(array_map('strtolower', $txt['days_short']), array(
'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'
));
// Find all possible variants of AM and PM for this language.
if ($txt['time_am'] != ' ' && $txt['time_pm'] != ' ') {
$replacements[strtolower($txt['time_am'])] = 'AM';
$replacements[strtolower($txt['time_pm'])] = 'PM';
if (($am = smf_strftime('%p', strtotime('01:00:00'))) !== 'p' && $am !== false)
{
$replacements[strtolower($am)] = 'AM';
$replacements[strtolower(smf_strftime('%p', strtotime('23:00:00')))] = 'PM';
}
if (($am = smf_strftime('%P', strtotime('01:00:00'))) !== 'P' && $am !== false)
{
$replacements[strtolower($am)] = 'AM';
$replacements[strtolower(smf_strftime('%P', strtotime('23:00:00')))] = 'PM';
}
}
return strtr(strtolower($date), $replacements);
}
#8796 fixes this