VectorEpochTerm.java

  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. import org.orekit.files.iirv.terms.base.DoubleValuedIIRVTerm;
  19. import org.orekit.files.iirv.terms.base.IIRVVectorTerm;
  20. import org.orekit.time.AbsoluteDate;
  21. import org.orekit.time.TimeComponents;
  22. import org.orekit.time.UTCScale;

  23. import java.text.DecimalFormat;
  24. import java.text.DecimalFormatSymbols;
  25. import java.util.Locale;

  26. /**
  27.  * Vector epoch in UTC with resolution to nearest millisecond.
  28.  * <p>
  29.  * Valid values:
  30.  * <p>
  31.  * hhmmsssss where:
  32.  * <ul>
  33.  * <li> hh = 00 to 23
  34.  * <li> mm = 00 to 59
  35.  * <li> sssss = 00000 to 59999 (milliseconds, implied decimal point three places from right)
  36.  * </ul>
  37.  *
  38.  * @author Nick LaFarge
  39.  * @since 13.0
  40.  */
  41. public class VectorEpochTerm extends IIRVVectorTerm<TimeComponents> {

  42.     /** The length of the IIRV term within the message. */
  43.     public static final int VECTOR_EPOCH_TERM_LENGTH = 9;

  44.     /**
  45.      * Regular expression that ensures the validity of string values for this term.
  46.      * <p>
  47.      * String in the form "hhmmsssss":
  48.      * <ul>
  49.      * <li> hh is 00 to 23: (0[0-9]|1[0-9]|2[0-3])
  50.      * <li> mm is 00 to 59: ([0-5][0-9])
  51.      * <li> sssss is 00000 to 599999: ([0-5][0-9]{4})
  52.      * </ul>
  53.      */
  54.     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})";

  55.     /**
  56.      * Constructs from a String value.
  57.      *
  58.      * @param stringValue Day of the year (001-366)
  59.      */
  60.     public VectorEpochTerm(final String stringValue) {
  61.         super(VECTOR_EPOCH_TERM_PATTERN, VectorEpochTerm.fromString(stringValue), VECTOR_EPOCH_TERM_LENGTH);
  62.     }

  63.     /**
  64.      * Constructs from a {@link TimeComponents} value.
  65.      *
  66.      * @param timeComponents TimeComponents value to extract vector epoch information from
  67.      */
  68.     public VectorEpochTerm(final TimeComponents timeComponents) {
  69.         super(VECTOR_EPOCH_TERM_PATTERN, timeComponents, VECTOR_EPOCH_TERM_LENGTH);
  70.     }

  71.     /**
  72.      * Constructs from a {@link AbsoluteDate} value.
  73.      *
  74.      * @param absoluteDate AbsoluteDate value to extract vector epoch information from (in UTC)
  75.      * @param utc          UTC time scale
  76.      */
  77.     public VectorEpochTerm(final AbsoluteDate absoluteDate, final UTCScale utc) {
  78.         super(VECTOR_EPOCH_TERM_PATTERN,
  79.             absoluteDate.getComponents(utc).getTime(),
  80.             VECTOR_EPOCH_TERM_LENGTH);
  81.     }

  82.     /**
  83.      * Parses an IIRV string in  format to a {@link TimeComponents} instance.
  84.      * <p>
  85.      * Format is "hhmmsssss" where the implied decimal place is three from the left (hh mm ss.sss)
  86.      *
  87.      * @param iirvString IIRV-formatted string to parse
  88.      * @return time components contained in the input string
  89.      */
  90.     private static TimeComponents fromString(final String iirvString) {
  91.         final int hour = Integer.parseInt(iirvString.substring(0, 2));
  92.         final int minute = Integer.parseInt(iirvString.substring(2, 4));

  93.         // Convert {fullSeconds}.{fractionalSeconds} to seconds
  94.         final double second = DoubleValuedIIRVTerm.computeValueFromString(iirvString.substring(4, 9), 3);

  95.         return new TimeComponents(hour, minute, second);
  96.     }

  97.     /**
  98.      * Gets the two-character hour of the vector epoch.
  99.      *
  100.      * @return hh: hour of the vector epoch
  101.      */
  102.     public String hh() {
  103.         return toEncodedString().substring(0, 2);
  104.     }

  105.     /**
  106.      * Gets the two-character minute of the vector epoch.
  107.      *
  108.      * @return mm: minute of the vector epoch
  109.      */
  110.     public String mm() {
  111.         return toEncodedString().substring(2, 4);
  112.     }

  113.     /**
  114.      * Gets the two-character second of the vector epoch.
  115.      *
  116.      * @return ss: second of the vector epoch
  117.      */
  118.     public String ss() {
  119.         return toEncodedString().substring(4, 6);
  120.     }


  121.     /** {@inheritDoc} */
  122.     @Override
  123.     public String toEncodedString(final TimeComponents value) {

  124.         final DecimalFormat secondsFormat = new DecimalFormat("00.000", new DecimalFormatSymbols(Locale.US));
  125.         final String ss_sss = secondsFormat.format(value.getSecond());

  126.         // Edge case: 60th second doesn't make sense... Round up the hour instead
  127.         if (ss_sss.charAt(0) == '6') {
  128.             final int nextSecond = 0;
  129.             int nextMinute = value.getMinute() + 1;
  130.             int nextHour = value.getHour();
  131.             if (nextMinute == 60) {
  132.                 nextMinute = 0;
  133.                 nextHour++;
  134.                 if (nextHour == 24) {
  135.                     nextHour = 0;
  136.                 }
  137.             }
  138.             return toEncodedString(new TimeComponents(nextHour, nextMinute, nextSecond));
  139.         }

  140.         return String.format("%02d%02d%s",
  141.             value.getHour(),
  142.             value.getMinute(),
  143.             ss_sss.replace(".", "")
  144.         );
  145.     }
  146. }