1   /* Copyright 2002-2019 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.hipparchus.util.FastMath;
22  import org.orekit.utils.Constants;
23  
24  /** Container for date in GPS form.
25   * @author Luc Maisonobe
26   * @see AbsoluteDate
27   * @since 9.3
28   */
29  public class GPSDate implements Serializable, TimeStamped {
30  
31      /** Serializable UID. */
32      private static final long serialVersionUID = 20180633L;
33  
34      /** Duration of a week in seconds. */
35      private static final double WEEK = 7 * Constants.JULIAN_DAY;
36  
37      /** conversion factor from seconds to milliseconds. */
38      private static final double S_TO_MS = 1000.0;
39  
40      /** Week number since {@link AbsoluteDate#GPS_EPOCH GPS epoch}. */
41      private final int weekNumber;
42  
43      /** Number of milliseconds since week start. */
44      private final double milliInWeek;
45  
46      /** Corresponding date. */
47      private final transient AbsoluteDate date;
48  
49      /** Build an instance corresponding to a GPS date.
50       * <p>GPS dates are provided as a week number starting at
51       * {@link AbsoluteDate#GPS_EPOCH GPS epoch} and as a number of milliseconds
52       * since week start.</p>
53       * @param weekNumber week number since {@link AbsoluteDate#GPS_EPOCH GPS epoch}
54       * @param milliInWeek number of milliseconds since week start
55       */
56      public GPSDate(final int weekNumber, final double milliInWeek) {
57  
58          this.weekNumber  = weekNumber;
59          this.milliInWeek = milliInWeek;
60  
61          final int day = (int) FastMath.floor(milliInWeek / (Constants.JULIAN_DAY * S_TO_MS));
62          final double secondsInDay = milliInWeek / S_TO_MS - day * Constants.JULIAN_DAY;
63          date = new AbsoluteDate(new DateComponents(DateComponents.GPS_EPOCH, weekNumber * 7 + day),
64                                  new TimeComponents(secondsInDay),
65                                  TimeScalesFactory.getGPS());
66  
67      }
68  
69      /** Build an instance from an absolute date.
70       * @param date absolute date to consider
71       */
72      public GPSDate(final AbsoluteDate date) {
73  
74          this.weekNumber  = (int) FastMath.floor(date.durationFrom(AbsoluteDate.GPS_EPOCH) / WEEK);
75          final AbsoluteDateteDate">AbsoluteDate weekStart = new AbsoluteDate(AbsoluteDate.GPS_EPOCH, WEEK * weekNumber);
76          this.milliInWeek = date.durationFrom(weekStart) * S_TO_MS;
77          this.date        = date;
78  
79      }
80  
81      /** Get the week number since {@link AbsoluteDate#GPS_EPOCH GPS epoch}.
82       * @return week number since {@link AbsoluteDate#GPS_EPOCH GPS epoch}
83       */
84      public int getWeekNumber() {
85          return weekNumber;
86      }
87  
88      /** Get the number of milliseconds since week start.
89       * @return number of milliseconds since week start
90       */
91      public double getMilliInWeek() {
92          return milliInWeek;
93      }
94  
95      /** {@inheritDoc} */
96      @Override
97      public AbsoluteDate getDate() {
98          return date;
99      }
100 
101     /** Replace the instance with a data transfer object for serialization.
102      * @return data transfer object that will be serialized
103      */
104     private Object writeReplace() {
105         return new DataTransferObject(weekNumber, milliInWeek);
106     }
107 
108     /** Internal class used only for serialization. */
109     private static class DataTransferObject implements Serializable {
110 
111         /** Serializable UID. */
112         private static final long serialVersionUID = 20180633L;
113 
114         /** Week number since {@link AbsoluteDate#GPS_EPOCH GPS epoch}. */
115         private final int weekNumber;
116 
117         /** Number of milliseconds since week start. */
118         private final double milliInWeek;
119 
120         /** Simple constructor.
121          * @param weekNumber week number since {@link AbsoluteDate#GPS_EPOCH GPS epoch}
122          * @param milliInWeek number of milliseconds since week start
123          */
124         DataTransferObject(final int weekNumber, final double milliInWeek) {
125             this.weekNumber  = weekNumber;
126             this.milliInWeek = milliInWeek;
127         }
128 
129         /** Replace the deserialized data transfer object with a {@link GPSDate}.
130          * @return replacement {@link GPSDate}
131          */
132         private Object readResolve() {
133             return new GPSDate(weekNumber, milliInWeek);
134         }
135 
136     }
137 
138 }