1   /* Copyright 2002-2013 CS Systèmes d'Information
2    * Licensed to CS Systèmes d'Information (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.orekit.utils.Constants;
22  
23  /** Offset between {@link UTCScale UTC} and  {@link TAIScale TAI} time scales.
24   * <p>The {@link UTCScale UTC} and  {@link TAIScale TAI} time scales are two
25   * scales offset with respect to each other. The {@link TAIScale TAI} scale is
26   * continuous whereas the {@link UTCScale UTC} includes some discontinuity when
27   * leap seconds are introduced by the <a href="http://www.iers.org/">International
28   * Earth Rotation Service</a> (IERS).</p>
29   * <p>This class represents the offset between the two scales that is
30   * valid between two leap seconds occurrences. It handles both the linear offsets
31   * used from 1961-01-01 to 1971-12-31 and the constant integer offsets used since
32   * 1972-01-01.</p>
33   * @author Luc Maisonobe
34   * @see UTCScale
35   * @see UTCTAIHistoryFilesLoader
36   */
37  class UTCTAIOffset implements TimeStamped, Serializable {
38  
39      /** Serializable UID. */
40      private static final long serialVersionUID = 4742190573136348054L;
41  
42      /** Leap date. */
43      private final AbsoluteDate leapDate;
44  
45      /** Leap date in Modified Julian Day. */
46      private final int leapDateMJD;
47  
48      /** Offset start of validity date. */
49      private final AbsoluteDate validityStart;
50  
51      /** Offset end of validity date. */
52      private AbsoluteDate validityEnd;
53  
54      /** Reference date for the slope multiplication as Modified Julian Day. */
55      private final int mjdRef;
56  
57      /** Reference date for the slope multiplication. */
58      private final AbsoluteDate reference;
59  
60      /** Value of the leap at offset validity start (in seconds). */
61      private final double leap;
62  
63      /** Offset at validity start in seconds (TAI minus UTC). */
64      private final double offset;
65  
66      /** Offset slope in seconds per UTC second (TAI minus UTC / dUTC). */
67      private final double slopeUTC;
68  
69      /** Offset slope in seconds per TAI second (TAI minus UTC / dTAI). */
70      private final double slopeTAI;
71  
72      /** Simple constructor for a constant model.
73       * @param leapDate leap date
74       * @param leapDateMJD leap date in Modified Julian Day
75       * @param leap value of the leap at offset validity start (in seconds)
76       * @param offset offset in seconds (TAI minus UTC)
77       */
78      public UTCTAIOffset(final AbsoluteDate leapDate, final int leapDateMJD,
79                          final double leap, final double offset) {
80          this(leapDate, leapDateMJD, leap, offset, 0, 0);
81      }
82  
83      /** Simple constructor for a linear model.
84       * @param leapDate leap date
85       * @param leapDateMJD leap date in Modified Julian Day
86       * @param leap value of the leap at offset validity start (in seconds)
87       * @param offset offset in seconds (TAI minus UTC)
88       * @param mjdRef reference date for the slope multiplication as Modified Julian Day
89       * @param slope offset slope in seconds per UTC second (TAI minus UTC / dUTC)
90       */
91      public UTCTAIOffset(final AbsoluteDate leapDate, final int leapDateMJD,
92                          final double leap, final double offset,
93                          final int mjdRef, final double slope) {
94          this.leapDate      = leapDate;
95          this.leapDateMJD   = leapDateMJD;
96          this.validityStart = leapDate.shiftedBy(leap);
97          this.validityEnd   = AbsoluteDate.FUTURE_INFINITY;
98          this.mjdRef        = mjdRef;
99          this.reference     = new AbsoluteDate(new DateComponents(DateComponents.MODIFIED_JULIAN_EPOCH, mjdRef),
100                                               TimeScalesFactory.getTAI()).shiftedBy(offset);
101         this.leap          = leap;
102         this.offset        = offset;
103         this.slopeUTC      = slope;
104         this.slopeTAI      = slope / (1 + slope);
105     }
106 
107     /** Get the date of the start of the leap.
108      * @return date of the start of the leap
109      * @see #getValidityStart()
110      */
111     public AbsoluteDate getDate() {
112         return leapDate;
113     }
114 
115     /** Get the date of the start of the leap as Modified Julian Day.
116      * @return date of the start of the leap as Modified Julian Day
117      */
118     public int getMJD() {
119         return leapDateMJD;
120     }
121 
122     /** Get the start time of validity for this offset.
123      * <p>The start of the validity of the offset is {@link #getLeap()}
124      * seconds after the start of the leap itself.</p>
125      * @return start of validity date
126      * @see #getDate()
127      * @see #getValidityEnd()
128      */
129     public AbsoluteDate getValidityStart() {
130         return validityStart;
131     }
132 
133     /** Get the end time of validity for this offset.
134      * <p>The end of the validity of the offset is the date of the
135      * start of the leap leading to the next offset.</p>
136      * @return end of validity date
137      * @see #getValidityStart()
138      */
139     public AbsoluteDate getValidityEnd() {
140         return validityEnd;
141     }
142 
143     /** Set the end time of validity for this offset.
144      * @param validityEnd end of validity date
145      * @see #getValidityEnd()
146      */
147     void setValidityEnd(final AbsoluteDate validityEnd) {
148         this.validityEnd = validityEnd;
149     }
150 
151     /** Get the value of the leap at offset validity start (in seconds).
152      * @return value of the leap at offset validity start (in seconds)
153      */
154     public double getLeap() {
155         return leap;
156     }
157 
158     /** Get the TAI - UTC offset in seconds.
159      * @param date date at which the offset is requested
160      * @return TAI - UTC offset in seconds.
161      */
162     public double getOffset(final AbsoluteDate date) {
163         return offset + date.durationFrom(reference) * slopeTAI;
164     }
165 
166     /** Get the TAI - UTC offset in seconds.
167      * @param date date components (in UTC) at which the offset is requested
168      * @param time time components (in UTC) at which the offset is requested
169      * @return TAI - UTC offset in seconds.
170      */
171     public double getOffset(final DateComponents date, final TimeComponents time) {
172         final int    days     = date.getMJD() - mjdRef;
173         final double fraction = time.getSecondsInDay();
174         return offset + days * (slopeUTC * Constants.JULIAN_DAY) + fraction * slopeUTC;
175     }
176 
177 }