/// <summary> /// Returns the difference TAI - UTC as of the given date, in seconds. /// </summary> /// <param name="date">The date.</param> /// <returns>The difference.</returns> public double GetTaiMinusUtc(JulianDate date) { LeapSecond toFind = new LeapSecond(date, 0.0); // Start by assuming we're working with UTC, we'll check later if we're // off by one because we really have TAI. int index = m_leapSeconds.BinarySearch(toFind, s_compareLeapSecondDate); if (index < 0) { index = ~index; --index; } // Check if we're off by one because we're really working with TAI. // If the requested date minus the most recent previous leap second offset is less than the date // for the current leap second, then we haven't quite gotten to that leap second yet. // This gets a little tricky because JulianDate and its conversion mechanisms try to outsmart us. if (date.Standard == TimeStandard.InternationalAtomicTime) { JulianDate lastDate = GetDateForIndex(index); JulianDate taiCutoff = new JulianDate(lastDate.Day, lastDate.SecondsOfDay, TimeStandard.InternationalAtomicTime); taiCutoff += Duration.FromSeconds(GetOffsetForIndex(index)); if (date < taiCutoff) { --index; } } return(GetOffsetForIndex(index)); }
/// <summary> /// Try to convert <paramref name="date"/> from TAI to UTC, if possible. /// </summary> /// <param name="date">The date, which must be in the TAI /// <see cref="TimeStandard"/>.</param> /// <param name="result">Out parameter for returning the resulting UTC /// <see cref="JulianDate"/>, if it was possible to convert.</param> /// <returns><see langword="true"/> if <paramref name="date"/> could be converted /// to UTC, otherwise false.</returns> internal bool TryConvertTaiToUtc(JulianDate date, out JulianDate result) { //treat the request date as if it were UTC, and search for the most recent leap second. LeapSecond toFind = new LeapSecond(date, 0.0); int index = m_leapSeconds.BinarySearch(toFind, s_compareLeapSecondDate); if (index < 0) { index = ~index; --index; } //now we have the index of the most recent leap second that is after the requested date if (index >= 0) { double mostRecentOffset = GetOffsetForIndex(index); JulianDate leapSecondDate = GetDateForIndex(index); if (date.Day == leapSecondDate.Day) { //if the requested date is on the day of the leap second, we may have to adjust double secondsSinceLeapSecond = date.SecondsOfDay - leapSecondDate.SecondsOfDay; if (secondsSinceLeapSecond >= mostRecentOffset - 1 && secondsSinceLeapSecond < mostRecentOffset) { //if the requested date is during the moment of a leap second, then we cannot convert to UTC. result = JulianDate.MinValue; return(false); } if (secondsSinceLeapSecond < mostRecentOffset) { //The leap second we found is actually after the desired date, as a result of simply treating the //TAI date as if it were UTC. So, use the next previous leap second instead. --index; } } } result = new JulianDate(date.Day, date.SecondsOfDay - GetOffsetForIndex(index), TimeStandard.CoordinatedUniversalTime); return(true); }
/// <summary> /// Determines if a given day contains a leap second. /// </summary> /// <param name="julianDayNumber">The day, specified as a Julian day number.</param> /// <returns>true if the day contains a leap second, otherwise false.</returns> public bool DoesDayHaveLeapSecond(int julianDayNumber) { LeapSecond potentialLeapSecond = new LeapSecond(new JulianDate(julianDayNumber, 43200, TimeStandard.CoordinatedUniversalTime), 0.0); return(m_leapSeconds.BinarySearch(potentialLeapSecond, s_compareLeapSecondDate) >= 0); }