VectorEpochTerm.java
/* Copyright 2024-2025 The Johns Hopkins University Applied Physics Laboratory
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.files.iirv.terms;
import org.orekit.files.iirv.terms.base.DoubleValuedIIRVTerm;
import org.orekit.files.iirv.terms.base.IIRVVectorTerm;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeComponents;
import org.orekit.time.UTCScale;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Locale;
/**
* Vector epoch in UTC with resolution to nearest millisecond.
* <p>
* Valid values:
* <p>
* hhmmsssss where:
* <ul>
* <li> hh = 00 to 23
* <li> mm = 00 to 59
* <li> sssss = 00000 to 59999 (milliseconds, implied decimal point three places from right)
* </ul>
*
* @author Nick LaFarge
* @since 13.0
*/
public class VectorEpochTerm extends IIRVVectorTerm<TimeComponents> {
/** The length of the IIRV term within the message. */
public static final int VECTOR_EPOCH_TERM_LENGTH = 9;
/**
* Regular expression that ensures the validity of string values for this term.
* <p>
* String in the form "hhmmsssss":
* <ul>
* <li> hh is 00 to 23: (0[0-9]|1[0-9]|2[0-3])
* <li> mm is 00 to 59: ([0-5][0-9])
* <li> sssss is 00000 to 599999: ([0-5][0-9]{4})
* </ul>
*/
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})";
/**
* Constructs from a String value.
*
* @param stringValue Day of the year (001-366)
*/
public VectorEpochTerm(final String stringValue) {
super(VECTOR_EPOCH_TERM_PATTERN, VectorEpochTerm.fromString(stringValue), VECTOR_EPOCH_TERM_LENGTH);
}
/**
* Constructs from a {@link TimeComponents} value.
*
* @param timeComponents TimeComponents value to extract vector epoch information from
*/
public VectorEpochTerm(final TimeComponents timeComponents) {
super(VECTOR_EPOCH_TERM_PATTERN, timeComponents, VECTOR_EPOCH_TERM_LENGTH);
}
/**
* Constructs from a {@link AbsoluteDate} value.
*
* @param absoluteDate AbsoluteDate value to extract vector epoch information from (in UTC)
* @param utc UTC time scale
*/
public VectorEpochTerm(final AbsoluteDate absoluteDate, final UTCScale utc) {
super(VECTOR_EPOCH_TERM_PATTERN,
absoluteDate.getComponents(utc).getTime(),
VECTOR_EPOCH_TERM_LENGTH);
}
/**
* Parses an IIRV string in format to a {@link TimeComponents} instance.
* <p>
* Format is "hhmmsssss" where the implied decimal place is three from the left (hh mm ss.sss)
*
* @param iirvString IIRV-formatted string to parse
* @return time components contained in the input string
*/
private static TimeComponents fromString(final String iirvString) {
final int hour = Integer.parseInt(iirvString.substring(0, 2));
final int minute = Integer.parseInt(iirvString.substring(2, 4));
// Convert {fullSeconds}.{fractionalSeconds} to seconds
final double second = DoubleValuedIIRVTerm.computeValueFromString(iirvString.substring(4, 9), 3);
return new TimeComponents(hour, minute, second);
}
/**
* Gets the two-character hour of the vector epoch.
*
* @return hh: hour of the vector epoch
*/
public String hh() {
return toEncodedString().substring(0, 2);
}
/**
* Gets the two-character minute of the vector epoch.
*
* @return mm: minute of the vector epoch
*/
public String mm() {
return toEncodedString().substring(2, 4);
}
/**
* Gets the two-character second of the vector epoch.
*
* @return ss: second of the vector epoch
*/
public String ss() {
return toEncodedString().substring(4, 6);
}
/** {@inheritDoc} */
@Override
public String toEncodedString(final TimeComponents value) {
final DecimalFormat secondsFormat = new DecimalFormat("00.000", new DecimalFormatSymbols(Locale.US));
final String ss_sss = secondsFormat.format(value.getSecond());
// Edge case: 60th second doesn't make sense... Round up the hour instead
if (ss_sss.charAt(0) == '6') {
final int nextSecond = 0;
int nextMinute = value.getMinute() + 1;
int nextHour = value.getHour();
if (nextMinute == 60) {
nextMinute = 0;
nextHour++;
if (nextHour == 24) {
nextHour = 0;
}
}
return toEncodedString(new TimeComponents(nextHour, nextMinute, nextSecond));
}
return String.format("%02d%02d%s",
value.getHour(),
value.getMinute(),
ss_sss.replace(".", "")
);
}
}