All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yamcs.utils.TimeEncoding Maven / Gradle / Ivy

There is a newer version: 5.10.9
Show newest version
package org.yamcs.utils;

import java.io.InputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.yamcs.time.Instant;
import org.yamcs.utils.TaiUtcConverter.ValidityLine;

import com.google.protobuf.Timestamp;

/**
 *
 * This class provides times in terms of milliseconds since 1970TAI
 * 
 * @author nm
 *
 */
public class TimeEncoding {
    public static final long INVALID_INSTANT = Long.MIN_VALUE;
    public static long MAX_INSTANT = 185539080470435999L;
    public static final long MIN_INSTANT = Long.MIN_VALUE + 1;

    // these two are used for open intervals
    public static final long NEGATIVE_INFINITY = MIN_INSTANT - 1;
    public static final long POSITIVE_INFINITY = MAX_INSTANT + 1;

    static final long GPS_EPOCH_YAMCS_EPOCH_DELTA = 315964819000L;
    static final long TAI_EPOCH_YAMCS_EPOCH_DELTA = -378691200000L;
    static final long J2000_EPOCH_YAMCS_EPOCH_DELTA = 946727967816L;

    static final long GPS_TAI_DELTA = 19000;

    static TaiUtcConverter taiUtcConverter;
    static Pattern iso8601Pattern = Pattern
            .compile("(\\d+)\\-(\\d{2})\\-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(\\.(\\d{3})\\d{0,9})?Z?");
    static Pattern doyPattern = Pattern.compile("(\\d+)\\/(\\d+)T(\\d{2}):(\\d{2}):(\\d{2})(\\.(\\d{3})\\d{0,9})?Z?");

    static Pattern iso8601PatternHres = Pattern
            .compile("(\\d+)\\-(\\d{2})\\-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(\\.(\\d{3})(\\d{0,9}))?Z?");
    static Pattern doyPatternHres = Pattern
            .compile("(\\d+)\\/(\\d+)T(\\d{2}):(\\d{2}):(\\d{2})(\\.(\\d{3})(\\d{0,9}))?Z?");

    public static void setUp() {
        try {
            taiUtcConverter = new TaiUtcConverter();
            MAX_INSTANT = 185539080470399999L + taiUtcConverter.diffTaiUtc * 1000;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void setUp(InputStream in) {
        try {
            taiUtcConverter = new TaiUtcConverter(in);
            MAX_INSTANT = 185539080470399999L + taiUtcConverter.diffTaiUtc * 1000;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Returns the current operating system time but converted to Yamcs instant.
     * 
     * @return
     */
    public static long getWallclockTime() {
        return taiUtcConverter.unixToInstant(System.currentTimeMillis());
    }

    /**
     * Sane as {@link #getWallclockTime()} but returns a high resolution instant.
     * 

* Currently java does not make it easy to get a high resolution time so the returned object has always the * picosecond field set to 0. * * @return */ public static Instant getWallclockHresTime() { long millis = taiUtcConverter.unixToInstant(System.currentTimeMillis()); return Instant.get(millis); } private static void formatOn2Digits(int x, StringBuilder sb) { if (x < 10) { sb.append("0").append(x); } else { sb.append(x); } } private static void formatOn3Digits(int x, StringBuilder sb) { if (x < 10) { sb.append("00").append(x); } else if (x < 100) { sb.append("0").append(x); } else { sb.append(x); } } private static void formatOn4Digits(int x, StringBuilder sb) { if (x < 10) { sb.append("000").append(x); } else if (x < 100) { sb.append("00").append(x); } else if (x < 1000) { sb.append("0").append(x); } else { sb.append(x); } } /** * Returns the instant formatted as UTC yyyy-MM-DDTHH:mm:ss.SSSZ *

* If the value is smalle than {@link #MIN_INSTANT} it returns -inf * * If the value is larger than {@link #MAX_INSTANT} it returns +inf * * @param instant * @return */ public static String toString(long instant) { if (instant < MIN_INSTANT) { return "-inf"; } if (instant > MAX_INSTANT) { return "+inf"; } TaiUtcConverter.DateTimeComponents dtc = taiUtcConverter.instantToUtc(instant); StringBuilder sb = new StringBuilder(); formatOn4Digits(dtc.year, sb); sb.append("-"); formatOn2Digits(dtc.month, sb); sb.append("-"); formatOn2Digits(dtc.day, sb); sb.append("T"); formatOn2Digits(dtc.hour, sb); sb.append(":"); formatOn2Digits(dtc.minute, sb); sb.append(":"); formatOn2Digits(dtc.second, sb); sb.append("."); formatOn3Digits(dtc.millisec, sb); return sb.append("Z").toString(); } /** * Returns the instant formatted as UTC yyyy-DDDTHH:mm:ss.SSS * * @param instant * @return */ public static String toOrdinalDateTime(long instant) { TaiUtcConverter.DateTimeComponents dtc = taiUtcConverter.instantToUtc(instant); StringBuilder sb = new StringBuilder(); formatOn4Digits(dtc.year, sb); sb.append("-"); formatOn3Digits(dtc.doy, sb); sb.append("T"); formatOn2Digits(dtc.hour, sb); sb.append(":"); formatOn2Digits(dtc.minute, sb); sb.append(":"); formatOn2Digits(dtc.second, sb); sb.append("."); formatOn3Digits(dtc.millisec, sb); return sb.toString(); } /** * Returns the instant in UTC time scale formatted as YYYY-DDDTHHhMMmSSsSSS so that is leads to an MS Windows * compatible filename * * @param instant * @return */ public static String toWinCompatibleDateTime(long instant) { TaiUtcConverter.DateTimeComponents dtc = taiUtcConverter.instantToUtc(instant); StringBuilder sb = new StringBuilder(); formatOn4Digits(dtc.year, sb); sb.append("-"); formatOn3Digits(dtc.doy, sb); sb.append("T"); formatOn2Digits(dtc.hour, sb); sb.append("h"); formatOn2Digits(dtc.minute, sb); sb.append("m"); formatOn2Digits(dtc.second, sb); sb.append("s"); formatOn3Digits(dtc.millisec, sb); return sb.toString(); } public static String toCombinedFormat(long instant) { TaiUtcConverter.DateTimeComponents dtc = taiUtcConverter.instantToUtc(instant); StringBuilder sb = new StringBuilder(); formatOn4Digits(dtc.year, sb); sb.append("-"); formatOn2Digits(dtc.month, sb); sb.append("-"); formatOn2Digits(dtc.day, sb); sb.append("/"); formatOn3Digits(dtc.doy, sb); sb.append("T"); formatOn2Digits(dtc.hour, sb); sb.append(":"); formatOn2Digits(dtc.minute, sb); sb.append(":"); formatOn2Digits(dtc.second, sb); sb.append("."); formatOn3Digits(dtc.millisec, sb); return sb.toString(); } /** * we assume coarseTime to be always positive (corresponding to uint32_t in C) * * @param coarseTime * number of seconds from GPS epoch * @param fineTime * number of 1/256 seconds * @return */ public static long fromGpsCcsdsTime(int coarseTime, byte fineTime) { long c = ((long) coarseTime) & 0xFFFFFFFFL; return GPS_EPOCH_YAMCS_EPOCH_DELTA + c * 1000 + 1000 * (0xFF & fineTime) / 256; } /** * Conversion from instant to GPS time. * * @param instant * yamcs time * @return GPS time */ public static GpsCcsdsTime toGpsTime(final long instant) { long shiftedMillis = instant - GPS_EPOCH_YAMCS_EPOCH_DELTA; int coarseTime = (int) (shiftedMillis / 1000); byte fineTime = (byte) (((shiftedMillis % 1000) * 256 / 1000)); return new GpsCcsdsTime(coarseTime, fineTime); } /** * Conversion from current instant to GPS time. Current time is the *nix time this function is called. * * @return GPS time */ public static GpsCcsdsTime getCurrentGpsTime() { return toGpsTime(TimeEncoding.getWallclockTime()); } /** * Conversion from instant to GPS time (milliseconds since the GPS epoch). * * @param instant * TimeEncoding instant * * @return GPS time */ public static long toGpsTimeMillisec(final long instant) { return instant - GPS_EPOCH_YAMCS_EPOCH_DELTA; } public static long fromGpsYearSecMillis(int year, int secOfYear, int millis) { Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); cal.clear(); cal.set(Calendar.YEAR, year); cal.add(Calendar.SECOND, secOfYear); cal.add(Calendar.MILLISECOND, millis); return GPS_TAI_DELTA + cal.getTimeInMillis(); } public static TaiUtcConverter.DateTimeComponents toUtc(long instant) { return taiUtcConverter.instantToUtc(instant); } public static long fromUtc(TaiUtcConverter.DateTimeComponents dtc) { return taiUtcConverter.utcToInstant(dtc); } public static List getTaiUtcConversionTable() { return taiUtcConverter.lines; } /** * parses an ISO 8601 UTC date into an instant * * @param s * - string to be parsed * @return - internal Yamcs timestamp * @throws IllegalArgumentException * if the time cannot be parsed */ public static long parse(String s) { TaiUtcConverter.DateTimeComponents dtc; Matcher m = iso8601Pattern.matcher(s); if (m.matches()) { int year = Integer.parseInt(m.group(1)); int month = Integer.parseInt(m.group(2)); int day = Integer.parseInt(m.group(3)); int hour = Integer.parseInt(m.group(4)); int minute = Integer.parseInt(m.group(5)); int second = Integer.parseInt(m.group(6)); int millisec = 0; if (m.group(7) != null) { millisec = Integer.parseInt(m.group(8)); } dtc = new TaiUtcConverter.DateTimeComponents(year, month, day, hour, minute, second, millisec); } else { m = doyPattern.matcher(s); if (m.matches()) { int year = Integer.parseInt(m.group(1)); int doy = Integer.parseInt(m.group(2)); int hour = Integer.parseInt(m.group(3)); int minute = Integer.parseInt(m.group(4)); int second = Integer.parseInt(m.group(5)); int millisec = 0; if (m.group(6) != null) { millisec = Integer.parseInt(m.group(7)); } dtc = new TaiUtcConverter.DateTimeComponents(year, doy, hour, minute, second, millisec); } else { throw new IllegalArgumentException( "Cannot parse '" + s + "' with the pattern '" + iso8601Pattern + " or " + doyPattern); } } return taiUtcConverter.utcToInstant(dtc); } public static Instant parseHres(String s) { TaiUtcConverter.DateTimeComponents dtc; Matcher m = iso8601PatternHres.matcher(s); int picos = 0; if (m.matches()) { int year = Integer.parseInt(m.group(1)); int month = Integer.parseInt(m.group(2)); int day = Integer.parseInt(m.group(3)); int hour = Integer.parseInt(m.group(4)); int minute = Integer.parseInt(m.group(5)); int second = Integer.parseInt(m.group(6)); int millisec = 0; if (m.group(7) != null) { millisec = Integer.parseInt(m.group(8)); picos = getPicos(m.group(9)); } dtc = new TaiUtcConverter.DateTimeComponents(year, month, day, hour, minute, second, millisec); } else { m = doyPatternHres.matcher(s); if (m.matches()) { int year = Integer.parseInt(m.group(1)); int doy = Integer.parseInt(m.group(2)); int hour = Integer.parseInt(m.group(3)); int minute = Integer.parseInt(m.group(4)); int second = Integer.parseInt(m.group(5)); int millisec = 0; if (m.group(6) != null) { millisec = Integer.parseInt(m.group(7)); picos = getPicos(m.group(9)); } dtc = new TaiUtcConverter.DateTimeComponents(year, doy, hour, minute, second, millisec); } else { throw new IllegalArgumentException( "Cannot parse '" + s + "' with the pattern '" + iso8601Pattern + " or " + doyPattern); } } long millis = taiUtcConverter.utcToInstant(dtc); return Instant.get(millis, picos); } // get the number of picoseconds from a max to 9 digits number aligned at left static private int getPicos(String ps) { if (ps.length() == 0) { return 0; } int r = Integer.parseInt(ps); for (int i = ps.length(); i < 9; i++) { r *= 10; } return r; } /** * Transforms UNIX time (milliseconds since 1970, picos in millisecond) to high resolution instant * * @param millis * milliseconds since 1970 (without leap seconds) * @param picos * picoseconds in milliseconds - can be negative or larger than 10^9 (but has to fit into a 32 bit signed * integer). * * @return */ public static Instant fromUnixPicos(long millis, int picos) { return Instant.get(taiUtcConverter.unixToInstant(millis), picos); } /** * Transforms UNIX time (milliseconds since 1970) to instant * * @param milliseconds * @return */ public static long fromUnixMillisec(long milliseconds) { return taiUtcConverter.unixToInstant(milliseconds); } /** * Transforms UNIX time expressed in seconds and microseconds since 1970 to instant WARNING: this conversion will * lose precision (microsecond to millisecond) * * @param seconds * @param microseconds * @return */ public static long fromUnixTime(long seconds, int microseconds) { long millisec = seconds * 1000 + microseconds / 1000; return taiUtcConverter.unixToInstant(millisec); } /** * Transforms instant to UNIX time expressed in milliseconds since 1970 * * @param instant * @return */ public static long toUnixMillisec(long instant) { return taiUtcConverter.instantToUnix(instant); } /** * Transforms a {@link java.util.Calendar} from UNIX (millisec since 1970) to instant */ public static long fromCalendar(Calendar cal) { return fromUnixMillisec(cal.getTimeInMillis()); } /** * Transforms a {@link java.util.Date} from UNIX (millisec since 1970) to instant */ public static long fromDate(Date date) { return fromUnixMillisec(date.getTime()); } /** * Transforms a {@link java.time.Instant} from UNIX (millisec since 1970) to instant */ public static long fromJavaInstant(java.time.Instant instant) { return fromUnixMillisec(instant.toEpochMilli()); } /** * Transforms instant into a {@link java.util.Calendar} containing milliseconds since 1970 * * @param instant * Yamcs instant */ public static Calendar toCalendar(long instant) { if (instant == TimeEncoding.INVALID_INSTANT) { return null; } long t = taiUtcConverter.instantToUnix(instant); Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(t); return cal; } /** * Transforms instant into a {@link java.time.Instant} containing milliseconds since 1970 * * @param instant * Yamcs instant */ public static java.time.Instant toJavaInstant(long instant) { if (instant == TimeEncoding.INVALID_INSTANT) { return null; } long t = taiUtcConverter.instantToUnix(instant); return java.time.Instant.ofEpochMilli(t); } /** * JavaGps is number of milliseconds since 1970 that assumes no leap seconds from 1970 to GPS Epoch, and then * continues with the leap seconds. * * @param instant * @return */ public static long getJavaGpsFromInstant(long instant) { return instant - 19000; } public static long getInstantfromJavaGps(long javagps) { return javagps + 19000; } /** * * @param gpstime * number of millisec from GPS epoch * @return */ public static long fromGpsMillisec(long gpstime) { return gpstime + GPS_EPOCH_YAMCS_EPOCH_DELTA; } public static long fromTaiMillisec(long taitime) { return taitime + TAI_EPOCH_YAMCS_EPOCH_DELTA; } public static long toTaiMillisec(long instant) { return instant - TAI_EPOCH_YAMCS_EPOCH_DELTA; } public static long fromJ2000Millisec(long j2000time) { return j2000time + J2000_EPOCH_YAMCS_EPOCH_DELTA; } public static long toJ2000Millisec(long instant) { return instant - J2000_EPOCH_YAMCS_EPOCH_DELTA; } /** * Transforms protobuf Timestamp to instant. The conversion will do the "unsmearing" around the leap seconds and * will also lose precision (nanoseconds to milliseconds). * * @see https://developers.google.com/time/smear * * @param ts * - the timestamp to be converted * @return */ public static long fromProtobufTimestamp(Timestamp ts) { return taiUtcConverter.protobufToInstant(ts); } /** * Transforms protobuf Timestamp to high resolution instant. The conversion will do the "unsmearing" around the leap * seconds. * * @see https://developers.google.com/time/smear * * @param ts * - the timestamp to be converted * @return */ public static Instant fromProtobufHresTimestamp(Timestamp ts) { return taiUtcConverter.protobufToHresInstant(ts); } /** * Transforms the instant to protobuf timestamp performing the smearing around the leap seconds. * * @see https://developers.google.com/time/smear * * @param instant * - the instant to be converted * @return */ public static Timestamp toProtobufTimestamp(long instant) { return taiUtcConverter.instantToProtobuf(Instant.get(instant)); } /** * Transforms the instant to protobuf timestamp performing the smearing around the leap seconds. * * @see https://developers.google.com/time/smear * * @param instant * - the instant to be converted * @return */ public static Timestamp toProtobufTimestamp(Instant instant) { return taiUtcConverter.instantToProtobuf(instant); } /** * returns true if the {@link #setUp()} method has been called to load the leap second table. *

* If this method returns false, any call to the UTC conversion functions will throw a NullPointerException */ public static boolean isSetUp() { return taiUtcConverter != null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy