1 /* Copyright 2002-2026 CS GROUP
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.utils;
18
19 import org.hipparchus.util.RyuDouble;
20 import org.orekit.time.DateTimeComponents;
21
22 /** Formatter used to produce strings from data with high accuracy.
23 * <p>
24 * When producing test output from computed data, we want the shortest
25 * decimal representation of a floating point number that maintains
26 * round-trip safety. That is, a correct parser can recover the exact
27 * original number.
28 * </p>
29 * <p>
30 * For efficiency, this class uses the {@link RyuDouble Ryƫ} algorithm
31 * for producing shortest string representation with round-trip safety.
32 * </p>
33 * @author Luc Maisonobe
34 * @since 11.0
35 */
36 public class AccurateFormatter implements Formatter {
37
38 /** Low switch level for exponential format in dates (will never be reached due to {@link #LOW_TRUNCATION}). */
39 private static final int LOW_EXP = -18;
40
41 /** Truncation level for seconds, to avoid scientific format. */
42 private static final double LOW_TRUNCATION = 1.0e-15;
43
44 /** Public constructor.
45 */
46 public AccurateFormatter() {
47 // nothing to do
48 }
49
50 /** Formats to full accuracy.
51 * {@inheritDoc}
52 */
53 @Override
54 public String toString(final double value) {
55 return RyuDouble.doubleToString(value);
56 }
57
58 /** Formats the seconds variable with maximum precision needed.
59 * {@inheritDoc}
60 */
61 @Override
62 public String toString(final int year, final int month, final int day,
63 final int hour, final int minute, final double seconds) {
64 final double truncated = seconds < LOW_TRUNCATION ? 0.0 : seconds;
65 final String s = RyuDouble.doubleToString(truncated, LOW_EXP, RyuDouble.DEFAULT_HIGH_EXP);
66 return String.format(STANDARDIZED_LOCALE, DATE_FORMAT,
67 year, month, day,
68 hour, minute, s.charAt(1) == '.' ? "0" + s : s);
69 }
70
71 /**
72 * Format date time components to make use of attosecond accuracy from {@link org.orekit.time.TimeOffset}.
73 * It relies on the {@link DateTimeComponents#toStringWithoutUtcOffset()} method to display date time.
74 *
75 * @param dt date time components to be formatted
76 * @return date formatted to match the following format [yyyy-MM-ddTHH:mm:ss.S#]
77 * @since 13.1.6
78 */
79 @Override
80 public String toString(final DateTimeComponents dt) {
81 return dt.toStringWithoutUtcOffset();
82 }
83 }