private async Task UpdateExceptionsAsync(string id, IAppointmentSchedule schedule, bool force) { var exceptions = schedule.Recurrence.Exceptions.Where(kv => kv.Value != null); foreach (var kv in exceptions) { using (Logger.Scope($"GoogleCalendar.UpdateException({kv.Key.Date})")) { EventsResource.InstancesRequest instancesRequest = _service.Events.Instances(CalendarId, id); var originalStart = new DateTime(kv.Key.Year, kv.Key.Month, kv.Key.Day, schedule.Start.Hour, schedule.Start.Minute, schedule.Start.Second); TimeSpan utcOffset = schedule.StartTimeZone.GetUtcOffset(originalStart); string offsetFormat = (utcOffset < TimeSpan.Zero ? "\\-" : "") + "hh\\:mm"; instancesRequest.OriginalStart = $"{originalStart:yyyy-MM-ddTHH:mm:ss}{utcOffset.ToString(offsetFormat)}"; Events instances = await instancesRequest.ExecuteAsync().ConfigureAwait(false); Event instance = instances.Items.FirstOrDefault(); if (instance == null) { Logger.Warning($"Failed to find instance of \"{kv.Value}\" at {instancesRequest.OriginalStart} to create an exception"); continue; } if (force || kv.Value.LastModifiedDateTime > (instance.Updated ?? DateTime.MinValue)) { await UpdateAppointmentAsync(instance.Id, instance.Sequence, kv.Value, force).ConfigureAwait(false); } } } }
public static IEnumerable <string> ToRfc5545Rules(this IAppointmentSchedule schedule) { var recurrence = schedule.Recurrence; if (recurrence == null) { yield break; } var sb = new StringBuilder(); sb.Append("RRULE:FREQ="); switch (recurrence.Frequency) { case RecurrenceFrequency.Daily: sb.Append("DAILY"); break; case RecurrenceFrequency.Weekly: sb.Append("WEEKLY"); break; case RecurrenceFrequency.Monthly: sb.Append("MONTHLY"); break; case RecurrenceFrequency.Yearly: sb.Append("YEARLY"); break; } if (recurrence.Count.HasValue) { sb.Append($";COUNT={recurrence.Count.Value}"); } if (recurrence.Interval.HasValue) { sb.Append($";INTERVAL={recurrence.Interval.Value}"); } if (recurrence.Until.HasValue) { sb.Append($";UNTIL={recurrence.Until.Value.Date:yyyyMMddT000000Z}"); // TODO: is UTC okay? } if (recurrence.WeekDay.HasValue) { sb.Append($";BYDAY={ToRfc5545String(recurrence.WeekDay.Value)}"); } if (recurrence.YearMonth.HasValue) { sb.Append($";BYMONTH={recurrence.YearMonth.Value}"); } if (recurrence.MonthDay.HasValue) { sb.Append($";BYMONTHDAY={recurrence.MonthDay.Value}"); } if (recurrence.Exceptions != null) { string startTime = schedule.Start.ToString("HHmmss"); string startTimezone = TZConvert.WindowsToIana(schedule.StartTimeZone.Id); foreach (DateTime exceptionDate in recurrence.Exceptions.Where(kv => kv.Value == null).Select(kv => kv.Key)) { yield return($"EXDATE;TZID={startTimezone}:{exceptionDate:yyyyMMdd}T{startTime}"); } } yield return(sb.ToString()); }