1 /* Copyright 2002-2024 CS GROUP 2 * Licensed to CS GROUP (CS) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * CS licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.orekit.time; 18 19 import java.io.Serializable; 20 21 import org.hipparchus.CalculusFieldElement; 22 import org.orekit.utils.Constants; 23 24 /** Offset between {@link UTCScale UTC} and {@link TAIScale TAI} time scales. 25 * <p>The {@link UTCScale UTC} and {@link TAIScale TAI} time scales are two 26 * scales offset with respect to each other. The {@link TAIScale TAI} scale is 27 * continuous whereas the {@link UTCScale UTC} includes some discontinuity when 28 * leap seconds are introduced by the <a href="http://www.iers.org/">International 29 * Earth Rotation Service</a> (IERS).</p> 30 * <p>This class represents the offset between the two scales that is 31 * valid between two leap seconds occurrences. It handles both the linear offsets 32 * used from 1961-01-01 to 1971-12-31 and the constant integer offsets used since 33 * 1972-01-01.</p> 34 * @author Luc Maisonobe 35 * @see UTCScale 36 * @see UTCTAIHistoryFilesLoader 37 */ 38 public class UTCTAIOffset implements TimeStamped, Serializable { 39 40 /** Serializable UID. */ 41 private static final long serialVersionUID = 4742190573136348054L; 42 43 /** Leap date. */ 44 private final AbsoluteDate leapDate; 45 46 /** Leap date in Modified Julian Day. */ 47 private final int leapDateMJD; 48 49 /** Offset start of validity date. */ 50 private final AbsoluteDate validityStart; 51 52 /** Reference date for the slope multiplication as Modified Julian Day. */ 53 private final int mjdRef; 54 55 /** Reference date for the slope multiplication. */ 56 private final AbsoluteDate reference; 57 58 /** Value of the leap at offset validity start (in seconds). */ 59 private final double leap; 60 61 /** Offset at validity start in seconds (TAI minus UTC). */ 62 private final double offset; 63 64 /** Offset slope in seconds per UTC second (TAI minus UTC / dUTC). */ 65 private final double slopeUTC; 66 67 /** Offset slope in seconds per TAI second (TAI minus UTC / dTAI). */ 68 private final double slopeTAI; 69 70 /** Simple constructor for a linear model. 71 * @param leapDate leap date 72 * @param leapDateMJD leap date in Modified Julian Day 73 * @param leap value of the leap at offset validity start (in seconds) 74 * @param offset offset in seconds (TAI minus UTC) 75 * @param mjdRef reference date for the slope multiplication as Modified Julian Day 76 * @param slope offset slope in seconds per UTC second (TAI minus UTC / dUTC) 77 * @param reference date for slope computations. 78 */ 79 UTCTAIOffset(final AbsoluteDate leapDate, final int leapDateMJD, 80 final double leap, final double offset, 81 final int mjdRef, final double slope, final AbsoluteDate reference) { 82 this.leapDate = leapDate; 83 this.leapDateMJD = leapDateMJD; 84 this.validityStart = leapDate.shiftedBy(leap); 85 this.mjdRef = mjdRef; 86 this.reference = reference; 87 this.leap = leap; 88 this.offset = offset; 89 this.slopeUTC = slope; 90 this.slopeTAI = slope / (1 + slope); 91 } 92 93 /** Get the date of the start of the leap. 94 * @return date of the start of the leap 95 * @see #getValidityStart() 96 */ 97 public AbsoluteDate getDate() { 98 return leapDate; 99 } 100 101 /** Get the date of the start of the leap as Modified Julian Day. 102 * @return date of the start of the leap as Modified Julian Day 103 */ 104 public int getMJD() { 105 return leapDateMJD; 106 } 107 108 /** Get the start time of validity for this offset. 109 * <p>The start of the validity of the offset is {@link #getLeap()} 110 * seconds after the start of the leap itself.</p> 111 * @return start of validity date 112 * @see #getDate() 113 */ 114 public AbsoluteDate getValidityStart() { 115 return validityStart; 116 } 117 118 /** Get the value of the leap at offset validity start (in seconds). 119 * @return value of the leap at offset validity start (in seconds) 120 */ 121 public double getLeap() { 122 return leap; 123 } 124 125 /** Get the TAI - UTC offset in seconds. 126 * @param date date at which the offset is requested 127 * @return TAI - UTC offset in seconds. 128 */ 129 public double getOffset(final AbsoluteDate date) { 130 if (slopeTAI == 0) { 131 // we use an if statement here so the offset computation returns 132 // a finite value when date is AbsoluteDate.FUTURE_INFINITY 133 // without this if statement, the multiplication between an 134 // infinite duration and a zero slope would induce a NaN offset 135 return offset; 136 } else { 137 return offset + date.durationFrom(reference) * slopeTAI; 138 } 139 } 140 141 /** Get the TAI - UTC offset in seconds. 142 * @param date date at which the offset is requested 143 * @param <T> type of the filed elements 144 * @return TAI - UTC offset in seconds. 145 * @since 9.0 146 */ 147 public <T extends CalculusFieldElement<T>> T getOffset(final FieldAbsoluteDate<T> date) { 148 if (slopeTAI == 0) { 149 // we use an if statement here so the offset computation returns 150 // a finite value when date is FieldAbsoluteDate.getFutureInfinity(field) 151 // without this if statement, the multiplication between an 152 // infinite duration and a zero slope would induce a NaN offset 153 return date.getField().getZero().newInstance(offset); 154 } else { 155 return date.durationFrom(reference).multiply(slopeTAI).add(offset); 156 } 157 } 158 159 /** Get the TAI - UTC offset in seconds. 160 * @param date date components (in UTC) at which the offset is requested 161 * @param time time components (in UTC) at which the offset is requested 162 * @return TAI - UTC offset in seconds. 163 */ 164 public double getOffset(final DateComponents date, final TimeComponents time) { 165 final int days = date.getMJD() - mjdRef; 166 final double fraction = time.getSecondsInUTCDay(); 167 return offset + days * (slopeUTC * Constants.JULIAN_DAY) + fraction * slopeUTC; 168 } 169 170 }