DateTimeComponents.java

  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. import java.io.Serializable;

  19. import org.hipparchus.util.FastMath;
  20. import org.orekit.utils.Constants;

  21. /** Holder for date and time components.
  22.  * <p>This class is a simple holder with no processing methods.</p>
  23.  * <p>Instance of this class are guaranteed to be immutable.</p>
  24.  * @see AbsoluteDate
  25.  * @see DateComponents
  26.  * @see TimeComponents
  27.  * @author Luc Maisonobe
  28.  */
  29. public class DateTimeComponents implements Serializable, Comparable<DateTimeComponents> {

  30.     /**
  31.      * The Julian Epoch.
  32.      *
  33.      * @see TimeScales#getJulianEpoch()
  34.      */
  35.     public static final DateTimeComponents JULIAN_EPOCH =
  36.             new DateTimeComponents(DateComponents.JULIAN_EPOCH, TimeComponents.H12);

  37.     /** Serializable UID. */
  38.     private static final long serialVersionUID = 5061129505488924484L;

  39.     /** Date component. */
  40.     private final DateComponents date;

  41.     /** Time component. */
  42.     private final TimeComponents time;

  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.     /** Build an instance from raw level components.
  52.      * @param year year number (may be 0 or negative for BC years)
  53.      * @param month month number from 1 to 12
  54.      * @param day day number from 1 to 31
  55.      * @param hour hour number from 0 to 23
  56.      * @param minute minute number from 0 to 59
  57.      * @param second second number from 0.0 to 60.0 (excluded)
  58.      * @exception IllegalArgumentException if inconsistent arguments
  59.      * are given (parameters out of range, february 29 for non-leap years,
  60.      * dates during the gregorian leap in 1582 ...)
  61.      */
  62.     public DateTimeComponents(final int year, final int month, final int day,
  63.                               final int hour, final int minute, final double second)
  64.         throws IllegalArgumentException {
  65.         this.date = new DateComponents(year, month, day);
  66.         this.time = new TimeComponents(hour, minute, second);
  67.     }

  68.     /** Build an instance from raw level components.
  69.      * @param year year number (may be 0 or negative for BC years)
  70.      * @param month month enumerate
  71.      * @param day day number from 1 to 31
  72.      * @param hour hour number from 0 to 23
  73.      * @param minute minute number from 0 to 59
  74.      * @param second second number from 0.0 to 60.0 (excluded)
  75.      * @exception IllegalArgumentException if inconsistent arguments
  76.      * are given (parameters out of range, february 29 for non-leap years,
  77.      * dates during the gregorian leap in 1582 ...)
  78.      */
  79.     public DateTimeComponents(final int year, final Month month, final int day,
  80.                               final int hour, final int minute, final double second)
  81.         throws IllegalArgumentException {
  82.         this.date = new DateComponents(year, month, day);
  83.         this.time = new TimeComponents(hour, minute, second);
  84.     }

  85.     /** Build an instance from raw level components.
  86.      * <p>The hour is set to 00:00:00.000.</p>
  87.      * @param year year number (may be 0 or negative for BC years)
  88.      * @param month month number from 1 to 12
  89.      * @param day day number from 1 to 31
  90.      * @exception IllegalArgumentException if inconsistent arguments
  91.      * are given (parameters out of range, february 29 for non-leap years,
  92.      * dates during the gregorian leap in 1582 ...)
  93.      */
  94.     public DateTimeComponents(final int year, final int month, final int day)
  95.         throws IllegalArgumentException {
  96.         this.date = new DateComponents(year, month, day);
  97.         this.time = TimeComponents.H00;
  98.     }

  99.     /** Build an instance from raw level components.
  100.      * <p>The hour is set to 00:00:00.000.</p>
  101.      * @param year year number (may be 0 or negative for BC years)
  102.      * @param month month enumerate
  103.      * @param day day number from 1 to 31
  104.      * @exception IllegalArgumentException if inconsistent arguments
  105.      * are given (parameters out of range, february 29 for non-leap years,
  106.      * dates during the gregorian leap in 1582 ...)
  107.      */
  108.     public DateTimeComponents(final int year, final Month month, final int day)
  109.         throws IllegalArgumentException {
  110.         this.date = new DateComponents(year, month, day);
  111.         this.time = TimeComponents.H00;
  112.     }

  113.     /** Build an instance from a seconds offset with respect to another one.
  114.      * @param reference reference date/time
  115.      * @param offset offset from the reference in seconds
  116.      * @see #offsetFrom(DateTimeComponents)
  117.      */
  118.     public DateTimeComponents(final DateTimeComponents reference,
  119.                               final double offset) {

  120.         // extract linear data from reference date/time
  121.         int    day     = reference.getDate().getJ2000Day();
  122.         double seconds = reference.getTime().getSecondsInLocalDay();

  123.         // apply offset
  124.         seconds += offset;

  125.         // fix range
  126.         final int dayShift = (int) FastMath.floor(seconds / Constants.JULIAN_DAY);
  127.         seconds -= Constants.JULIAN_DAY * dayShift;
  128.         day     += dayShift;
  129.         final TimeComponents tmpTime = new TimeComponents(seconds);

  130.         // set up components
  131.         this.date = new DateComponents(day);
  132.         this.time = new TimeComponents(tmpTime.getHour(), tmpTime.getMinute(), tmpTime.getSecond(),
  133.                                        reference.getTime().getMinutesFromUTC());

  134.     }

  135.     /** Parse a string in ISO-8601 format to build a date/time.
  136.      * <p>The supported formats are all date formats supported by {@link DateComponents#parseDate(String)}
  137.      * and all time formats supported by {@link TimeComponents#parseTime(String)} separated
  138.      * by the standard time separator 'T', or date components only (in which case a 00:00:00 hour is
  139.      * implied). Typical examples are 2000-01-01T12:00:00Z or 1976W186T210000.
  140.      * </p>
  141.      * @param string string to parse
  142.      * @return a parsed date/time
  143.      * @exception IllegalArgumentException if string cannot be parsed
  144.      */
  145.     public static DateTimeComponents parseDateTime(final String string) {

  146.         // is there a time ?
  147.         final int tIndex = string.indexOf('T');
  148.         if (tIndex > 0) {
  149.             return new DateTimeComponents(DateComponents.parseDate(string.substring(0, tIndex)),
  150.                                           TimeComponents.parseTime(string.substring(tIndex + 1)));
  151.         }

  152.         return new DateTimeComponents(DateComponents.parseDate(string), TimeComponents.H00);

  153.     }

  154.     /** Compute the seconds offset between two instances.
  155.      * @param dateTime dateTime to subtract from the instance
  156.      * @return offset in seconds between the two instants
  157.      * (positive if the instance is posterior to the argument)
  158.      * @see #DateTimeComponents(DateTimeComponents, double)
  159.      */
  160.     public double offsetFrom(final DateTimeComponents dateTime) {
  161.         final int dateOffset = date.getJ2000Day() - dateTime.date.getJ2000Day();
  162.         final double timeOffset = time.getSecondsInUTCDay() - dateTime.time.getSecondsInUTCDay();
  163.         return Constants.JULIAN_DAY * dateOffset + timeOffset;
  164.     }

  165.     /** Get the date component.
  166.      * @return date component
  167.      */
  168.     public DateComponents getDate() {
  169.         return date;
  170.     }

  171.     /** Get the time component.
  172.      * @return time component
  173.      */
  174.     public TimeComponents getTime() {
  175.         return time;
  176.     }

  177.     /** {@inheritDoc} */
  178.     public int compareTo(final DateTimeComponents other) {
  179.         final int dateComparison = date.compareTo(other.date);
  180.         if (dateComparison < 0) {
  181.             return -1;
  182.         } else if (dateComparison > 0) {
  183.             return 1;
  184.         }
  185.         return time.compareTo(other.time);
  186.     }

  187.     /** {@inheritDoc} */
  188.     public boolean equals(final Object other) {
  189.         try {
  190.             final DateTimeComponents otherDateTime = (DateTimeComponents) other;
  191.             return (otherDateTime != null) &&
  192.                    date.equals(otherDateTime.date) && time.equals(otherDateTime.time);
  193.         } catch (ClassCastException cce) {
  194.             return false;
  195.         }
  196.     }

  197.     /** {@inheritDoc} */
  198.     public int hashCode() {
  199.         return (date.hashCode() << 16) ^ time.hashCode();
  200.     }

  201.     /** Return a string representation of this pair.
  202.      * <p>The format used is ISO8601.</p>
  203.      * @return string representation of this pair
  204.      */
  205.     public String toString() {
  206.         return toString(60);
  207.     }

  208.     /** Return a string representation of this pair.
  209.      * <p>The format used is ISO8601.</p>
  210.      * @param minuteDuration 60 or 61 depending on the date being
  211.      * close to a leap second introduction
  212.      * @return string representation of this pair
  213.      */
  214.     public String toString(final int minuteDuration) {
  215.         double second = time.getSecond();
  216.         final double wrap = minuteDuration - 0.0005;
  217.         if (second >= wrap) {
  218.             // we should wrap around next millisecond
  219.             int minute = time.getMinute();
  220.             int hour   = time.getHour();
  221.             int j2000  = date.getJ2000Day();
  222.             second = 0;
  223.             ++minute;
  224.             if (minute > 59) {
  225.                 minute = 0;
  226.                 ++hour;
  227.                 if (hour > 23) {
  228.                     hour = 0;
  229.                     ++j2000;
  230.                 }
  231.             }
  232.             return new DateComponents(j2000).toString() + 'T' + new TimeComponents(hour, minute, second).toString();
  233.         }
  234.         return date.toString() + 'T' + time.toString();
  235.     }

  236. }