1 /* Copyright 2002-2020 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.util.FastMath;
22 import org.orekit.utils.Constants;
23
24 /** Holder for date and time components.
25 * <p>This class is a simple holder with no processing methods.</p>
26 * <p>Instance of this class are guaranteed to be immutable.</p>
27 * @see AbsoluteDate
28 * @see DateComponents
29 * @see TimeComponents
30 * @author Luc Maisonobe
31 */
32 public class DateTimeComponents implements Serializable, Comparable<DateTimeComponents> {
33
34 /**
35 * The Julian Epoch.
36 *
37 * @see TimeScales#getJulianEpoch()
38 */
39 public static final DateTimeComponents JULIAN_EPOCH =
40 new DateTimeComponents(DateComponents.JULIAN_EPOCH, TimeComponents.H12);
41
42 /** Serializable UID. */
43 private static final long serialVersionUID = 5061129505488924484L;
44
45 /** Date component. */
46 private final DateComponents date;
47
48 /** Time component. */
49 private final TimeComponents time;
50
51 /** Build a new instance from its components.
52 * @param date date component
53 * @param time time component
54 */
55 public DateTimeComponents(final DateComponents date, final TimeComponents time) {
56 this.date = date;
57 this.time = time;
58 }
59
60 /** Build an instance from raw level components.
61 * @param year year number (may be 0 or negative for BC years)
62 * @param month month number from 1 to 12
63 * @param day day number from 1 to 31
64 * @param hour hour number from 0 to 23
65 * @param minute minute number from 0 to 59
66 * @param second second number from 0.0 to 60.0 (excluded)
67 * @exception IllegalArgumentException if inconsistent arguments
68 * are given (parameters out of range, february 29 for non-leap years,
69 * dates during the gregorian leap in 1582 ...)
70 */
71 public DateTimeComponents(final int year, final int month, final int day,
72 final int hour, final int minute, final double second)
73 throws IllegalArgumentException {
74 this.date = new DateComponents(year, month, day);
75 this.time = new TimeComponents(hour, minute, second);
76 }
77
78 /** Build an instance from raw level components.
79 * @param year year number (may be 0 or negative for BC years)
80 * @param month month enumerate
81 * @param day day number from 1 to 31
82 * @param hour hour number from 0 to 23
83 * @param minute minute number from 0 to 59
84 * @param second second number from 0.0 to 60.0 (excluded)
85 * @exception IllegalArgumentException if inconsistent arguments
86 * are given (parameters out of range, february 29 for non-leap years,
87 * dates during the gregorian leap in 1582 ...)
88 */
89 public DateTimeComponents(final int year, final Month month, final int day,
90 final int hour, final int minute, final double second)
91 throws IllegalArgumentException {
92 this.date = new DateComponents(year, month, day);
93 this.time = new TimeComponents(hour, minute, second);
94 }
95
96 /** Build an instance from raw level components.
97 * <p>The hour is set to 00:00:00.000.</p>
98 * @param year year number (may be 0 or negative for BC years)
99 * @param month month number from 1 to 12
100 * @param day day number from 1 to 31
101 * @exception IllegalArgumentException if inconsistent arguments
102 * are given (parameters out of range, february 29 for non-leap years,
103 * dates during the gregorian leap in 1582 ...)
104 */
105 public DateTimeComponents(final int year, final int month, final int day)
106 throws IllegalArgumentException {
107 this.date = new DateComponents(year, month, day);
108 this.time = TimeComponents.H00;
109 }
110
111 /** Build an instance from raw level components.
112 * <p>The hour is set to 00:00:00.000.</p>
113 * @param year year number (may be 0 or negative for BC years)
114 * @param month month enumerate
115 * @param day day number from 1 to 31
116 * @exception IllegalArgumentException if inconsistent arguments
117 * are given (parameters out of range, february 29 for non-leap years,
118 * dates during the gregorian leap in 1582 ...)
119 */
120 public DateTimeComponents(final int year, final Month month, final int day)
121 throws IllegalArgumentException {
122 this.date = new DateComponents(year, month, day);
123 this.time = TimeComponents.H00;
124 }
125
126 /** Build an instance from a seconds offset with respect to another one.
127 * @param reference reference date/time
128 * @param offset offset from the reference in seconds
129 * @see #offsetFrom(DateTimeComponents)
130 */
131 public DateTimeComponentstml#DateTimeComponents">DateTimeComponents(final DateTimeComponents reference,
132 final double offset) {
133
134 // extract linear data from reference date/time
135 int day = reference.getDate().getJ2000Day();
136 double seconds = reference.getTime().getSecondsInLocalDay();
137
138 // apply offset
139 seconds += offset;
140
141 // fix range
142 final int dayShift = (int) FastMath.floor(seconds / Constants.JULIAN_DAY);
143 seconds -= Constants.JULIAN_DAY * dayShift;
144 day += dayShift;
145 final TimeComponentsComponents">TimeComponents tmpTime = new TimeComponents(seconds);
146
147 // set up components
148 this.date = new DateComponents(day);
149 this.time = new TimeComponents(tmpTime.getHour(), tmpTime.getMinute(), tmpTime.getSecond(),
150 reference.getTime().getMinutesFromUTC());
151
152 }
153
154 /** Parse a string in ISO-8601 format to build a date/time.
155 * <p>The supported formats are all date formats supported by {@link DateComponents#parseDate(String)}
156 * and all time formats supported by {@link TimeComponents#parseTime(String)} separated
157 * by the standard time separator 'T', or date components only (in which case a 00:00:00 hour is
158 * implied). Typical examples are 2000-01-01T12:00:00Z or 1976W186T210000.
159 * </p>
160 * @param string string to parse
161 * @return a parsed date/time
162 * @exception IllegalArgumentException if string cannot be parsed
163 */
164 public static DateTimeComponents parseDateTime(final String string) {
165
166 // is there a time ?
167 final int tIndex = string.indexOf('T');
168 if (tIndex > 0) {
169 return new DateTimeComponents(DateComponents.parseDate(string.substring(0, tIndex)),
170 TimeComponents.parseTime(string.substring(tIndex + 1)));
171 }
172
173 return new DateTimeComponents(DateComponents.parseDate(string), TimeComponents.H00);
174
175 }
176
177 /** Compute the seconds offset between two instances.
178 * @param dateTime dateTime to subtract from the instance
179 * @return offset in seconds between the two instants
180 * (positive if the instance is posterior to the argument)
181 * @see #DateTimeComponents(DateTimeComponents, double)
182 */
183 public double offsetFrom(final DateTimeComponents dateTime) {
184 final int dateOffset = date.getJ2000Day() - dateTime.date.getJ2000Day();
185 final double timeOffset = time.getSecondsInUTCDay() - dateTime.time.getSecondsInUTCDay();
186 return Constants.JULIAN_DAY * dateOffset + timeOffset;
187 }
188
189 /** Get the date component.
190 * @return date component
191 */
192 public DateComponents getDate() {
193 return date;
194 }
195
196 /** Get the time component.
197 * @return time component
198 */
199 public TimeComponents getTime() {
200 return time;
201 }
202
203 /** {@inheritDoc} */
204 public int compareTo(final DateTimeComponents other) {
205 final int dateComparison = date.compareTo(other.date);
206 if (dateComparison < 0) {
207 return -1;
208 } else if (dateComparison > 0) {
209 return 1;
210 }
211 return time.compareTo(other.time);
212 }
213
214 /** {@inheritDoc} */
215 public boolean equals(final Object other) {
216 try {
217 final DateTimeComponents/time/DateTimeComponents.html#DateTimeComponents">DateTimeComponents otherDateTime = (DateTimeComponents) other;
218 return (otherDateTime != null) &&
219 date.equals(otherDateTime.date) && time.equals(otherDateTime.time);
220 } catch (ClassCastException cce) {
221 return false;
222 }
223 }
224
225 /** {@inheritDoc} */
226 public int hashCode() {
227 return (date.hashCode() << 16) ^ time.hashCode();
228 }
229
230 /** Return a string representation of this pair.
231 * <p>The format used is ISO8601.</p>
232 * @return string representation of this pair
233 */
234 public String toString() {
235 return toString(60);
236 }
237
238 /** Return a string representation of this pair.
239 * <p>The format used is ISO8601.</p>
240 * @param minuteDuration 60 or 61 depending on the date being
241 * close to a leap second introduction
242 * @return string representation of this pair
243 */
244 public String toString(final int minuteDuration) {
245 double second = time.getSecond();
246 final double wrap = minuteDuration - 0.0005;
247 if (second >= wrap) {
248 // we should wrap around next millisecond
249 int minute = time.getMinute();
250 int hour = time.getHour();
251 int j2000 = date.getJ2000Day();
252 second = 0;
253 ++minute;
254 if (minute > 59) {
255 minute = 0;
256 ++hour;
257 if (hour > 23) {
258 hour = 0;
259 ++j2000;
260 }
261 }
262 return new DateComponents(j2000).toString() + 'T' + new TimeComponents(hour, minute, second).toString();
263 }
264 return date.toString() + 'T' + time.toString();
265 }
266
267 }
268