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

com.ocadotechnology.event.EventUtil Maven / Gradle / Ivy

There is a newer version: 16.6.21
Show newest version
/*
 * Copyright © 2017-2023 Ocado (Ocava)
 *
 * Licensed 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 com.ocadotechnology.event;

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;

import javax.annotation.Nullable;

import com.google.common.base.Preconditions;
import com.ocadotechnology.physics.units.TimeUnitConverter;

/**
 * Utilities for converting time values to readable strings. Supports timestamps corresponding to dates no earlier than
 * 0001-01-01 00:00:00.000.
 *
 * Currently asserts that the time unit for all schedulers is 1ms.
 */
public class EventUtil {
    private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
    private static final DateTimeFormatter isoDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
    private static final DateTimeFormatter dateTimeWithoutMsFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final DateTimeFormatter bigQueryDateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'");

    private static final ZoneId UTC = ZoneId.of("UTC");
    private static final long MIN_TIMESTAMP = -62135596800000L;  // 0001-01-01 00:00:00.000

    private static TimeUnit simulationTimeUnit = TimeUnit.SECONDS; // Default to assuming the simulation runs in seconds

    /**
     * Sets the simulation time unit to allow for conversion to a standard display format
     *
     * @param timeUnit the timeUnit that inputs to this class will be using
     */
    public static void setSimulationTimeUnit(TimeUnit timeUnit) {
        simulationTimeUnit = timeUnit;
    }

    private static String eventTimeToFormat(double eventTime, DateTimeFormatter dateTimeFormatter) {
        return Double.isFinite(eventTime)
                ? milliEventTimeToFormat(TimeUnitConverter.toTimeUnitLong(eventTime, simulationTimeUnit, TimeUnit.MILLISECONDS), dateTimeFormatter)
                : Double.toString(eventTime);
    }

    private static String eventTimeToFormat(long eventTime, DateTimeFormatter dateTimeFormatter) {
        return milliEventTimeToFormat(TimeUnitConverter.toTimeUnitLong(eventTime, simulationTimeUnit, TimeUnit.MILLISECONDS), dateTimeFormatter);
    }

    private static String milliEventTimeToFormat(long eventTimeInMillis, DateTimeFormatter dateTimeFormatter) {
        Preconditions.checkArgument(eventTimeInMillis >= MIN_TIMESTAMP, "Timestamp is before 0001-01-01 00:00:00.000: %s", eventTimeInMillis);
        return dateTimeFormatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(eventTimeInMillis), UTC));
    }

    /**
     * Returns a string representation of the given timestamp, if finite. If the corresponding year has fewer than 4
     * digits, it will be padded by zeros (e.g., 0034), and if it has 5 or more digits it will be prefixed with '+'
     * (e.g., +10000). For Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY or Double.NAN, the string representation
     * of those values will be returned.
     *
     * @param eventTime The timestamp to convert.
     *
     * @throws IllegalArgumentException If the timestamp corresponds to a time prior to 0001-01-01 00:00:00.000, or
     * later than 292278994-08-17 07:12:54.784. Note that, due to rounding calculations, the maximum supported timestamp
     * is slightly smaller than for the equivalent methods which accept a long or Long value.
     */
    public static String eventTimeToString(double eventTime) {
        return eventTimeToFormat(eventTime, dateTimeFormatter);
    }

    /**
     * Returns a string representation of the given timestamp, if finite. If the corresponding year has fewer than 4
     * digits, it will be padded by zeros (e.g., 0034), and if it has 5 or more digits it will be prefixed with '+'
     * (e.g., +10000). For values corresponding to Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NAN, or
     * null, the string representation of those values will be returned.
     *
     * @param eventTime The timestamp to convert.
     *
     * @throws IllegalArgumentException If the timestamp corresponds to a time prior to 0001-01-01 00:00:00.000, or
     * later than 292278994-08-17 07:12:54.784. Note that, due to rounding calculations, the maximum supported timestamp
     * is slightly smaller than for the equivalent methods which accept a long or Long value.
     */
    public static String eventTimeToString(@Nullable Double eventTime) {
        return eventTime == null
                ? "null"
                : eventTimeToString(eventTime.doubleValue());
    }

    /**
     * Returns a string representation of the given timestamp. If the corresponding year has fewer than 4 digits, it
     * will be padded by zeros (e.g., 0034), and if it has 5 or more digits it will be prefixed with '+' (e.g., +10000).
     *
     * @param eventTime The timestamp to convert.
     *
     * @throws IllegalArgumentException If the timestamp corresponds to a time prior to 0001-01-01 00:00:00.000 or
     *          greater than Long.MAX_VALUE milliseconds.
     */
    public static String eventTimeToString(long eventTime) {
        return eventTimeToFormat(eventTime, dateTimeFormatter);
    }

    /**
     * Returns a string representation of the given timestamp, or "null" if the timestamp is null. If the corresponding
     * year has fewer than 4 digits, it will be padded by zeros (e.g., 0034), and if it has 5 or more digits it will be
     * prefixed with '+' (e.g., +10000).
     *
     * @param eventTime The timestamp to convert.
     *
     * @throws IllegalArgumentException If the timestamp corresponds to a time prior to 0001-01-01 00:00:00.000 or
     *          greater than Long.MAX_VALUE milliseconds.
     */
    public static String eventTimeToString(@Nullable Long eventTime) {
        return eventTime == null
                ? "null"
                : eventTimeToString(eventTime.longValue());
    }

    public static String eventTimeToIsoString(double eventTime) {
        return eventTimeToFormat(eventTime, isoDateTimeFormatter);
    }

    public static String eventTimeToStringWithoutMs(double eventTime) {
        return eventTimeToFormat(eventTime, dateTimeWithoutMsFormatter);
    }

    public static String eventTimeToBigQueryString(double eventTime) {
        return eventTimeToFormat(eventTime, bigQueryDateTimeFormatter);
    }

    /**
     * Generates a computation for formatting a timestamp.
     * 

* Many loggers defer the actual log-line formatting. For example:
* * logger.info("Scheduling missiles for {}", EventUtil.logTime(now + durationToSafeDistance)); *
* Here, EventUtil.logTime is always called regardless of the actual log level. *
* But, if the log level is higher than info, the log line will never be formatted and toString * will never be called, which depending on how many millions of log lines are generated may save significant computation. *
* Further, many logging libraries off-load the log line formatting to separate threads, so the * original thread may never incur the toString penalty. * In thise case, using logTime instead of eventTimeToString is * at least two orders of magnitude faster (for the calling thread). * * @param eventTime The timestamp to convert * @return an Object where toString returns the same as EventUtil.eventTimeToString */ public static Object logTime(double eventTime) { return new Object() { public String toString() { return eventTimeToString(eventTime); } }; } /** * Generates a computation for formatting a (possibly null) timestamp. *

* This may provide faster logging; see {@link #logTime(double)} * * @param eventTime The timestamp to convert * @return an Object where toString returns the same as EventUtil.eventTimeToString */ public static Object logTime(@Nullable Double eventTime) { return new Object() { public String toString() { return eventTimeToString(eventTime); } }; } /** * Generates a computation for formatting a timestamp. *

* This may provide faster logging; see {@link #logTime(double)} * * @param eventTime The timestamp to convert * @return an Object where toString returns the same as EventUtil.eventTimeToString */ public static Object logTime(long eventTime) { return new Object() { public String toString() { return eventTimeToString(eventTime); } }; } /** * Generates a computation for formatting a (possibly null) timestamp. *

* This may provide faster logging; see {@link #logTime(double)} * * @param eventTime The timestamp to convert * @return an Object where toString returns the same as EventUtil.eventTimeToString */ public static Object logTime(@Nullable Long eventTime) { return new Object() { public String toString() { return eventTimeToString(eventTime); } }; } public static String durationToString(double duration) { Duration d = Duration.ofMillis((long) duration); long seconds = d.getSeconds(); long absSeconds = Math.abs(seconds); String positive = String.format( "%02d:%02d:%02d.%03d", absSeconds / 3600, (absSeconds % 3600) / 60, absSeconds % 60, Math.abs(d.toMillis()) % 1000); return seconds < 0 ? "-" + positive : positive; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy