com.ocadotechnology.event.EventUtil Maven / Gradle / Ivy
/*
* 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