@@ -319,30 +319,21 @@ class TerrestrialTimeScaleConverter
319319
320320 break ;
321321 case basic_astrodynamics::utc_scale:
322- timesToUpdate. utc = inputTimeValue;
323- timesToUpdate. tai = sofa_interface::convertUTCtoTAI < TimeType >( timesToUpdate. utc );
322+ // --- 1. Use function to calculate TAI and TT from UTC ---
323+ calculateAtomicTimesFromUtc < TimeType >( inputTimeValue );
324324
325- timesToUpdate. tt = basic_astrodynamics::convertTAItoTT< TimeType >( timesToUpdate. tai );
325+ // --- 2. Calculate TDB from the newly computed TT ---
326326 tdbMinusTt = static_cast < TimeType >( this ->getTDBminusTT ( timesToUpdate.tt , earthFixedPosition ) );
327327 timesToUpdate.tdb = timesToUpdate.tt + tdbMinusTt;
328328
329- if ( dailyUtcUt1CorrectionInterpolator_ != nullptr )
329+ // --- 3. Calculate UT1 if possible (for modern era) ---
330+ if ( dailyUtcUt1CorrectionInterpolator_ != nullptr && timesToUpdate.tai >= utcIntroductionEpochInTai_ )
330331 {
331- try
332- {
333- timesToUpdate.ut1 = static_cast < TimeType >( dailyUtcUt1CorrectionInterpolator_->interpolate ( timesToUpdate.utc ) ) +
334- timesToUpdate.utc ;
335- }
336- catch ( std::runtime_error& caughtException )
337- {
338- throw std::runtime_error ( " Error in UTC-UT1 correction.\n Original error: " + std::string ( caughtException.what ( ) ) );
339- }
340-
341-
332+ timesToUpdate.ut1 = static_cast < TimeType >( dailyUtcUt1CorrectionInterpolator_->interpolate ( timesToUpdate.utc ) ) +
333+ timesToUpdate.utc ;
342334 timesToUpdate.ut1 +=
343335 static_cast < TimeType >( shortPeriodUt1CorrectionCalculator_->getCorrections ( timesToUpdate.tdb ) );
344336 }
345-
346337 break ;
347338 case basic_astrodynamics::ut1_scale:
348339
@@ -509,6 +500,50 @@ class TerrestrialTimeScaleConverter
509500 }
510501 }
511502
503+
504+ template < typename TimeType >
505+ void calculateAtomicTimesFromUtc ( const TimeType& inputUtcTime )
506+ {
507+ // --- NEW LOGIC: Check for historical date FIRST ---
508+ // The UTC introduction epoch is in TAI, but we can use it as an approximate
509+ // threshold for the input time (which is UTC-like) to decide which path to take.
510+ // This avoids calling SOFA functions with dates they cannot handle.
511+ if ( inputUtcTime < utcIntroductionEpochInTai_)
512+ {
513+ // --- 1. Historical Time (Pre-UTC Era) ---
514+ // This path is now correctly taken for the 1893 date.
515+ // In this period, the input "UTC" is effectively UT1.
516+ // The conversion path is UT1 -> TT -> TAI.
517+ getCurrentTimeList< TimeType >( ).ut1 = inputUtcTime;
518+ getCurrentTimeList< TimeType >( ).utc = inputUtcTime;
519+
520+ // Approximate the year to look up the historical ΔT value.
521+ double approximateYear = ( inputUtcTime / physical_constants::JULIAN_YEAR ) + 2000.0 ;
522+
523+ // Calculate TT from UT1 using the historical ΔT. (TT = UT1 + ΔT)
524+ getCurrentTimeList< TimeType >( ).tt = getCurrentTimeList< TimeType >( ).ut1 +
525+ historicalDeltaTInterpolator_->interpolate ( approximateYear );
526+
527+ // Convert TT to TAI using the standard constant offset.
528+ getCurrentTimeList< TimeType >( ).tai = basic_astrodynamics::convertTTtoTAI< TimeType >(
529+ getCurrentTimeList< TimeType >( ).tt );
530+ }
531+ else
532+ {
533+ // --- 2. Modern Time (Post-UTC Era) ---
534+ // The conversion is handled directly by the SOFA function, which correctly
535+ // accounts for all leap seconds.
536+ getCurrentTimeList< TimeType >( ).utc = inputUtcTime;
537+ getCurrentTimeList< TimeType >( ).tai = sofa_interface::convertUTCtoTAI< TimeType >(
538+ getCurrentTimeList< TimeType >( ).utc );
539+
540+ // >>>>> THE FIX IS HERE <<<<<
541+ // We must also convert the newly calculated TAI to TT.
542+ getCurrentTimeList< TimeType >( ).tt = basic_astrodynamics::convertTAItoTT< TimeType >(
543+ getCurrentTimeList< TimeType >( ).tai );
544+ }
545+ }
546+
512547 // ! Interpolator for UT1 corrections, values published daily by IERS
513548 std::shared_ptr< interpolators::OneDimensionalInterpolator< double , double > > dailyUtcUt1CorrectionInterpolator_;
514549
0 commit comments