strftime() возвращает неправильный предпочтительный формат времени

Я получил PHP 7.0.8 (FPM), работающий на FreeBSD 10.1 и nginx. Мне нужно отображать время в предпочитаемом формате в зависимости от страны, где проживает пользователь.

setlocale(LC_ALL, "ru_RU.UTF-8");
date_default_timezone_set("Europe/Moscow");
echo strftime('%X', time());
// Returns 21:23:12 (correct) because 24-hr format is preferred in Russia.

setlocale(LC_ALL, "en_US.UTF-8");
date_default_timezone_set("America/New_York");
echo strftime('%X', time());
// Returns 21:23:12 (incorrect) must return 9:23:12 pm as preferred format in U.S.

Это похоже на проблему с моим сервером или версией PHP, потому что другие пользователи получают правильные результаты.

locale -a возврат содержит оба ru_RU.UTF-8 а также en_US.UTF-8,

echo setlocale(LC_ALL, "en_US.UTF-8") возвращает правильный язык

Специальная конфигурация не применяется.

Пожалуйста, помогите мне решить эту проблему. Благодарю.

% X Предпочитаемое представление времени на основе локали без даты

PS Предпочитаемая дата %x работает правильно, отображая дд.мм.гггг для России и мм / дд / гггг для США

2 ответа

Решение

То же самое во FreeBSD 10.3:

php -r 'date_default_timezone_set("Europe/Paris"); var_dump(setlocale(LC_ALL, "en_US.UTF-8"), strftime("%X", time()));'
string(11) "en_US.UTF-8"
string(8) "15:03:07"

Первый, ls -l /usr/share/locale/en_US.UTF-8/LC_TIME возвращает:

/usr/share/locale/en_US.UTF-8/LC_TIME@ -> ../en_US.ISO8859-1/LC_TIME

Таким образом, en_US.UTF-8 фактически является символической ссылкой на en_US.ISO8859-1.

Затем, если мы посмотрим в /usr/src/share/timedef/en_US.ISO8859-1.src (вам нужны установленные источники), мы найдем:

#
# X_fmt
#
%H:%M:%S

Что объясняет фактический результат, когда вы ожидаете %I:%M:%S %p (или же %r).

Возможные решения:

  • заполнить отчет об ошибке, если вы считаете, что это актуально и / или 1 патч файла выше, а затем восстановить мир (я думаю)
  • обработать этот конкретный случай:

    echo strftime(0 === strpos(setlocale(LC_ALL, '0'), 'en_US') ? '%r' : '%X');
    
  • предпочитают использовать http://php.net/IntlDateFormatter, который не зависит от системных локалей (предполагается библиотекой ICU). Например:

    $timefmt = new IntlDateFormatter('en_US', IntlDateFormatter::NONE, IntlDateFormatter::MEDIUM);
    $timefmt->format(date_create());
    

1 кажется, что X_fmt ценится до %I:%M:%S %p в багажнике и 11-СТАБИЛЬНО

Обновить:

  • изменение коммита X_fmt был отменен с тех пор (т.е. во FreeBSD >= 11, X_fmt по-прежнему определяется как %H:%M:%S)
  • в FreeBSD 11 файл, определяющий форматы времени, имеет вид /usr/src/share/timedef/en_US.UTF-8.src (символическая ссылка на локаль en_US.ISO8859-1 пропала)

Выдержка из /usr/share/i18n/locales/en_US на Ubuntu 12.04:

% Appropriate time representation (%X)
%       "%r"
t_fmt   "<U0025><U0072>"
%
% Appropriate AM/PM time representation (%r)
%       "%I:%M:%S %p"
t_fmt_ampm "<U0025><U0049><U003A><U0025><U004D><U003A><U0025><U0053><U0020>/
<U0025><U0070>"

Пожалуйста, обратите внимание %I в дату AM/PM для%r.

%X в Юникоде 25 70, который %P,

И из man date (лишен для простоты):

%H     hour (00..23)

%I     hour (01..12)

%p     locale's equivalent of either AM or PM; blank if not known

%P     like %p, but lower case

%r     locale's 12-hour clock time (e.g., 11:11:04 PM)

%R     24-hour hour and minute; same as %H:%M

%x     locale's date representation (e.g., 12/31/99)

%X     locale's time representation (e.g., 23:13:48)

Читая весь этот файл, он должен работать как положено, поэтому я подозреваю, что ваша установка использует другой файл локали или откат к C locale (например, если там нет файла locale)

Теперь для setlocale, он вернет false только в случае, если вы дадите неверную переменную (т.е. LCAL вместо LCALL) но вернет то, что система возвращает для других случаев:

Примечание. Возвращаемое значение setlocale() зависит от системы, в которой работает PHP. Он возвращает именно то, что возвращает системная функция setlocale.

На "linux" setlocale возвращается NULL который не всегда воспринимается как ложный (см. здесь), что может быть источником вашей проблемы, я не могу поклясться, поскольку у меня нет FreeBSD, чтобы подтвердить это.

Другие вопросы по тегам