public static DateTimeOffset ToDateTimeOffset(this DateTime dt, TimeZoneInfo tz) { if (dt.Kind != DateTimeKind.Unspecified) { // Handle UTC or Local kinds (regular and hidden 4th kind) DateTimeOffset dto = new DateTimeOffset(dt.ToUniversalTime(), TimeSpan.Zero); return(TimeZoneInfo.ConvertTime(dto, tz)); } if (tz.IsAmbiguousTime(dt)) { // Prefer the daylight offset, because it comes first sequentially (1:30 ET becomes // 1:30 EDT) TimeSpan[] offsets = tz.GetAmbiguousTimeOffsets(dt); TimeSpan offset = offsets[0] > offsets[1] ? offsets[0] : offsets[1]; return(new DateTimeOffset(dt, offset)); } if (tz.IsInvalidTime(dt)) { // Advance by the gap, and return with the daylight offset (2:30 ET becomes 3:30 EDT) TimeSpan[] offsets = { tz.GetUtcOffset(dt.AddDays(-1)), tz.GetUtcOffset(dt.AddDays(1)) }; TimeSpan gap = offsets[1] - offsets[0]; return(new DateTimeOffset(dt.Add(gap), offsets[1])); } // Simple case return(new DateTimeOffset(dt, tz.GetUtcOffset(dt))); }
/// <summary> /// Gets <see cref="DateTimeOffset"/> list for specified <see cref="DateTimeOffset"/> in the specified <see cref="TimeZoneInfo"/>. /// If the result contains two DateTimeOffsets, the index-1 contains standard time. /// </summary> /// <param name="dateTime"><see cref="DateTime"/> to calculate <see cref="DateTimeOffset"/>. /// <see cref="DateTimeKind"/> is important because there are ambiguous datetimes in some timezones(that has daylight saving time). /// For <see cref="DateTimeKind.Utc"/>, only one <see cref="DateTimeOffset"/> is in the returned list. /// For <see cref="DateTimeKind.Unspecified"/> or <see cref="DateTimeKind.Local"/>, there is a case that two <see cref="DateTimeOffset"/> items are returned when the datetime is ambiguous. /// For <see cref="DateTimeKind.Local"/>, there are more complicated situations that local time zone also have ambiguous datetimes. /// </param> /// <param name="timeZoneInfo"><see cref="TimeZoneInfo"/> to calculate <see cref="DateTimeOffset"/>.</param> /// <returns><see cref="DateTimeOffset"/>.</returns> /// <remarks> /// <see cref="DateTimeKind"/> is important because there are ambiguous datetimes in some timezones(that has daylight saving time). /// For <see cref="DateTimeKind.Utc"/>, only one <see cref="DateTimeOffset"/> is in the returned list. /// For <see cref="DateTimeKind.Unspecified"/> or <see cref="DateTimeKind.Local"/>, there is a case that two <see cref="DateTimeOffset"/> items are returned when the datetime is ambiguous. /// For <see cref="DateTimeKind.Local"/>, there are more complicated situations that local time zone also have ambiguous datetimes. /// </remarks> /// <exception cref="ArgumentException">The dateTime parameter represents an invalid time.</exception> /// <exception cref="ArgumentNullException">The timeZoneInfo parameter is null.</exception> public static DateTimeOffset[] GetDateTimeOffsets(DateTime dateTime, TimeZoneInfo timeZoneInfo) { if (timeZoneInfo == null) { throw new ArgumentNullException("timeZoneInfo"); } if (dateTime.Kind == DateTimeKind.Utc || !(timeZoneInfo.SupportsDaylightSavingTime)) { return(new DateTimeOffset[] { GetDateTimeOffset(dateTime, timeZoneInfo) }); } DateTime dateTimeAdjusted = dateTime; if (dateTime.Kind == DateTimeKind.Local && !(TimeZoneInfo.Local.Equals(timeZoneInfo))) { dateTimeAdjusted = TimeZoneInfo.ConvertTime(dateTime, TimeZoneInfo.Local, timeZoneInfo); } if (dateTimeAdjusted.Kind != DateTimeKind.Unspecified) { dateTimeAdjusted = DateTime.SpecifyKind(dateTimeAdjusted, DateTimeKind.Unspecified); } if (TimeZoneInfo.Utc.Equals(timeZoneInfo)) { return(new DateTimeOffset[] { new DateTimeOffset(dateTimeAdjusted, TimeSpan.Zero) }); } else if (timeZoneInfo.IsInvalidTime(dateTimeAdjusted)) { throw new ArgumentException(ResourceMessage.ErrorMessages.InvalidDateTime, "dateTime"); } else if (!(timeZoneInfo.IsAmbiguousTime(dateTimeAdjusted))) { return(new DateTimeOffset[] { new DateTimeOffset(dateTimeAdjusted, timeZoneInfo.GetUtcOffset(dateTimeAdjusted)) }); } else { var timeSpans = timeZoneInfo.GetAmbiguousTimeOffsets(dateTimeAdjusted); var results = new List <DateTimeOffset>(2); var baseOffset = timeZoneInfo.BaseUtcOffset; foreach (var item in timeSpans) { if (item == baseOffset) { results.Insert(0, new DateTimeOffset(dateTimeAdjusted, item)); } else { results.Add(new DateTimeOffset(dateTimeAdjusted, item)); } } return(results.ToArray()); } }
// <Snippet1> private void ShowPossibleUtcTimes(DateTime ambiguousTime, TimeZoneInfo timeZone) { // Determine if time is ambiguous in target time zone if (!timeZone.IsAmbiguousTime(ambiguousTime)) { Console.WriteLine("{0} is not ambiguous in time zone {1}.", ambiguousTime, timeZone.DisplayName); } else { // Display time and its time zone (local, UTC, or indicated by timeZone argument) string originalTimeZoneName; if (ambiguousTime.Kind == DateTimeKind.Utc) { originalTimeZoneName = "UTC"; } else if (ambiguousTime.Kind == DateTimeKind.Local) { originalTimeZoneName = "local time"; } else { originalTimeZoneName = timeZone.DisplayName; } Console.WriteLine("{0} {1} maps to the following possible times:", ambiguousTime, originalTimeZoneName); // Get ambiguous offsets TimeSpan[] offsets = timeZone.GetAmbiguousTimeOffsets(ambiguousTime); // Handle times not in time zone of timeZone argument // Local time where timeZone is not local zone if ((ambiguousTime.Kind == DateTimeKind.Local) && !timeZone.Equals(TimeZoneInfo.Local)) { ambiguousTime = TimeZoneInfo.ConvertTime(ambiguousTime, TimeZoneInfo.Local, timeZone); } // UTC time where timeZone is not UTC zone else if ((ambiguousTime.Kind == DateTimeKind.Utc) && !timeZone.Equals(TimeZoneInfo.Utc)) { ambiguousTime = TimeZoneInfo.ConvertTime(ambiguousTime, TimeZoneInfo.Utc, timeZone); } // Display each offset and its mapping to UTC foreach (TimeSpan offset in offsets) { if (offset.Equals(timeZone.BaseUtcOffset)) { Console.WriteLine("If {0} is {1}, {2} UTC", ambiguousTime, timeZone.StandardName, ambiguousTime - offset); } else { Console.WriteLine("If {0} is {1}, {2} UTC", ambiguousTime, timeZone.DaylightName, ambiguousTime - offset); } } } }
public void DateIsNotAmbiguous() { if (Environment.OSVersion.Platform != PlatformID.Unix) { throw new ArgumentException(); } TimeZoneInfo brussels = TimeZoneInfo.FindSystemTimeZoneById("Europe/Brussels"); DateTime date = new DateTime(2007, 05, 11, 11, 40, 00); brussels.GetAmbiguousTimeOffsets(date); }
public static TimeSpan GetUtcOffset(DateTime dateTime, TimeZoneInfo timeZoneInfo) { // Unlike the default behavior of TimeZoneInfo.GetUtcOffset, it is prefered to choose // the DAYLIGHT time when the input is ambiguous, because the daylight instance is the // FIRST instance, and time moves in a forward direction. TimeSpan offset = timeZoneInfo.IsAmbiguousTime(dateTime) ? timeZoneInfo.GetAmbiguousTimeOffsets(dateTime).Max() : timeZoneInfo.GetUtcOffset(dateTime); return(offset); }
public void AmbiguousOffsets() { if (Environment.OSVersion.Platform != PlatformID.Unix) { return; } TimeZoneInfo brussels = TimeZoneInfo.FindSystemTimeZoneById("Europe/Brussels"); DateTime date = new DateTime(2007, 10, 28, 2, 30, 00); Assert.IsTrue(brussels.IsAmbiguousTime(date)); Assert.AreEqual(2, brussels.GetAmbiguousTimeOffsets(date).Length); Assert.AreEqual(new TimeSpan[] { new TimeSpan(1, 0, 0), new TimeSpan(2, 0, 0) }, brussels.GetAmbiguousTimeOffsets(date)); }
// the point before DST/Standard change public static DateTimeOffset GetCurrentPeriodEnd(this TimeZoneInfo timeZone, DateTime value) { var next = GetAdjustmentDate(timeZone, value); if (next == DateTime.MaxValue) { throw new InvalidOperationException("date is not ambigous"); } var list = timeZone.GetAmbiguousTimeOffsets(value); var offset = list[0] == timeZone.GetUtcOffset(next) ? list[1] : list[0]; return(new DateTimeOffset(next, offset)); }
internal static DateTimeOffset ToDateTimeOffset(this DateTime dateTime, TimeZoneInfo timeZoneInfo) { TimeSpan offset; if (timeZoneInfo.IsAmbiguousTime(dateTime)) { // Ambiguous times happen when during backward transitions, such as the end of daylight saving time. // Since we were just told this time is ambiguous, there will always be exactly two offsets in the following array: TimeSpan[] offsets = timeZoneInfo.GetAmbiguousTimeOffsets(dateTime); // A reasonable common practice is to pick the first occurrence, which is always the largest offset in the array. // Ex: 2019-11-03T01:30:00 in the Pacific time zone occurs twice. First at 1:30 PDT (-07:00), then an hour later // at 1:30 PST (-08:00). We choose PDT (-07:00) because it comes first sequentially. offset = TimeSpan.FromMinutes(Math.Max(offsets[0].TotalMinutes, offsets[1].TotalMinutes)); } else if (timeZoneInfo.IsInvalidTime(dateTime)) { // Invalid times happen during the gap created by a forward transition, such as the start of daylight saving time. // While they are not values that actually occur in correct local time, they are sometimes encountered // in scenarios such as a scheduled daily task. In such cases, a reasonable common practice is to advance // to a valid local time by the amount of the transition gap (usually 1 hour). // Ex: 2019-03-10T02:30:00 does not exist in Pacific time. // The local time went from 01:59:59 PST (-08:00) directly to 03:00:00 PDT (-07:00). // We will advance by 1 hour to 03:30:00 which is in PDT (-07:00). // The gap is usually 1 hour, but not always - so it must be calculated TimeSpan earlierOffset = timeZoneInfo.GetUtcOffset(dateTime.AddDays(-1)); TimeSpan laterOffset = timeZoneInfo.GetUtcOffset(dateTime.AddDays(1)); TimeSpan gap = laterOffset - earlierOffset; dateTime = dateTime.Add(gap); offset = laterOffset; } else { dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc); offset = timeZoneInfo.GetUtcOffset(dateTime); } return(new DateTimeOffset(dateTime, offset)); }
/// <summary> /// Given a recurrence rule, get the next valid draw open and close based on a time zone. In the situation of DST /// ending, find the minimum of the ambigious times which comes after the afterTime argument. In the situation of DST /// starting, simply skip an invalid time provided by the library /// </summary> /// <param name="afterTime">The UTC time after which you want the next recurrence match</param> /// <param name="timeZoneId">The time zone you are calculatinig for</param> /// <param name="recurrence">The recurrence pattern</param> /// <returns>The next occurence in UTC</returns> public static DateTimeOffset GetNextOccurence(DateTimeOffset afterTime, string timeZoneId, List <Recurrence> recurrenceList) { DateTimeOffset nextUtc; TimeZoneInfo authorityTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId); DateTime afterTimeLocalized = TimeZoneInfo.ConvertTime(afterTime, authorityTimeZone).DateTime; DateTime nextLocal = recurrenceList.Min(e => e.NextInstance(afterTimeLocalized, true)); if (authorityTimeZone.IsInvalidTime(nextLocal)) { // Invalid times occur when Daylight Savings starts and the clocks are moved forward // I.E. The clock is 1:59:59AM ST and becomes 3:00:00AM DST, thereby eliminating the hour from 2AM to 3AM // Unfortunately our recurrance library will give us 2:00:00AM as a valid time // Thus we must add an hour nextLocal = nextLocal.AddHours(1); nextUtc = new DateTimeOffset(nextLocal, authorityTimeZone.GetUtcOffset(nextLocal)); } else if (authorityTimeZone.IsAmbiguousTime(nextLocal)) { // Ambigious times occur when Daylight Savings ends and the clocks are moved backward // I.E. The clock is 1:59:59AM DST and becomes 1:00:00AM ST, thereby repeating the hour from 1AM to 2AM // In this situation, the recurrence library will not repeat the hour var minOffset = (from Offset in authorityTimeZone.GetAmbiguousTimeOffsets(nextLocal) let DrawOpen = new DateTimeOffset(nextLocal, Offset) where DrawOpen > afterTime orderby DrawOpen select new { DrawOpen, Offset }).First(); nextUtc = minOffset.DrawOpen; } else if (authorityTimeZone.IsAmbiguousTime(nextLocal.AddHours(-1)) && recurrenceList.Any(z => z.OccursOn(nextLocal.AddHours(-1), true))) { // In this situation, the recurrence library potentially skipped the 2nd ambigious instance // So apply the two UTC time offsets and see if any of them is greater than the afterTime argument // If so, the recurrence library skipped the 2nd ambigious instance, and potentiallyValidTime is valid. // If not, nextLocal is correct DateTime potentiallyValidTime = nextLocal.AddHours(-1); var minOffset = (from Offset in authorityTimeZone.GetAmbiguousTimeOffsets(potentiallyValidTime) let DrawOpen = new DateTimeOffset(potentiallyValidTime, Offset) where DrawOpen > afterTime orderby DrawOpen select new { DrawOpen, Offset }).FirstOrDefault(); if (minOffset == null) { nextUtc = new DateTimeOffset(nextLocal, authorityTimeZone.GetUtcOffset(nextLocal)); } else { nextUtc = minOffset.DrawOpen; } } else { nextUtc = new DateTimeOffset(nextLocal, authorityTimeZone.GetUtcOffset(nextLocal)); } return(nextUtc); }
private static TimeSpan[] GetAmbiguousOffsets(TimeZoneInfo zone, DateTime ambiguousTime) { return(zone.GetAmbiguousTimeOffsets(ambiguousTime.AddTicks(1))); }
public static string GetPossibleUtcTimes(TimeZoneInfo timeZone, DateTime ambiguousTime) { StringBuilder oSB = new StringBuilder(); oSB.AppendLine(" Possible UTC Times for timezone:"); // Determine if time is ambiguous in target time zone if (!timeZone.IsAmbiguousTime(ambiguousTime)) { oSB.AppendFormat(" {0} is not ambiguous in time zone {1}.", ambiguousTime, timeZone.DisplayName); } else { // Display time and its time zone (local, UTC, or indicated by timeZone argument) string originalTimeZoneName = string.Empty;; if (ambiguousTime.Kind == DateTimeKind.Utc) { originalTimeZoneName = "UTC"; } else if (ambiguousTime.Kind == DateTimeKind.Local) { originalTimeZoneName = "local time"; } else { originalTimeZoneName = timeZone.DisplayName; } oSB.AppendFormat(" {0} {1} maps to the following possible times:", ambiguousTime, originalTimeZoneName); // Get ambiguous offsets TimeSpan[] offsets = timeZone.GetAmbiguousTimeOffsets(ambiguousTime); // Handle times not in time zone of timeZone argument // Local time where timeZone is not local zone if ((ambiguousTime.Kind == DateTimeKind.Local) && !timeZone.Equals(TimeZoneInfo.Local)) { ambiguousTime = TimeZoneInfo.ConvertTime(ambiguousTime, TimeZoneInfo.Local, timeZone); } // UTC time where timeZone is not UTC zone else if ((ambiguousTime.Kind == DateTimeKind.Utc) && !timeZone.Equals(TimeZoneInfo.Utc)) { ambiguousTime = TimeZoneInfo.ConvertTime(ambiguousTime, TimeZoneInfo.Utc, timeZone); } // Display each offset and its mapping to UTC foreach (TimeSpan offset in offsets) { if (offset.Equals(timeZone.BaseUtcOffset)) { oSB.AppendFormat(" If {0} is {1}, {2} UTC", ambiguousTime, timeZone.StandardName, ambiguousTime - offset); } else { oSB.AppendFormat(" If {0} is {1}, {2} UTC", ambiguousTime, timeZone.DaylightName, ambiguousTime - offset); } } } return(oSB.ToString()); }
public static string GetValuesFromTimezoneStringAndDateTime(TimeZoneInfo oTimeZoneInfo, DateTime oDateTime) { string s = string.Empty; StringBuilder oSB = new StringBuilder(); oSB.AppendLine(" Using this Date: " + oDateTime.ToString()); oSB.AppendLine(" Using this TimeZone: " + oTimeZoneInfo.ToString()); oSB.AppendLine(" Id: " + oTimeZoneInfo.Id); oSB.AppendLine(" DisplayName: " + oTimeZoneInfo.DisplayName); oSB.AppendLine(" StandardName: " + oTimeZoneInfo.StandardName); oSB.AppendLine(" DaylightName: " + oTimeZoneInfo.DaylightName); oSB.AppendLine(" BaseUtcOffset: " + oTimeZoneInfo.BaseUtcOffset.ToString()); oSB.AppendLine(" SupportsDaylightSavingTime: " + oTimeZoneInfo.SupportsDaylightSavingTime.ToString()); oSB.AppendLine(" BaseUtcOffset: " + oTimeZoneInfo.BaseUtcOffset.ToString()); oSB.AppendLine(" Days: " + oTimeZoneInfo.BaseUtcOffset.Days.ToString()); oSB.AppendLine(" Hours: " + oTimeZoneInfo.BaseUtcOffset.Hours.ToString()); oSB.AppendLine(" Milliseconds: " + oTimeZoneInfo.BaseUtcOffset.Milliseconds.ToString()); oSB.AppendLine(" Minutes: " + oTimeZoneInfo.BaseUtcOffset.Minutes.ToString()); oSB.AppendLine(" Seconds: " + oTimeZoneInfo.BaseUtcOffset.Seconds.ToString()); oSB.AppendLine(" Ticks: " + oTimeZoneInfo.BaseUtcOffset.Ticks.ToString()); oSB.AppendLine(" TotalDays: " + oTimeZoneInfo.BaseUtcOffset.TotalDays.ToString()); oSB.AppendLine(" TotalHours: " + oTimeZoneInfo.BaseUtcOffset.TotalHours.ToString()); oSB.AppendLine(" TotalMilliseconds: " + oTimeZoneInfo.BaseUtcOffset.TotalMilliseconds.ToString()); oSB.AppendLine(" TotalMinutes: " + oTimeZoneInfo.BaseUtcOffset.TotalMinutes.ToString()); oSB.AppendLine(" TotalSeconds: " + oTimeZoneInfo.BaseUtcOffset.TotalSeconds.ToString()); oSB.AppendLine(" IsDaylightSavingTime: " + oTimeZoneInfo.IsDaylightSavingTime(oDateTime).ToString()); oSB.AppendLine(" IsAmbiguousTime: " + oTimeZoneInfo.IsAmbiguousTime(oDateTime).ToString()); if (oTimeZoneInfo.IsAmbiguousTime(oDateTime) == true) { DateTime oDT = TimeZoneInfo.ConvertTime(oDateTime, oTimeZoneInfo); oSB.AppendLine(ResolveAmbiguousTime(oDateTime, oTimeZoneInfo)); } oSB.AppendLine(" IsInvalidTime: " + oTimeZoneInfo.IsInvalidTime(oDateTime).ToString()); //if (oTimeZoneInfo.IsInvalidTime(oDateTime) == true) //{ // oSB.AppendLine(GetPossibleUtcTimes(oTimeZoneInfo, oDateTime)); //} oSB.AppendLine(" ToSerializedString: " + oTimeZoneInfo.ToSerializedString()); oSB.AppendLine(" "); oSB.AppendLine(GetAdjustmentRules(oTimeZoneInfo)); //oSB.AppendLine(" AdjustmentRules:"); //foreach (TimeZoneInfo.AdjustmentRule ars in oTimeZoneInfo.GetAdjustmentRules()) //{ // oSB.AppendLine(" Adjustment Rule: DateStart: " + ars.DateStart.ToString() + " DateEnd: " + ars.DateEnd.ToString()); // oSB.AppendLine(" DaylightTransitionStart: "); // oSB.AppendLine(" Month: " + ars.DaylightTransitionStart.Month.ToString()); // oSB.AppendLine(" Day: " + ars.DaylightTransitionStart.Day.ToString()); // oSB.AppendLine(" DayOfWeek: " + ars.DaylightTransitionStart.DayOfWeek.ToString()); // oSB.AppendLine(" TimeOfDay: " + ars.DaylightTransitionStart.TimeOfDay.ToString()); // oSB.AppendLine(" Week: " + ars.DaylightTransitionStart.Week.ToString()); // oSB.AppendLine(" IsFixedDateRule: " + ars.DaylightTransitionStart.IsFixedDateRule.ToString()); // oSB.AppendLine(" DaylightTransitionEnd: "); // oSB.AppendLine(" Month: " + ars.DaylightTransitionEnd.Month.ToString()); // oSB.AppendLine(" Day: " + ars.DaylightTransitionEnd.Day.ToString()); // oSB.AppendLine(" DayOfWeek: " + ars.DaylightTransitionEnd.DayOfWeek.ToString()); // oSB.AppendLine(" TimeOfDay: " + ars.DaylightTransitionEnd.TimeOfDay.ToString()); // oSB.AppendLine(" Week: " + ars.DaylightTransitionEnd.Week.ToString()); // oSB.AppendLine(" IsFixedDateRule: " + ars.DaylightTransitionEnd.IsFixedDateRule.ToString()); // oSB.AppendLine(" DaylightDelta: " + ars.DaylightDelta.ToString()); //} oSB.AppendLine(" "); oSB.AppendLine(" GetAmbiguousTimeOffsets:"); if (oTimeZoneInfo.IsAmbiguousTime(oDateTime) == false) { oSB.AppendLine(" The time is not Ambiguous for ths timezone."); } else { foreach (TimeSpan oTzTimeSpan in oTimeZoneInfo.GetAmbiguousTimeOffsets(oDateTime)) { oSB.AppendLine(" TimeSpan: " + oTzTimeSpan.ToString()); oSB.AppendLine(" Days: " + oTzTimeSpan.Days.ToString()); oSB.AppendLine(" Hours: " + oTzTimeSpan.Hours.ToString()); oSB.AppendLine(" Milliseconds: " + oTzTimeSpan.Milliseconds.ToString()); oSB.AppendLine(" Minutes: " + oTzTimeSpan.Minutes.ToString()); oSB.AppendLine(" Seconds: " + oTzTimeSpan.Seconds.ToString()); oSB.AppendLine(" Ticks: " + oTzTimeSpan.Ticks.ToString()); oSB.AppendLine(" TotalDays: " + oTzTimeSpan.TotalDays.ToString()); oSB.AppendLine(" TotalHours: " + oTzTimeSpan.TotalHours.ToString()); oSB.AppendLine(" TotalMilliseconds: " + oTzTimeSpan.TotalMilliseconds.ToString()); oSB.AppendLine(" TotalMinutes: " + oTzTimeSpan.TotalMinutes.ToString()); oSB.AppendLine(" TotalSeconds: " + oTzTimeSpan.TotalSeconds.ToString()); } } oSB.AppendLine(" "); //// http://msdn.microsoft.com/en-us/library/bb495915(v=vs.110).aspx //// Convert to local time oSB.AppendLine("****************************"); oSB.AppendLine("Test convert to Local ****"); try { DateTime localTime = TimeZoneInfo.ConvertTime(oDateTime, oTimeZoneInfo, TimeZoneInfo.Local); oSB.AppendLine(" In Local: "); oSB.AppendLine(" DateTime: " + localTime.ToString()); oSB.AppendLine(" IsDaylightSavingTime: " + TimeZoneInfo.Local.IsDaylightSavingTime(localTime).ToString()); oSB.AppendLine(" "); } catch (Exception exConvertLocal) { oSB.AppendLine(" "); oSB.AppendLine("****************"); oSB.AppendLine(" Error trying to use TimeZoneInfo.ConvertTime to convert timezone to Local time using spedified DateTime"); oSB.AppendLine(" " + exConvertLocal.ToString()); oSB.AppendLine(" ****************"); oSB.AppendLine(" "); } oSB.AppendLine("**************************"); oSB.AppendLine(" "); oSB.AppendLine("****************************"); oSB.AppendLine("Test convert to UTC"); try { // Convert to UTC DateTime utcTime = TimeZoneInfo.ConvertTime(oDateTime, oTimeZoneInfo, TimeZoneInfo.Utc); oSB.AppendLine(" In UTC - ConvertTime: "); oSB.AppendLine(" DateTime: " + utcTime); oSB.AppendLine(" IsDaylightSavingTime: " + TimeZoneInfo.Local.IsDaylightSavingTime(utcTime).ToString()); oSB.AppendLine(" "); } catch (Exception exConvertLocal) { oSB.AppendLine(" "); oSB.AppendLine(" ****************"); oSB.AppendLine(" Error trying to use TimeZoneInfo.ConvertTime to convert timezone to UTC time using spedified DateTime"); oSB.AppendLine(" " + exConvertLocal.ToString()); oSB.AppendLine(" ****************"); oSB.AppendLine(" "); } oSB.AppendLine("**************************"); oSB.AppendLine(" "); s = oSB.ToString(); return(s); }
public static TimeSpan GetOtherAmbigousOffset(this TimeZoneInfo timeZone, DateTimeOffset value) { var list = timeZone.GetAmbiguousTimeOffsets(value); return(list[0] == value.Offset ? list[1] : list[0]); }
public DateTime NextUtc(DateTime dateTimeUtc) { if (dateTimeUtc.Kind != DateTimeKind.Utc) { throw new ArgumentException("Only UTC times can be used", nameof(dateTimeUtc)); } var truncatedUtc = dateTimeUtc.TruncateMs(); var dateTime = TimeZoneInfo.ConvertTimeFromUtc(truncatedUtc, _timeZoneInfo); var offsets = new List <TimeSpan>(); if (_timeZoneInfo.IsAmbiguousTime(dateTime)) { offsets.AddRange(_timeZoneInfo.GetAmbiguousTimeOffsets(dateTime)); } else { offsets.Add(_timeZoneInfo.GetUtcOffset(dateTime)); } var possibleResults = new List <DateTime?>(); DateTime nextDateTime, originalDateTime; foreach (var offset in offsets) { nextDateTime = originalDateTime = DateTime.SpecifyKind(truncatedUtc.Add(offset), DateTimeKind.Unspecified); DoNext(ref nextDateTime, nextDateTime.Year); if (nextDateTime == originalDateTime) { // We arrived at the original timestamp - round up to the next whole second and try again... nextDateTime = nextDateTime.AddSeconds(1); DoNext(ref nextDateTime, nextDateTime.Year); } // try to skip invalid time for the time zone while (_timeZoneInfo.IsInvalidTime(nextDateTime)) { nextDateTime = nextDateTime.AddSeconds(1); DoNext(ref nextDateTime, nextDateTime.Year); } if (_timeZoneInfo.IsAmbiguousTime(nextDateTime)) { var nextOffsets = _timeZoneInfo.GetAmbiguousTimeOffsets(nextDateTime); if (_isIntervalBased) { foreach (var nextOffset in nextOffsets) { possibleResults.Add(DateTime.SpecifyKind(nextDateTime.Subtract(nextOffset), DateTimeKind.Utc)); } } else { // if the expression is not interval based (doesn't have */- in sec, min, hour field) // we only use one of the intervals (the last one), which has the largest offset and yields smallest time after subtract. possibleResults.Add(DateTime.SpecifyKind(nextDateTime.Subtract(nextOffsets.Last()), DateTimeKind.Utc)); } } else { var nextOffset = _timeZoneInfo.GetUtcOffset(nextDateTime); possibleResults.Add(DateTime.SpecifyKind(nextDateTime.Subtract(nextOffset), DateTimeKind.Utc)); } } return(possibleResults .OrderBy(utc => utc) .FirstOrDefault(utc => utc > dateTimeUtc) ?? throw new Exception("Possible bug in code - couldn't find next cron time")); }