1 /* Copyright 2024-2025 The Johns Hopkins University Applied Physics Laboratory
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.files.iirv.terms;
18
19 import org.orekit.files.iirv.terms.base.DoubleValuedIIRVTerm;
20 import org.orekit.files.iirv.terms.base.IIRVVectorTerm;
21 import org.orekit.time.AbsoluteDate;
22 import org.orekit.time.TimeComponents;
23 import org.orekit.time.UTCScale;
24
25 import java.text.DecimalFormat;
26 import java.text.DecimalFormatSymbols;
27 import java.util.Locale;
28
29 /**
30 * Vector epoch in UTC with resolution to nearest millisecond.
31 * <p>
32 * Valid values:
33 * <p>
34 * hhmmsssss where:
35 * <ul>
36 * <li> hh = 00 to 23
37 * <li> mm = 00 to 59
38 * <li> sssss = 00000 to 59999 (milliseconds, implied decimal point three places from right)
39 * </ul>
40 *
41 * @author Nick LaFarge
42 * @since 13.0
43 */
44 public class VectorEpochTerm extends IIRVVectorTerm<TimeComponents> {
45
46 /** The length of the IIRV term within the message. */
47 public static final int VECTOR_EPOCH_TERM_LENGTH = 9;
48
49 /**
50 * Regular expression that ensures the validity of string values for this term.
51 * <p>
52 * String in the form "hhmmsssss":
53 * <ul>
54 * <li> hh is 00 to 23: (0[0-9]|1[0-9]|2[0-3])
55 * <li> mm is 00 to 59: ([0-5][0-9])
56 * <li> sssss is 00000 to 599999: ([0-5][0-9]{4})
57 * </ul>
58 */
59 public static final String VECTOR_EPOCH_TERM_PATTERN = "(0[0-9]|1[0-9]|2[0-3])([0-5][0-9])([0-5][0-9]{4})";
60
61 /**
62 * Constructs from a String value.
63 *
64 * @param stringValue Day of the year (001-366)
65 */
66 public VectorEpochTerm(final String stringValue) {
67 super(VECTOR_EPOCH_TERM_PATTERN, VectorEpochTerm.fromString(stringValue), VECTOR_EPOCH_TERM_LENGTH);
68 }
69
70 /**
71 * Constructs from a {@link TimeComponents} value.
72 *
73 * @param timeComponents TimeComponents value to extract vector epoch information from
74 */
75 public VectorEpochTerm(final TimeComponents timeComponents) {
76 super(VECTOR_EPOCH_TERM_PATTERN, timeComponents, VECTOR_EPOCH_TERM_LENGTH);
77 }
78
79 /**
80 * Constructs from a {@link AbsoluteDate} value.
81 *
82 * @param absoluteDate AbsoluteDate value to extract vector epoch information from (in UTC)
83 * @param utc UTC time scale
84 */
85 public VectorEpochTerm(final AbsoluteDate absoluteDate, final UTCScale utc) {
86 super(VECTOR_EPOCH_TERM_PATTERN,
87 absoluteDate.getComponents(utc).getTime(),
88 VECTOR_EPOCH_TERM_LENGTH);
89 }
90
91 /**
92 * Parses an IIRV string in format to a {@link TimeComponents} instance.
93 * <p>
94 * Format is "hhmmsssss" where the implied decimal place is three from the left (hh mm ss.sss)
95 *
96 * @param iirvString IIRV-formatted string to parse
97 * @return time components contained in the input string
98 */
99 private static TimeComponents fromString(final String iirvString) {
100 final int hour = Integer.parseInt(iirvString.substring(0, 2));
101 final int minute = Integer.parseInt(iirvString.substring(2, 4));
102
103 // Convert {fullSeconds}.{fractionalSeconds} to seconds
104 final double second = DoubleValuedIIRVTerm.computeValueFromString(iirvString.substring(4, 9), 3);
105
106 return new TimeComponents(hour, minute, second);
107 }
108
109 /**
110 * Gets the two-character hour of the vector epoch.
111 *
112 * @return hh: hour of the vector epoch
113 */
114 public String hh() {
115 return toEncodedString().substring(0, 2);
116 }
117
118 /**
119 * Gets the two-character minute of the vector epoch.
120 *
121 * @return mm: minute of the vector epoch
122 */
123 public String mm() {
124 return toEncodedString().substring(2, 4);
125 }
126
127 /**
128 * Gets the two-character second of the vector epoch.
129 *
130 * @return ss: second of the vector epoch
131 */
132 public String ss() {
133 return toEncodedString().substring(4, 6);
134 }
135
136
137 /** {@inheritDoc} */
138 @Override
139 public String toEncodedString(final TimeComponents value) {
140
141 final DecimalFormat secondsFormat = new DecimalFormat("00.000", new DecimalFormatSymbols(Locale.US));
142 final String ss_sss = secondsFormat.format(value.getSecond());
143
144 // Edge case: 60th second doesn't make sense... Round up the hour instead
145 if (ss_sss.charAt(0) == '6') {
146 final int nextSecond = 0;
147 int nextMinute = value.getMinute() + 1;
148 int nextHour = value.getHour();
149 if (nextMinute == 60) {
150 nextMinute = 0;
151 nextHour++;
152 if (nextHour == 24) {
153 nextHour = 0;
154 }
155 }
156 return toEncodedString(new TimeComponents(nextHour, nextMinute, nextSecond));
157 }
158
159 return String.format("%02d%02d%s",
160 value.getHour(),
161 value.getMinute(),
162 ss_sss.replace(".", "")
163 );
164 }
165 }