/// <summary> /// Ensures the properties. /// </summary> private void EnsureProperties( ) { if (string.IsNullOrEmpty(Uid)) { // Create a new UID for the component Uid = new UidFactory( ).Build( ); } // NOTE: removed setting the 'CREATED' property here since it breaks serialization. // See https://sourceforge.net/projects/dday-ical/forums/forum/656447/topic/3754354 if (DtStamp == null) { // Here, we don't simply set to DateTime.Now because DateTime.Now contains milliseconds, and // the iCalendar standard doesn't care at all about milliseconds. Therefore, when comparing // two calendars, one generated, and one loaded from file, they may be functionally identical, // but be determined to be different due to millisecond differences. // // NOTE: also ensure we're in UTC, so our CLR implementation closely matches the RFC. // See bug #3485766. DateTime now = DateTime.UtcNow; DtStamp = new iCalDateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second) { IsUniversalTime = true }; } }
/// <summary> /// Converts to I date time. /// </summary> /// <param name="dt">The date time.</param> /// <param name="referenceDate">The reference date.</param> /// <returns></returns> protected IDateTime ConvertToIDateTime(DateTime dt, IDateTime referenceDate) { IDateTime newDt = new iCalDateTime(dt, referenceDate.TzId); newDt.AssociateWith(referenceDate); return(newDt); }
/// <summary> /// Evaluates the specified start date. /// </summary> /// <param name="startDate">The start date.</param> /// <param name="fromDate">From date.</param> /// <param name="endDate">The end date.</param> /// <returns></returns> public List <Period> Evaluate(iCalDateTime startDate, iCalDateTime fromDate, iCalDateTime endDate) { var periods = new List <Period>( ); if (startDate > fromDate) { fromDate = startDate; } if (endDate < fromDate || fromDate > endDate) { return(periods); } foreach (Period p in Periods) { if (!periods.Contains(p)) { periods.Add(p); } } return(periods); }
/// <summary> /// Associates the with. /// </summary> /// <param name="dt">The date time.</param> public void AssociateWith(IDateTime dt) { if (AssociatedObject == null && dt.AssociatedObject != null) { AssociatedObject = dt.AssociatedObject; } else if (AssociatedObject != null && dt.AssociatedObject == null) { dt.AssociatedObject = AssociatedObject; } // If these share the same TZID, then let's see if we // can share the time zone observance also! if (TzId != null && string.Equals(TzId, dt.TzId)) { if (TimeZoneObservance != null && dt.TimeZoneObservance == null) { IDateTime normalizedDt = new iCalDateTime(TimeZoneObservance.Value.TimeZoneInfo.OffsetTo.ToUtc(dt.Value)); if (TimeZoneObservance.Value.Contains(normalizedDt)) { dt.TimeZoneObservance = TimeZoneObservance; } } else if (dt.TimeZoneObservance != null && TimeZoneObservance == null) { IDateTime normalizedDt = new iCalDateTime(dt.TimeZoneObservance.Value.TimeZoneInfo.OffsetTo.ToUtc(Value)); if (dt.TimeZoneObservance.Value.Contains(normalizedDt)) { TimeZoneObservance = dt.TimeZoneObservance; } } } }
/// <summary> /// Creates the period. /// </summary> /// <param name="dt">The date time.</param> /// <param name="referenceDate">The reference date.</param> /// <returns></returns> private IPeriod CreatePeriod(DateTime dt, IDateTime referenceDate) { // Turn each resulting date/time into an IDateTime and associate it // with the reference date. IDateTime newDt = new iCalDateTime(dt, referenceDate.TzId); // NOTE: fixes bug #2938007 - hasTime missing newDt.HasTime = referenceDate.HasTime; newDt.AssociateWith(referenceDate); // Create a period from the new date/time. return(new Period(newDt)); }
/// <summary> /// Determines whether the specified <see cref="System.Object" /> is equal to this instance. /// </summary> /// <param name="obj"> /// The <see cref="System.Object" /> to compare with this instance. /// </param> /// <returns> /// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>. /// </returns> public override bool Equals(object obj) { var dateTime = obj as IDateTime; if (dateTime != null) { AssociateWith(dateTime); return(dateTime.Utc.Equals(Utc)); } if (obj is DateTime) { var dt = new iCalDateTime(( DateTime )obj); AssociateWith(dt); return(Equals(dt.Utc, Utc)); } return(false); }
/// <summary> /// Converts from the system time zone. /// </summary> /// <param name="tzinfo">The time zone info.</param> /// <param name="earliestDateTimeToSupport">The earliest date time to support.</param> /// <param name="includeHistoricalData"> /// if set to <c>true</c> [include historical data]. /// </param> /// <returns></returns> public static iCalTimeZone FromSystemTimeZone(TimeZoneInfo tzinfo, DateTime earliestDateTimeToSupport, bool includeHistoricalData) { TimeZoneInfo.AdjustmentRule[] adjustmentRules = tzinfo.GetAdjustmentRules( ); TimeSpan utcOffset = tzinfo.BaseUtcOffset; var tz = new iCalTimeZone { TzId = tzinfo.Id }; IDateTime earliest = new iCalDateTime(earliestDateTimeToSupport); foreach (TimeZoneInfo.AdjustmentRule adjustmentRule in adjustmentRules) { // Only include historical data if asked to do so. Otherwise, // use only the most recent adjustment rule available. if (!includeHistoricalData && adjustmentRule.DateEnd < earliestDateTimeToSupport) { continue; } TimeSpan delta = adjustmentRule.DaylightDelta; var tzinfoStandard = new iCalTimeZoneInfo { Name = "STANDARD", TimeZoneName = tzinfo.StandardName, Start = new iCalDateTime(new DateTime(adjustmentRule.DateStart.Year, adjustmentRule.DaylightTransitionEnd.Month, adjustmentRule.DaylightTransitionEnd.Day, adjustmentRule.DaylightTransitionEnd.TimeOfDay.Hour, adjustmentRule.DaylightTransitionEnd.TimeOfDay.Minute, adjustmentRule.DaylightTransitionEnd.TimeOfDay.Second).AddDays(1)) }; if (tzinfoStandard.Start.LessThan(earliest)) { tzinfoStandard.Start = tzinfoStandard.Start.AddYears(earliest.Year - tzinfoStandard.Start.Year); } tzinfoStandard.OffsetFrom = new UtcOffset(utcOffset + delta); tzinfoStandard.OffsetTo = new UtcOffset(utcOffset); PopulateiCalTimeZoneInfo(tzinfoStandard, adjustmentRule.DaylightTransitionEnd); // Add the "standard" time rule to the time zone tz.AddChild(tzinfoStandard); if (tzinfo.SupportsDaylightSavingTime) { var tzinfoDaylight = new iCalTimeZoneInfo { Name = "DAYLIGHT", TimeZoneName = tzinfo.DaylightName, Start = new iCalDateTime(new DateTime(adjustmentRule.DateStart.Year, adjustmentRule.DaylightTransitionStart.Month, adjustmentRule.DaylightTransitionStart.Day, adjustmentRule.DaylightTransitionStart.TimeOfDay.Hour, adjustmentRule.DaylightTransitionStart.TimeOfDay.Minute, adjustmentRule.DaylightTransitionStart.TimeOfDay.Second)) }; if (tzinfoDaylight.Start.LessThan(earliest)) { tzinfoDaylight.Start = tzinfoDaylight.Start.AddYears(earliest.Year - tzinfoDaylight.Start.Year); } tzinfoDaylight.OffsetFrom = new UtcOffset(utcOffset); tzinfoDaylight.OffsetTo = new UtcOffset(utcOffset + delta); PopulateiCalTimeZoneInfo(tzinfoDaylight, adjustmentRule.DaylightTransitionStart); // Add the "daylight" time rule to the time zone tz.AddChild(tzinfoDaylight); } } // If no time zone information was recorded, at least // add a STANDARD time zone element to indicate the // base time zone information. if (tz.TimeZoneInfos.Count == 0) { var tzinfoStandard = new iCalTimeZoneInfo { Name = "STANDARD", TimeZoneName = tzinfo.StandardName, Start = earliest, OffsetFrom = new UtcOffset(utcOffset), OffsetTo = new UtcOffset(utcOffset) }; // Add the "standard" time rule to the time zone tz.AddChild(tzinfoStandard); } return(tz); }
/// <summary> /// Processes the recurrence pattern. /// </summary> /// <param name="referenceDate">The reference date.</param> /// <returns></returns> private IRecurrencePattern ProcessRecurrencePattern(IDateTime referenceDate) { var r = new RecurrencePattern( ); r.CopyFrom(Pattern); // Convert the UNTIL value to a local date/time based on the time zone information that // is in the reference date if (r.Until != DateTime.MinValue) { // Build an iCalDateTime with the correct time zone & calendar var until = new iCalDateTime(r.Until, referenceDate.TzId) { AssociatedObject = referenceDate.AssociatedObject }; // Convert back to local time so time zone comparisons match r.Until = until.Local; } if (r.Frequency > FrequencyType.Secondly && r.BySecond.Count == 0 && referenceDate.HasTime /* NOTE: Fixes a bug where all-day events have BySecond/ByMinute/ByHour added incorrectly */) { r.BySecond.Add(referenceDate.Second); } if (r.Frequency > FrequencyType.Minutely && r.ByMinute.Count == 0 && referenceDate.HasTime /* NOTE: Fixes a bug where all-day events have BySecond/ByMinute/ByHour added incorrectly */) { r.ByMinute.Add(referenceDate.Minute); } if (r.Frequency > FrequencyType.Hourly && r.ByHour.Count == 0 && referenceDate.HasTime /* NOTE: Fixes a bug where all-day events have BySecond/ByMinute/ByHour added incorrectly */) { r.ByHour.Add(referenceDate.Hour); } // If BYDAY, BYYEARDAY, or BYWEEKNO is specified, then // we don't default BYDAY, BYMONTH or BYMONTHDAY if (r.ByDay.Count == 0) { // If the frequency is weekly, use the original date's day of week. // NOTE: fixes WeeklyCount1() and WeeklyUntil1() handling // If BYWEEKNO is specified and BYMONTHDAY/BYYEARDAY is not specified, // then let's add BYDAY to BYWEEKNO. // NOTE: fixes YearlyByWeekNoX() handling if (r.Frequency == FrequencyType.Weekly || ( r.ByWeekNo.Count > 0 && r.ByMonthDay.Count == 0 && r.ByYearDay.Count == 0 )) { r.ByDay.Add(new WeekDay(referenceDate.DayOfWeek)); } // If BYMONTHDAY is not specified, // default to the current day of month. // NOTE: fixes YearlyByMonth1() handling, added BYYEARDAY exclusion // to fix YearlyCountByYearDay1() handling if (r.Frequency > FrequencyType.Weekly && r.ByWeekNo.Count == 0 && r.ByYearDay.Count == 0 && r.ByMonthDay.Count == 0) { r.ByMonthDay.Add(referenceDate.Day); } // If BYMONTH is not specified, default to // the current month. // NOTE: fixes YearlyCountByYearDay1() handling if (r.Frequency > FrequencyType.Monthly && r.ByWeekNo.Count == 0 && r.ByYearDay.Count == 0 && r.ByMonth.Count == 0) { r.ByMonth.Add(referenceDate.Month); } } return(r); }