Перейти к содержимому
DedicatedPHP Контакт

Локали, валюты и часовые пояса в PHP без ошибок

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

Схема PHP-приложения, разделяющего язык, региональный формат, валюту и часовой пояс

Сумма, которая меняется при смене языка, дата не в тот день или перевод, меняющий бизнес-правило, обычно указывают на одну и ту же проблему: приложение путает данные с решениями о представлении. Интернационализация дат и валют в PHP требует отдельно обрабатывать язык, региональные настройки, валюту и часовой пояс, а также определять, какое значение сохраняет система и какое представление видит пользователь.

Такое разделение позволяет расширять поддержку регионов, не дублируя бизнес-правила и не переосмысливая исторические данные. Оно также помогает найти источник ошибок: проблема может быть во вводе пользователя, хранении данных, преобразовании времени или только в формате вывода.

Язык, locale, валюта и часовой пояс — разные параметры

Язык, locale, валюта и часовой пояс — разные параметры — guía visual de DedicatedPHP

Язык определяет текст интерфейса и переводимое содержимое, например метки, сообщения валидации и названия товаров. Locale, или региональные настройки, задаёт правила представления: разделители дробной части, порядок даты и названия месяцев. Он не всегда совпадает с языком: в двух регионах с общим языком могут использоваться разные форматы.

Валюта определяет единицу измерения суммы, например EUR или JPY. Её нельзя надёжно вывести из языка или locale. Пользователь может просматривать интерфейс на испанском, использовать определённый региональный формат и совершать покупку в другой валюте. Часовой пояс, в свою очередь, задаёт связь местного времени со всемирным временем и правилами перевода часов в конкретном регионе.

Эти предпочтения следует задавать явно. Например, у учётной записи могут быть язык и часовой пояс, сессия может определять предпочтительный формат, а заказ должен сохранять фактически использованную валюту. Допустимые значения и значения по умолчанию должны определяться продуктом, а не незаметно выводиться из сетевого местоположения.

Что хранить, а что вычислять для отображения

Сохраняйте данные, необходимые для восстановления исходного события, а не только уже отформатированную строку. Дата создания обозначает момент времени; строка вроде «03/04/2025» неоднозначна и не подходит в качестве канонического представления. Для глобальных событий обычно удобно хранить момент времени в UTC и сохранять соответствующий часовой пояс, если от него зависит контекст, как в случае встречи, назначенной в конкретном городе.

В PHP-приложении DateTimeImmutable помогает избежать случайных изменений при преобразованиях. При подготовке ответа преобразуйте момент времени в выбранный часовой пояс, не подменяя сохранённые данные. Используйте распознаваемые идентификаторы часовых поясов, например Europe/Madrid, вместо фиксированного смещения вроде +01:00: смещение не содержит исторических правил и сезонных изменений.

Для регионального формата храните метку locale, допустимую в используемой библиотеке и среде, и явно обрабатывайте неподдерживаемые предпочтения. Функции расширения intl, такие как IntlDateFormatter и NumberFormatter, позволяют применять региональные правила без ручной склейки разделителей и названий месяцев. Убедитесь, что расширение доступно во всех средах, где запускается приложение.

Даты и время: преобразование и неоднозначные случаи

Зарегистрированные системой моменты времени и гражданское местное время — не одно и то же. Момент «2025-04-10T15:00:00Z» однозначен. А «2025-10-26 в 02:30 в Europe/Madrid» может быть неоднозначным при переходе на зимнее время, поскольку это местное время может наступить дважды. При весеннем переходе некоторые значения местного времени не существуют.

Чтобы запланировать действие на будущее местное время, не сохраняйте только timestamp, рассчитанный один раз, если обязательство привязано к местным часам конкретного региона. Сохраняйте запрошенные дату и время, часовой пояс и правило обработки несуществующих или повторяющихся значений времени. Решение — отклонить запрос, попросить уточнение или выбрать одно из повторяющихся значений местного времени — зависит от продукта. Для уже произошедшего события, напротив, фиксируйте фактический момент времени.

Также определите, как интерпретировать даты, полученные из форм и API. Принимайте документированные форматы, проверяйте часовой пояс и отклоняйте неоднозначный ввод, а не угадывайте, означает ли «04/05/2025» апрель или май. В интерфейсе показывайте удобное для чтения представление, но сохраняйте канонические данные для сортировки, сравнения и аудита.

Суммы: точность, валюта и форматирование

Отображаемый формат не должен становиться источником истины для финансовых данных. Не используйте двоичные числа с плавающей точкой для денежных расчётов: некоторые десятичные дроби нельзя представить точно, что может привести к ошибкам округления. Распространённый подход — хранить суммы целыми числами в минимальных денежных единицах вместе с кодом валюты. Однако не все валюты используют два десятичных знака, а для некоторых расчётов требуется большая промежуточная точность, чем у итоговой суммы к оплате.

Определяйте точность и момент округления в соответствии с правилами предметной области: для каждой позиции, налога или общей суммы. Явно указывайте валюту в заказах, платежах, возвратах и расчётах; не интерпретируйте число, не зная, к какой валюте оно относится. При конвертации валют также сохраняйте данные, необходимые для объяснения пересчёта, например применённый курс и время, к которому он относится, если это важно для операции.

При отображении передавайте региональному форматтеру числовое значение и код валюты. Представление может различаться символами, их расположением и разделителями. Пользователь должен иметь возможность определить валюту, не полагаясь на неоднозначный символ. Не разбирайте локализованную строку так, словно это универсальное число: проверьте ввод и преобразуйте его в контролируемое числовое представление перед обработкой.

Перевод содержимого без дублирования бизнес-правил

Переводите тексты и адаптируйте форматы, но централизуйте правила, определяющие цены, налоги, соответствие критериям, права или статусы. Дублирование логики для разных языков приводит к расхождениям в поведении, которые трудно обнаружить. Выбор тарифа может зависеть от рынка, договора или коммерческой политики; он не должен меняться только из-за смены метки интерфейса.

Отделяйте каталоги переводов от доменной логики. Для редактируемого локализованного содержимого определите, какие версии могут существовать, как обрабатываются отсутствующие версии и какое поведение используется в качестве запасного варианта. Переведённое название не должно заменять стабильный идентификатор. В API документируйте, содержат ли поля канонические значения, локализованное содержимое или уже подготовленные для отображения форматы.

Тестирование и постепенное развёртывание региональной поддержки

Проверяйте решения на разных уровнях. Модульные тесты должны проверять преобразования часовых поясов, валидацию дат, округление и форматирование сумм. Добавьте случаи на границах суток, переходы на сезонное время, повторяющиеся и несуществующие часы, месяцы разной продолжительности и валюты с разной точностью. Не полагайтесь на locale или часовой пояс по умолчанию в тестовой среде: задавайте их явно.

Интеграционные тесты должны подтверждать, что API сохраняет канонические данные, а интерфейс показывает их с учётом согласованных предпочтений. Также проверяйте некорректный ввод, неизвестные локали, изменение предпочтений и отсутствие необходимого расширения. При обновлении баз часовых поясов проверяйте процессы, планирующие будущие события, и ожидаемые результаты.

Подключайте поддержку регионов постепенно: сначала определите данные и правила, затем протестируйте форматы и сквозные сценарии и, наконец, включите пользовательский интерфейс для целевой аудитории. Мониторинг ошибок валидации, расхождений при округлении и задач, выполненных не по расписанию, помогает обнаружить проблемы, незаметные на скриншоте.

Контрольный список

Контрольный список — guía visual de DedicatedPHP
  • Язык: отделён ли он от locale и предусмотрен ли запасной вариант?
  • Даты: различаются ли момент времени и запланированное местное время?
  • Часовой пояс: сохраняются ли региональные идентификаторы и обрабатываются ли неоднозначные значения времени?
  • Суммы: указана ли валюта для каждой суммы явно и определены ли правила точности?
  • Представление: используются ли подходящие инструменты форматирования и исключено ли использование отображаемого текста для расчётов?
  • Тесты: проверяются ли границы суток, переводы часов, некорректный ввод и разные предпочтения?
  • Эксплуатация: проверяется ли конфигурация PHP и внедряется ли региональная поддержка контролируемым образом?

Главное — чётко отделять данные, которые понимает система, от способа их отображения для каждого человека. Благодаря этой границе интернационализация дат и валют в PHP превращается в набор проверяемых правил, а не в коллекцию исключений, разбросанных по приложению.

Хотите применить эти идеи в своем проекте?Давайте обсудим вашу PHP-платформу.
Посмотреть связанные услуги