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