com.geotab.model.serialization.DurationSerializationUtil Maven / Gradle / Ivy
/*
*
* 2020 Copyright (C) Geotab Inc. All rights reserved.
*/
package com.geotab.model.serialization;
import java.time.Duration;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DurationFormatUtils;
/**
* Serialization helper used to convert {@link Duration} to and from {@link String}.
*
* Expected {@link Duration} pattern is [-][d.]hh:mm:ss[.fffffff] , as explained in
* https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-timespan-format-strings .
*/
@UtilityClass
public class DurationSerializationUtil {
public static Duration durationFromString(String durationString) {
if (StringUtils.isEmpty(durationString)) {
return null;
}
Duration duration = Duration.ZERO;
boolean isNegated = false;
if (durationString.startsWith("-")) {
durationString = durationString.substring(1);
isNegated = true;
}
// 1.00:00:00 (1 days)
int dotIndex = durationString.indexOf('.');
if (dotIndex > -1 && dotIndex < 4) {
String[] dayParts = durationString.split("\\.");
duration = addDays(duration, dayParts[0]);
durationString = durationString.substring(dotIndex + 1);
}
String[] parts = durationString.split(":");
if (parts.length != 3) {
throw new IllegalArgumentException(
"Unexpected duration pattern for value " + durationString
+ " . Expected pattern is [-][d.]hh:mm:ss[.fffffff]");
}
duration = addHoursAndMinutes(duration, parts);
duration = addSecondsAndNanos(duration, parts[2]);
return isNegated ? duration.negated() : duration;
}
public static String durationToString(Duration duration) {
if (duration == null) {
return null;
}
String format = "HH:mm:ss";
if (duration.toDays() != 0) {
format = "d.".concat(format);
}
if (duration.isNegative()) {
duration = duration.negated();
format = "-".concat(format);
}
if (duration.toNanos() % 1_000_000_000 > 0) { // 1 sec = 1_000_000_000 nanos
long ticks = duration.getNano() / 100;
// if ticks are in the hundred thousand's range or less,then prepend with zeros up to 7 digits
format = format.concat(".'" + String.format("%07d", ticks) + "'");
}
return DurationFormatUtils.formatDuration(duration.toMillis(), format, true);
}
private static Duration addDays(Duration duration, String daysPart) {
int days = Integer.parseInt(daysPart);
return duration.plusDays(days);
}
private static Duration addHoursAndMinutes(Duration duration, String[] parts) {
int hours = Integer.parseInt(parts[0]);
int minutes = Integer.parseInt(parts[1]);
return duration.plusHours(hours).plusMinutes(minutes);
}
private static Duration addSecondsAndNanos(Duration duration, String secondsAndTicks) {
int seconds;
long ticks = 0;
// 00:14:44.0630001 (with ticks)
if (secondsAndTicks.contains(".")) {
String[] secondsParts = secondsAndTicks.split("\\.");
seconds = Integer.parseInt(secondsParts[0]);
// in case there are less the 7 digits for ticks, then append zeros up to 7 digits
ticks = Long.parseLong(String.format("%0$-7s", secondsParts[1]));
} else {
seconds = Integer.parseInt(secondsAndTicks);
}
return duration.plusSeconds(seconds).plusNanos(ticks * 100);
}
}