From 15396bba9bb6ff7559709126f553125ff08fb6ce Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 20 Sep 2012 17:18:33 +0800 Subject: [PATCH] MDL-35171 Forms: Date selector always gets UTF-8 strings --- lib/formslib.php | 38 ++++++++++++------------- lib/moodlelib.php | 54 ++++++++++++++++++++++++++---------- lib/tests/moodlelib_test.php | 36 ++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 33 deletions(-) diff --git a/lib/formslib.php b/lib/formslib.php index 00044d6a2b7..5e39e77f603 100644 --- a/lib/formslib.php +++ b/lib/formslib.php @@ -81,25 +81,25 @@ function form_init_date_js() { $function = 'M.form.dateselector.init_date_selectors'; $config = array(array( 'firstdayofweek' => get_string('firstdayofweek', 'langconfig'), - 'mon' => strftime('%a', strtotime("Monday")), - 'tue' => strftime('%a', strtotime("Tuesday")), - 'wed' => strftime('%a', strtotime("Wednesday")), - 'thu' => strftime('%a', strtotime("Thursday")), - 'fri' => strftime('%a', strtotime("Friday")), - 'sat' => strftime('%a', strtotime("Saturday")), - 'sun' => strftime('%a', strtotime("Sunday")), - 'january' => strftime('%B', strtotime("January 1")), - 'february' => strftime('%B', strtotime("February 1")), - 'march' => strftime('%B', strtotime("March 1")), - 'april' => strftime('%B', strtotime("April 1")), - 'may' => strftime('%B', strtotime("May 1")), - 'june' => strftime('%B', strtotime("June 1")), - 'july' => strftime('%B', strtotime("July 1")), - 'august' => strftime('%B', strtotime("August 1")), - 'september' => strftime('%B', strtotime("September 1")), - 'october' => strftime('%B', strtotime("October 1")), - 'november' => strftime('%B', strtotime("November 1")), - 'december' => strftime('%B', strtotime("December 1")) + 'mon' => date_format_string(strtotime("Monday"), '%a', 99), + 'tue' => date_format_string(strtotime("Tuesday"), '%a', 99), + 'wed' => date_format_string(strtotime("Wednesday"), '%a', 99), + 'thu' => date_format_string(strtotime("Thursday"), '%a', 99), + 'fri' => date_format_string(strtotime("Friday"), '%a', 99), + 'sat' => date_format_string(strtotime("Saturday"), '%a', 99), + 'sun' => date_format_string(strtotime("Sunday"), '%a', 99), + 'january' => date_format_string(strtotime("January 1"), '%B', 99), + 'february' => date_format_string(strtotime("February 1"), '%B', 99), + 'march' => date_format_string(strtotime("March 1"), '%B', 99), + 'april' => date_format_string(strtotime("April 1"), '%B', 99), + 'may' => date_format_string(strtotime("May 1"), '%B', 99), + 'june' => date_format_string(strtotime("June 1"), '%B', 99), + 'july' => date_format_string(strtotime("July 1"), '%B', 99), + 'august' => date_format_string(strtotime("August 1"), '%B', 99), + 'september' => date_format_string(strtotime("September 1"), '%B', 99), + 'october' => date_format_string(strtotime("October 1"), '%B', 99), + 'november' => date_format_string(strtotime("November 1"), '%B', 99), + 'december' => date_format_string(strtotime("December 1"), '%B', 99) )); $PAGE->requires->yui_module($module, $function, $config); $done = true; diff --git a/lib/moodlelib.php b/lib/moodlelib.php index ff9ecad8897..d6d7253ddc8 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -2083,13 +2083,7 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true, $fixhour // (because it's impossible to specify UTF-8 to fetch locale info in Win32) if (abs($timezone) > 13) { /// Server time - if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) { - $format = textlib::convert($format, 'utf-8', $localewincharset); - $datestring = strftime($format, $date); - $datestring = textlib::convert($datestring, $localewincharset, 'utf-8'); - } else { - $datestring = strftime($format, $date); - } + $datestring = date_format_string($date, $format, $timezone); if ($fixday) { $daystring = ltrim(str_replace(array(' 0', ' '), '', strftime(' %d', $date))); $datestring = str_replace('DD', $daystring, $datestring); @@ -2101,13 +2095,7 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true, $fixhour } else { $date += (int)($timezone * 3600); - if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) { - $format = textlib::convert($format, 'utf-8', $localewincharset); - $datestring = gmstrftime($format, $date); - $datestring = textlib::convert($datestring, $localewincharset, 'utf-8'); - } else { - $datestring = gmstrftime($format, $date); - } + $datestring = date_format_string($date, $format, $timezone); if ($fixday) { $daystring = ltrim(str_replace(array(' 0', ' '), '', gmstrftime(' %d', $date))); $datestring = str_replace('DD', $daystring, $datestring); @@ -2121,6 +2109,44 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true, $fixhour return $datestring; } +/** + * Returns a formatted date ensuring it is UTF-8. + * + * If we are running under Windows convert to Windows encoding and then back to UTF-8 + * (because it's impossible to specify UTF-8 to fetch locale info in Win32). + * + * This function does not do any calculation regarding the user preferences and should + * therefore receive the final date timestamp, format and timezone. Timezone being only used + * to differenciate the use of server time or not (strftime() against gmstrftime()). + * + * @param int $date the timestamp. + * @param string $format strftime format. + * @param int|float $timezone the numerical timezone, typically returned by {@link get_user_timezone_offset()}. + * @return string the formatted date/time. + * @since 2.3.3 + */ +function date_format_string($date, $format, $tz = 99) { + global $CFG; + if (abs($tz) > 13) { + if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) { + $format = textlib::convert($format, 'utf-8', $localewincharset); + $datestring = strftime($format, $date); + $datestring = textlib::convert($datestring, $localewincharset, 'utf-8'); + } else { + $datestring = strftime($format, $date); + } + } else { + if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) { + $format = textlib::convert($format, 'utf-8', $localewincharset); + $datestring = gmstrftime($format, $date); + $datestring = textlib::convert($datestring, $localewincharset, 'utf-8'); + } else { + $datestring = gmstrftime($format, $date); + } + } + return $datestring; +} + /** * Given a $time timestamp in GMT (seconds since epoch), * returns an array that represents the date in user time diff --git a/lib/tests/moodlelib_test.php b/lib/tests/moodlelib_test.php index dadd196a7a9..8e117588868 100644 --- a/lib/tests/moodlelib_test.php +++ b/lib/tests/moodlelib_test.php @@ -1920,4 +1920,40 @@ class moodlelib_testcase extends advanced_testcase { ); $this->assertEquals(convert_to_array($obj), $ar); } + + /** + * Test the function date_format_string(). + */ + function test_date_format_string() { + // Forcing locale and timezone. + $oldlocale = setlocale(LC_TIME, '0'); + setlocale(LC_TIME, 'en_AU.UTF-8'); + $systemdefaulttimezone = date_default_timezone_get(); + date_default_timezone_set('Australia/Perth'); + + // Note: date_format_string() uses the timezone only to differenciate + // the server time from the UTC time. It does not modify the timestamp. + // Hence similar results for timezones <= 13. + $str = date_format_string(1293876000, '%A, %d %B %Y, %I:%M %p', 99); + $this->assertEquals($str, 'Saturday, 01 January 2011, 06:00 PM'); + + $str = date_format_string(1293876000, '%A, %d %B %Y, %I:%M %p', 0); + $this->assertEquals($str, 'Saturday, 01 January 2011, 10:00 AM'); + + $str = date_format_string(1293876000, '%A, %d %B %Y, %I:%M %p', -12); + $this->assertEquals($str, 'Saturday, 01 January 2011, 10:00 AM'); + + $str = date_format_string(1293876000, 'Žluťoučký koníček %A', 99); + $this->assertEquals($str, 'Žluťoučký koníček Saturday'); + + $str = date_format_string(1293876000, '言語設定言語 %A', 99); + $this->assertEquals($str, '言語設定言語 Saturday'); + + $str = date_format_string(1293876000, '简体中文简体 %A', 99); + $this->assertEquals($str, '简体中文简体 Saturday'); + + // Restore system default values. + date_default_timezone_set($systemdefaulttimezone); + setlocale(LC_TIME, $oldlocale); + } }