DateTimeComponents.java

  1. /* Copyright 2002-2018 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. 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.     /** Serializable UID. */
  31.     private static final long serialVersionUID = 5061129505488924484L;

  32.     /** Date component. */
  33.     private final DateComponents date;

  34.     /** Time component. */
  35.     private final TimeComponents time;

  36.     /** Build a new instance from its components.
  37.      * @param date date component
  38.      * @param time time component
  39.      */
  40.     public DateTimeComponents(final DateComponents date, final TimeComponents time) {
  41.         this.date = date;
  42.         this.time = time;
  43.     }

  44.     /** Build an instance from raw level components.
  45.      * @param year year number (may be 0 or negative for BC years)
  46.      * @param month month number from 1 to 12
  47.      * @param day day number from 1 to 31
  48.      * @param hour hour number from 0 to 23
  49.      * @param minute minute number from 0 to 59
  50.      * @param second second number from 0.0 to 60.0 (excluded)
  51.      * @exception IllegalArgumentException if inconsistent arguments
  52.      * are given (parameters out of range, february 29 for non-leap years,
  53.      * dates during the gregorian leap in 1582 ...)
  54.      */
  55.     public DateTimeComponents(final int year, final int month, final int day,
  56.                               final int hour, final int minute, final double second)
  57.         throws IllegalArgumentException {
  58.         this.date = new DateComponents(year, month, day);
  59.         this.time = new TimeComponents(hour, minute, second);
  60.     }

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

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

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

  106.     /** Build an instance from a seconds offset with respect to another one.
  107.      * @param reference reference date/time
  108.      * @param offset offset from the reference in seconds
  109.      * @see #offsetFrom(DateTimeComponents)
  110.      */
  111.     public DateTimeComponents(final DateTimeComponents reference,
  112.                               final double offset) {

  113.         // extract linear data from reference date/time
  114.         int    day     = reference.getDate().getJ2000Day();
  115.         double seconds = reference.getTime().getSecondsInLocalDay();

  116.         // apply offset
  117.         seconds += offset;

  118.         // fix range
  119.         final int dayShift = (int) FastMath.floor(seconds / Constants.JULIAN_DAY);
  120.         seconds -= Constants.JULIAN_DAY * dayShift;
  121.         day     += dayShift;
  122.         final TimeComponents tmpTime = new TimeComponents(seconds);

  123.         // set up components
  124.         this.date = new DateComponents(day);
  125.         this.time = new TimeComponents(tmpTime.getHour(), tmpTime.getMinute(), tmpTime.getSecond(),
  126.                                        reference.getTime().getMinutesFromUTC());

  127.     }

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

  139.         // is there a time ?
  140.         final int tIndex = string.indexOf('T');
  141.         if (tIndex > 0) {
  142.             return new DateTimeComponents(DateComponents.parseDate(string.substring(0, tIndex)),
  143.                                           TimeComponents.parseTime(string.substring(tIndex + 1)));
  144.         }

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

  146.     }

  147.     /** Compute the seconds offset between two instances.
  148.      * @param dateTime dateTime to subtract from the instance
  149.      * @return offset in seconds between the two instants
  150.      * (positive if the instance is posterior to the argument)
  151.      * @see #DateTimeComponents(DateTimeComponents, double)
  152.      */
  153.     public double offsetFrom(final DateTimeComponents dateTime) {
  154.         final int dateOffset = date.getJ2000Day() - dateTime.date.getJ2000Day();
  155.         final double timeOffset = time.getSecondsInUTCDay() - dateTime.time.getSecondsInUTCDay();
  156.         return Constants.JULIAN_DAY * dateOffset + timeOffset;
  157.     }

  158.     /** Get the date component.
  159.      * @return date component
  160.      */
  161.     public DateComponents getDate() {
  162.         return date;
  163.     }

  164.     /** Get the time component.
  165.      * @return time component
  166.      */
  167.     public TimeComponents getTime() {
  168.         return time;
  169.     }

  170.     /** {@inheritDoc} */
  171.     public int compareTo(final DateTimeComponents other) {
  172.         final int dateComparison = date.compareTo(other.date);
  173.         if (dateComparison < 0) {
  174.             return -1;
  175.         } else if (dateComparison > 0) {
  176.             return 1;
  177.         }
  178.         return time.compareTo(other.time);
  179.     }

  180.     /** {@inheritDoc} */
  181.     public boolean equals(final Object other) {
  182.         try {
  183.             final DateTimeComponents otherDateTime = (DateTimeComponents) other;
  184.             return (otherDateTime != null) &&
  185.                    date.equals(otherDateTime.date) && time.equals(otherDateTime.time);
  186.         } catch (ClassCastException cce) {
  187.             return false;
  188.         }
  189.     }

  190.     /** {@inheritDoc} */
  191.     public int hashCode() {
  192.         return (date.hashCode() << 16) ^ time.hashCode();
  193.     }

  194.     /** Return a string representation of this pair.
  195.      * <p>The format used is ISO8601.</p>
  196.      * @return string representation of this pair
  197.      */
  198.     public String toString() {
  199.         return toString(60);
  200.     }

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

  229. }