package io.dropwizard.util;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.collect.ImmutableMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
public class Duration implements Comparable<Duration> {
private static final Pattern DURATION_PATTERN = Pattern.compile("(\\d+)\\s*(\\S+)");
private static final ImmutableMap<String, TimeUnit> SUFFIXES = new ImmutableMap.Builder<String, TimeUnit>()
.put("ns", TimeUnit.NANOSECONDS)
.put("nanosecond", TimeUnit.NANOSECONDS)
.put("nanoseconds", TimeUnit.NANOSECONDS)
.put("us", TimeUnit.MICROSECONDS)
.put("microsecond", TimeUnit.MICROSECONDS)
.put("microseconds", TimeUnit.MICROSECONDS)
.put("ms", TimeUnit.MILLISECONDS)
.put("millisecond", TimeUnit.MILLISECONDS)
.put("milliseconds", TimeUnit.MILLISECONDS)
.put("s", TimeUnit.SECONDS)
.put("second", TimeUnit.SECONDS)
.put("seconds", TimeUnit.SECONDS)
.put("m", TimeUnit.MINUTES)
.put("min", TimeUnit.MINUTES)
.put("mins", TimeUnit.MINUTES)
.put("minute", TimeUnit.MINUTES)
.put("minutes", TimeUnit.MINUTES)
.put("h", TimeUnit.HOURS)
.put("hour", TimeUnit.HOURS)
.put("hours", TimeUnit.HOURS)
.put("d", TimeUnit.DAYS)
.put("day", TimeUnit.DAYS)
.put("days", TimeUnit.DAYS)
.build();
public static Duration nanoseconds(long count) {
return new Duration(count, TimeUnit.NANOSECONDS);
}
public static Duration microseconds(long count) {
return new Duration(count, TimeUnit.MICROSECONDS);
}
public static Duration milliseconds(long count) {
return new Duration(count, TimeUnit.MILLISECONDS);
}
public static Duration seconds(long count) {
return new Duration(count, TimeUnit.SECONDS);
}
public static Duration minutes(long count) {
return new Duration(count, TimeUnit.MINUTES);
}
public static Duration hours(long count) {
return new Duration(count, TimeUnit.HOURS);
}
public static Duration days(long count) {
return new Duration(count, TimeUnit.DAYS);
}
@JsonCreator
public static Duration parse(String duration) {
final Matcher matcher = DURATION_PATTERN.matcher(duration);
checkArgument(matcher.matches(), "Invalid duration: " + duration);
final long count = Long.parseLong(matcher.group(1));
final TimeUnit unit = SUFFIXES.get(matcher.group(2));
if (unit == null) {
throw new IllegalArgumentException("Invalid duration: " + duration + ". Wrong time unit");
}
return new Duration(count, unit);
}
private final long count;
private final TimeUnit unit;
private Duration(long count, TimeUnit unit) {
this.count = count;
this.unit = requireNonNull(unit);
}
public long getQuantity() {
return count;
}
public TimeUnit getUnit() {
return unit;
}
public long toNanoseconds() {
return TimeUnit.NANOSECONDS.convert(count, unit);
}
public long toMicroseconds() {
return TimeUnit.MICROSECONDS.convert(count, unit);
}
public long toMilliseconds() {
return TimeUnit.MILLISECONDS.convert(count, unit);
}
public long toSeconds() {
return TimeUnit.SECONDS.convert(count, unit);
}
public long toMinutes() {
return TimeUnit.MINUTES.convert(count, unit);
}
public long toHours() {
return TimeUnit.HOURS.convert(count, unit);
}
public long toDays() {
return TimeUnit.DAYS.convert(count, unit);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
final Duration duration = (Duration) obj;
return (count == duration.count) && (unit == duration.unit);
}
@Override
public int hashCode() {
return (31 * (int) (count ^ (count >>> 32))) + unit.hashCode();
}
@Override
@JsonValue
public String toString() {
String units = unit.toString().toLowerCase(Locale.ENGLISH);
if (count == 1) {
units = units.substring(0, units.length() - 1);
}
return Long.toString(count) + ' ' + units;
}
@Override
public int compareTo(Duration other) {
if (unit == other.unit) {
return Long.compare(count, other.count);
}
return Long.compare(toNanoseconds(), other.toNanoseconds());
}
}