重复发生的事件失去自动时区转换

Recurring events lose automatic timezone conversion

我正在使用 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,事件时间为下午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,事件时间为下午4点,持续时间为3小时。结束日期为28日)

我需要在他们自己的时区向用户显示 DateTime,并且我需要显示从 eventTime 到 endDate 的重复事件

注意我没有在日历上指定时区 属性 可能也很有用,因为它导致发送的电子邮件在 outlook 中显示 "not supported calendar message"。在我删除它之前,它看起来像这样

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

当我打开指定了这个时区的 ical 文件时,它们似乎可以在多日活动中正常工作,但由于我需要它们显示在带有 accept/decline/tentative 按钮的 outlook 中,它不在将其添加回来的问题

我也试过像这样指定日期时间

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

但没有任何变化

编辑:我现在明白这个问题是由于重复发生的事件需要指定时区 here, but I'm not quite sure where the timezone needs to be specified. I went back to adding the vTimeZone back in and validating it through this 网站,并且 iCal 文件似乎缺少 standard/daylight 部分时区块

我也试过将时区指定为 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"));
}

我不太确定从这一点开始纠正 standard/daylight 逻辑错误需要发生什么。

最终编辑:

通读thispost后,我发现这个问题在去年11月就已经解决了。我检查了我们项目中的版本,结果发现一些天才只是直接复制了 dll 而没有通过 nuget 进行设置(以及几年前的版本)。我获取了最新版本,这次指定时区在 Outlook 中没有造成任何问题。我仍在尝试使用 addTimeZone 和 addLocalTimeZone,但我肯定走在正确的轨道上。感谢 rianjs 这个非常有用的库。如果没有它,我不知道如何使用这个疯狂的日历标准。

重复发生的事件总是相对于发送者的时区(或者更确切地说是事件位置),而不是接收者的时区,因为夏令时的变化可能在组织者和不同的接收者之间发生在不同的时间。

所以在大多数情况下,您希望在活动中使用有意义的时区(即不是 UTC)。 然后 Outlook 只是显示事件确实根据给定的时区发生。这表明事件可能并不总是在一天中的同一时间发生。

由于我花了很长时间才弄明白,所以我不妨分享一下我的解决方案,以防其他人遇到这个问题并找到它。

我用两个类型为 utc

的日期时间定义了 DtStart/DtEnd
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 将 "America/Phoenix" tzid 视为 LMT 时间,这给了我一个大约 28 分钟的休息时间......此外,将所有日期视为 GMT 更接近我们在应用程序其余部分中的实现,因此它适用于我的情况

给了我拼凑 Etc/GMT 东西的想法。