Экспорт календаря/события в ICS: неверное время (+1 ч) при импорте в Outlook с TZID=Europe/Berlin

Версия: Discourse 2026.1.5 (ESR), плагин discourse-calendar

Краткое описание
Созданные события с установленным часовым поясом (timezone="Europe/Berlin" и showLocalTime="true") отображают время с ошибкой +1 час при скачивании файла .ics и его импорте в Outlook (Windows). В самом форуме время отображается корректно. Проблема затрагивает только новые события, то есть импорт через файл .ics.

Воспроизведение

  1. Создайте событие (сегодня, в период летнего времени CEST/UTC+2): 17:00 – 19:15 по берлинскому времени.
[event start="2026-08-11 17:00" status="public" name="testevent 2" timezone="Europe/Berlin" showLocalTime="true" end="2026-08-11 19:15"]
[/event]

  1. «Добавить в календарь» → скачать файл .ics.
  2. Импортируйте файл в Outlook.

Ожидаемый результат: 11.08.2026, 17:00 – 19:15
Фактический результат: 11.08.2026, 18:00 – 20:15 (+1 час)

Содержимое ICS (релевантные части):

DTSTART;TZID=Europe/Berlin:20260811T170000
DTEND;TZID=Europe/Berlin:20260811T191500

(Файл не содержит блока VTIMEZONE для Europe/Berlin.)

Анализ / Предполагаемая причина
При экспорте время указывается локально с использованием TZID=Europe/Berlin (название IANA) вместо UTC (...Z). Outlook не понимает названия часовых поясов IANA (он использует идентификаторы Windows, такие как «W. Europe Standard Time») и, при отсутствии определения VTIMEZONE, использует фиксированное смещение UTC+1 (CET/зимнее время). В период летнего времени (CEST = UTC+2) это приводит к ошибке ровно +1 час. Перекрестная проверка: импорт того же файла в Google Calendar (который нативно поддерживает часовые пояса IANA) показывает корректное время 17:00.

Предложение: экспорт ICS должен либо использовать временные метки UTC с суффиксом Z, либо генерировать полный блок VTIMEZONE, включающий правила перехода на летнее время (см. также обсуждение соответствия спецификации ICS в теме LOCATION is not available in full ICS export).

Дополнительное наблюдение: Если то же самое событие создается без параметров timezone=/showLocalTime, то экспортируемый файл .ics использует UTC, и Outlook показывает +2 часа (поскольку 17:00 UTC = 19:00 CEST). Это документированное поведение для UTC, но оно дополнительно демонстрирует, что обработка часовых поясов при экспорте ICS вызывает путаницу у пользователей, ожидающих отображения локального времени.

2 лайка

Для сравнения, я запускал свой хост Discourse и контейнер приложения в локальной часовой зоне IANA, а не в UTC, из-за предыдущего поведения часовых поясов календаря.

Мой хост настроен с помощью:

timedatectl set-timezone Europe/London

а в моем app.yml содержится:

- exec: ln -fs /usr/share/zoneinfo/Europe/London /etc/localtime
- exec: dpkg-reconfigure --frontend noninteractive tzdata

Это означает, что и мой хост, и контейнер Discourse используют Europe/London, включая автоматическое переключение между GMT и BST.

Возможно, стоит протестировать аналогичную настройку с Europe/Berlin в вашей установке, чтобы проверить, правильно ли импортируется результирующий файл .ics в Outlook:

timedatectl set-timezone Europe/Berlin

и, в разделе run:,

- exec: ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime
- exec: dpkg-reconfigure --frontend noninteractive tzdata

Меня бы интересовало, изменяет ли это импорт вашего события в 17:00 по берлинскому времени с 18:00 на ожидаемые 17:00.

Если да, это может указывать на то, что часовой пояс Discourse/контейнера влияет на экспорт; если нет, то проблема с отсутствующим VTIMEZONE/обработкой в Outlook, вероятно, не зависит от часового пояса сервера.

Мы также сталкиваемся именно с этой проблемой.

Воспроизведение:

  • Событие создано с timezone="Europe/Berlin" и showLocalTime="true", в период действия CEST (летнего времени).
  • Файл .ics был скачан через «Добавить в календарь» и импортирован в Outlook.

Фактический результат: Время события отображается со сдвигом на +1 час (например, 17:00 по берлинскому времени отображается в Outlook как 18:00).
Ожидаемый результат: Время события должно отображаться как 17:00, как было введено.

Мы можем подтвердить, что это происходит последовательно, а не периодически, для событий, происходящих в период CEST. Другие события, вне периода CEST, не затронуты.

Мы были бы очень рады, если бы эта проблема была исправлена, поскольку наши пользователи могут быть очень чувствительны к сбоям :see_no_evil_monkey:

Я провёл более глубокое расследование и открыл PR для решения этой проблемы:

Проблема заключается не в часовом поясе сервера/контейнера, а в экспорте ICS. Экспортируемое событие использует IANA TZID, например Europe/Berlin, но в настоящее время не включает соответствующее определение VTIMEZONE, которое требуется клиентам, таким как Outlook, для надёжной интерпретации правил перехода на летнее время.

В PR добавлены определения VTIMEZONE для загрузок ICS с учётом часового пояса при сохранении существующих локальных значений DTSTART/DTEND.

Для примера из этой темы экспорт теперь включает правила применения CET/CEST для Europe/Berlin, поэтому:

DTSTART;TZID=Europe/Berlin:20260811T170000

может быть интерпретирован с правильным летним смещением UTC+2, а не с откатом Outlook к UTC+1.

Я также добавил покрытие для правил перехода на летнее время в Европе и Северной Америке, случай с фиксированным смещением и более необычные сезонные переходы, используемые в Africa/Casablanca.

2 лайка

@Michael_D @Tonja исправление было принято, скоро появится в latest :+1:

1 лайк

Я следил за пайплайном, пока ты печатал. Исправление уже в latest. Спасибо за твой вклад @Ethsim2!

1 лайк

Большое спасибо @Ethsim2 и @tannerabread :partying_face:

2 лайка