1   /* Copyright 2022-2026 Romain Serra
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 org.orekit.errors.OrekitException;
20  import org.orekit.errors.OrekitMessages;
21  
22  /**
23   * Interface representing a closed time interval i.e. [a, b], possibly of infinite length.
24   *
25   * @author Romain Serra
26   * @since 13.1
27   * @see AbsoluteDate
28   */
29  public interface TimeInterval {
30  
31      /** Interval covering the entire timeline
32       * from {@link AbsoluteDate#PAST_INFINITY} to {@link AbsoluteDate#FUTURE_INFINITY}.
33       * @since 14.0
34       */
35      TimeInterval UNLIMITED = TimeInterval.of(AbsoluteDate.PAST_INFINITY, AbsoluteDate.FUTURE_INFINITY, true);
36  
37      /**
38       * Getter for the left end of the interval.
39       * @return left end
40       */
41      AbsoluteDate getStartDate();
42  
43      /**
44       * Getter for the right end of the interval.
45       * @return right end
46       */
47      AbsoluteDate getEndDate();
48  
49      /**
50       * Computes the interval length in seconds.
51       * @return duration
52       */
53      default double duration() {
54          return getEndDate().durationFrom(getStartDate());
55      }
56  
57      /**
58       * Method returning true if and only if the dated input is contained within the closed interval.
59       * @param timeStamped time stamped object
60       * @return boolean on inclusion
61       */
62      default boolean contains(final TimeStamped timeStamped) {
63          final AbsoluteDate date = timeStamped.getDate();
64          return getStartDate().isBeforeOrEqualTo(date) && getEndDate().isAfterOrEqualTo(date);
65      }
66  
67      /**
68       * Method returning true if and only if input (also a closed time interval) contains the instance.
69       * @param interval time interval
70       * @return boolean on inclusion
71       */
72      default boolean contains(final TimeInterval interval) {
73          return (getEndDate().isAfterOrEqualTo(interval.getEndDate())) && (getStartDate().isBeforeOrEqualTo(interval.getStartDate()));
74      }
75  
76      /**
77       * Method returning true if and only if input (also a closed time interval) intersects the instance.
78       * @param interval time interval
79       * @return boolean on intersection
80       */
81      default boolean intersects(final TimeInterval interval) {
82          return (getEndDate().isAfterOrEqualTo(interval.getStartDate())) && (getStartDate().isBeforeOrEqualTo(interval.getEndDate()));
83      }
84  
85      /**
86       * Create instance from two dates.
87       *
88       * @param date                  date
89       * @param otherDate             other date
90       * @param allowNonChronological if true, the two dates can be in arbitrary order,
91       *                              they will be sorted internally. If false and {@code otherDate}
92       *                              is before {@code date}, then an exception is triggered
93       * @return time interval
94       * @since 14.0
95       */
96      static TimeInterval of(final AbsoluteDate date, final AbsoluteDate otherDate,
97                             final boolean allowNonChronological) {
98  
99          // check order
100         final AbsoluteDate start;
101         final AbsoluteDate end;
102         if (otherDate.isBefore(date)) {
103             if (allowNonChronological) {
104                 // reorder dates
105                 start = otherDate;
106                 end   = date;
107             } else {
108                 throw new OrekitException(OrekitMessages.NON_CHRONOLOGICALLY_SORTED_ENTRIES,
109                                           date, otherDate, date.durationFrom(otherDate));
110             }
111         } else {
112             start = date;
113             end   = otherDate;
114         }
115 
116         // create instance
117         return new TimeInterval() {
118 
119             /** {@inheritDoc} */
120             @Override
121             public AbsoluteDate getStartDate() {
122                 return start;
123             }
124 
125             /** {@inheritDoc} */
126             @Override
127             public AbsoluteDate getEndDate() {
128                 return end;
129             }
130 
131         };
132 
133     }
134 
135     /**
136      * Create instance from two dates in arbitrary order.
137      * @param date date
138      * @param otherDate other date
139      * @return time interval
140      */
141     static TimeInterval of(final AbsoluteDate date, final AbsoluteDate otherDate) {
142         return of(date, otherDate, true);
143     }
144 
145     /**
146      * Create instance from two dates in arbitrary order.
147      * @param date start (or end) date
148      * @param duration duration, in seconds (if positive, time interval is from date to date + duration,
149      *                 if negative, the time interval will be from date - duration to date)
150      * @return time interval
151      * @since 14.0
152      */
153     static TimeInterval of(final AbsoluteDate date, final double duration) {
154         return of(date, date.shiftedBy(duration), true);
155     }
156 
157 }