Повторяющиеся события теряют автоматическое преобразование часового пояса

Я настраиваю календарь приглашений, используя ical.net. Отправка неповторяющегося события, кажется, работает отлично: я установил дату начала и окончания следующим образом

iCalEvent.DtStart = new CalDateTime(DateTime.SpecifyKind(model.EventTime.Value, DateTimeKind.Utc));
iCalEvent.DtEnd = new CalDateTime(DateTime.SpecifyKind(model.EventTime.Value.AddMinutes(model.DurationMins.Value), DateTimeKind.Utc));

Когда приходит электронное письмо, часовой пояс конвертируется в часовой пояс получателя (часовой пояс -7, eventTime - 4 вечера и продолжительность - 3 часа)

Часовой пояс -7, eventTime 4 часа и продолжительность 3 часа

Тем не менее, когда я беру этот самый точный код и добавляю эту строку к нему

IRecurrencePattern recurrence = new RecurrencePattern(FrequencyType.Daily, 1)
{
    Until = DateTime.SpecifyKind(model.endDate.Value.AddDays(1), DateTimeKind.Utc)
};

iCalEvent.RecurrenceRules = new List<IRecurrencePattern> { recurrence };

Внезапно мой часовой пояс больше не преобразуется при получении электронного письма (часовой пояс -7, eventTime 4 часа и продолжительность 3 часа. EndDate 28-го числа)

Часовой пояс -7, eventTime - 4 вечера, продолжительность - 3 часа. Конечная дата 28 числа

Мне нужно, чтобы DateTime отображался пользователю в его собственном часовом поясе, и мне нужно отображать повторяющиеся события от eventTime до endDate.

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

iCal.AddTimeZone(new VTimeZone("UTC"));

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

Я также пытался указать дату и время, как это

iCalEvent.DtStart = new CalDateTime(leEvent.EventTime.Value, "UTC");

но ничего не изменилось

РЕДАКТИРОВАТЬ: Теперь я понимаю, что проблема связана с повторяющимся событием, нуждающимся в часовом поясе, как указано здесь, но я не совсем уверен, где часовой пояс должен быть указан. Я вернулся к добавлению vTimeZone и проверке его через этот сайт, и кажется, что в файле iCal отсутствует раздел стандартного / дневного света внутри блока часового пояса.

Результат проверки достоверности

Я также попытался указать часовой пояс как GMT и указать часовой пояс как "\"America/Phoenix\"", чтобы tzid получился как TZID:"America/Phoenix" (с кавычками в файле ical.

Это мой код на данный момент, который вызывает проблему.

iCalEvent.DtStart = new CalDateTime(DateTime.SpecifyKind(model.EventTime.Value, DateTimeKind.Utc));
iCalEvent.DtEnd = new CalDateTime(iCalEvent.DtStart.Value.AddMinutes(model.DurationMins.Value));

if (model.EndDate.HasValue)
{
    IRecurrencePattern recurrence = new RecurrencePattern(FrequencyType.Daily, 1)
    {
        Until = DateTime.SpecifyKind(model.MaxDate.Value, DateTimeKind.Utc).ToLocalTime()
    };

    iCalEvent.RecurrenceRules = new List<IRecurrencePattern> { recurrence };

    iCalEvent.DtStart = new CalDateTime(iCalEvent.DtStart.Value.ToLocalTime(), "America/Phoenix");
    iCalEvent.DtEnd = new CalDateTime(iCalEvent.DtEnd.Value.ToLocalTime(), "America/Phoenix");
    iCal.AddTimeZone(new VTimeZone("America/Phoenix"));
}

Я не совсем уверен, что должно произойти, чтобы исправить стандартную / дневную ошибку с этой точки зрения.

ЗАКЛЮЧИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ:

Прочитав этот пост, я обнаружил, что эта проблема уже решена по состоянию на последний ноябрь. Я проверил версию, которая была у нас в нашем проекте, и оказалось, что какой-то гений просто скопировал dll прямо, не настраивая его через nuget (и версию от нескольких лет назад не меньше). Я взял последнюю версию, и на этот раз указание часового пояса не вызвало никаких проблем в перспективе. Я все еще экспериментирую с addTimeZone и addLocalTimeZone, но я определенно на правильном пути. Спасибо rianjs за эту чрезвычайно полезную библиотеку. Я не знаю, как бы я мог работать с этим безумным календарным стандартом без него.

2 ответа

Решение

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

Поэтому в большинстве случаев вы хотите использовать значимый часовой пояс в событии (т.е. не в формате UTC). Затем Outlook просто показывает, что событие действительно происходит в соответствии с заданным часовым поясом. Это указывает на то, что событие не всегда может быть в одно и то же время суток для получателя.

Поскольку мне потребовалось так много времени, чтобы понять, я мог бы также поделиться своим решением на тот случай, если кто-нибудь еще столкнется с этой проблемой и обнаружит ее.

Я определил DtStart/DtEnd с двумя датами времени, которые имели вид utc

calendarEvent.DtStart = new CalDateTime(model.EventTime.Value);
calendarEvent.DtEnd = new CalDateTime(model.EventTime.Value.AddMinutes(model.DurationMins.Value));

который отлично работал на однодневных мероприятиях, но с многодневным я в итоге сделал это

if (model.EndDate.HasValue)
{
    RecurrencePattern recurrence = new RecurrencePattern(FrequencyType.Daily, 1)
    {
        Until = model.EndDate.Value //has kind: Utc
    };

    var timezoneOffsetString = "Etc/GMT";
    if (timezoneOffset > 0) //client time zone offset, calculated through js
    {
        timezoneOffsetString += "-" + timezoneOffset;
    }
    else if (timezoneOffset < 0)
    {
        timezoneOffsetString += "+" + (-1 * timezoneOffset);
    }

    calendar.AddTimeZone(timezoneOffsetString);
    calendarEvent.DtStart = calendarEvent.DtStart.ToTimeZone(timezoneOffsetString);
    calendarEvent.DtEnd = calendarEvent.DtEnd.ToTimeZone(timezoneOffsetString);

    calendarEvent.RecurrenceRules = new List<RecurrencePattern> { recurrence };
}

Он не является полностью защищенным, так как в некоторых местах могут быть странные проблемы с dst, но nodatime рассматривал tzid "Америка / Феникс" как время LMT, которое давало мне время, которое было как 28 минут... Кроме того, рассматривал все даты как GMT ближе к реализации, которую мы имеем в остальной части нашего приложения, так что это сработало для моей ситуации

Это решение дало мне идею собрать воедино материал Etc/GMT.

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