org.elasticsearch.common.unit.TimeValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch Show documentation
Show all versions of elasticsearch Show documentation
Elasticsearch subproject :server
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.common.unit;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.joda.time.Period;
import org.joda.time.PeriodType;
import org.joda.time.format.PeriodFormat;
import org.joda.time.format.PeriodFormatter;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
public class TimeValue implements Writeable, Comparable {
/** How many nano-seconds in one milli-second */
public static final long NSEC_PER_MSEC = TimeUnit.NANOSECONDS.convert(1, TimeUnit.MILLISECONDS);
private static Map TIME_UNIT_BYTE_MAP;
private static Map BYTE_TIME_UNIT_MAP;
static {
final Map timeUnitByteMap = new HashMap<>();
timeUnitByteMap.put(TimeUnit.NANOSECONDS, (byte)0);
timeUnitByteMap.put(TimeUnit.MICROSECONDS, (byte)1);
timeUnitByteMap.put(TimeUnit.MILLISECONDS, (byte)2);
timeUnitByteMap.put(TimeUnit.SECONDS, (byte)3);
timeUnitByteMap.put(TimeUnit.MINUTES, (byte)4);
timeUnitByteMap.put(TimeUnit.HOURS, (byte)5);
timeUnitByteMap.put(TimeUnit.DAYS, (byte)6);
final Set bytes = new HashSet<>();
for (TimeUnit value : TimeUnit.values()) {
assert timeUnitByteMap.containsKey(value) : value;
assert bytes.add(timeUnitByteMap.get(value));
}
final Map byteTimeUnitMap = new HashMap<>();
for (Map.Entry entry : timeUnitByteMap.entrySet()) {
byteTimeUnitMap.put(entry.getValue(), entry.getKey());
}
TIME_UNIT_BYTE_MAP = Collections.unmodifiableMap(timeUnitByteMap);
BYTE_TIME_UNIT_MAP = Collections.unmodifiableMap(byteTimeUnitMap);
}
public static final TimeValue MINUS_ONE = timeValueMillis(-1);
public static final TimeValue ZERO = timeValueMillis(0);
public static TimeValue timeValueNanos(long nanos) {
return new TimeValue(nanos, TimeUnit.NANOSECONDS);
}
public static TimeValue timeValueMillis(long millis) {
return new TimeValue(millis, TimeUnit.MILLISECONDS);
}
public static TimeValue timeValueSeconds(long seconds) {
return new TimeValue(seconds, TimeUnit.SECONDS);
}
public static TimeValue timeValueMinutes(long minutes) {
return new TimeValue(minutes, TimeUnit.MINUTES);
}
public static TimeValue timeValueHours(long hours) {
return new TimeValue(hours, TimeUnit.HOURS);
}
private final long duration;
// visible for testing
long duration() {
return duration;
}
private final TimeUnit timeUnit;
// visible for testing
TimeUnit timeUnit() {
return timeUnit;
}
public TimeValue(long millis) {
this(millis, TimeUnit.MILLISECONDS);
}
public TimeValue(long duration, TimeUnit timeUnit) {
this.duration = duration;
this.timeUnit = timeUnit;
}
/**
* Read from a stream.
*/
public TimeValue(StreamInput in) throws IOException {
duration = in.readZLong();
timeUnit = BYTE_TIME_UNIT_MAP.get(in.readByte());
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeZLong(duration);
out.writeByte(TIME_UNIT_BYTE_MAP.get(timeUnit));
}
public long nanos() {
return timeUnit.toNanos(duration);
}
public long getNanos() {
return nanos();
}
public long micros() {
return timeUnit.toMicros(duration);
}
public long getMicros() {
return micros();
}
public long millis() {
return timeUnit.toMillis(duration);
}
public long getMillis() {
return millis();
}
public long seconds() {
return timeUnit.toSeconds(duration);
}
public long getSeconds() {
return seconds();
}
public long minutes() {
return timeUnit.toMinutes(duration);
}
public long getMinutes() {
return minutes();
}
public long hours() {
return timeUnit.toHours(duration);
}
public long getHours() {
return hours();
}
public long days() {
return timeUnit.toDays(duration);
}
public long getDays() {
return days();
}
public double microsFrac() {
return ((double) nanos()) / C1;
}
public double getMicrosFrac() {
return microsFrac();
}
public double millisFrac() {
return ((double) nanos()) / C2;
}
public double getMillisFrac() {
return millisFrac();
}
public double secondsFrac() {
return ((double) nanos()) / C3;
}
public double getSecondsFrac() {
return secondsFrac();
}
public double minutesFrac() {
return ((double) nanos()) / C4;
}
public double getMinutesFrac() {
return minutesFrac();
}
public double hoursFrac() {
return ((double) nanos()) / C5;
}
public double getHoursFrac() {
return hoursFrac();
}
public double daysFrac() {
return ((double) nanos()) / C6;
}
public double getDaysFrac() {
return daysFrac();
}
private final PeriodFormatter defaultFormatter = PeriodFormat.getDefault()
.withParseType(PeriodType.standard());
public String format() {
Period period = new Period(millis());
return defaultFormatter.print(period);
}
public String format(PeriodType type) {
Period period = new Period(millis());
return PeriodFormat.getDefault().withParseType(type).print(period);
}
/**
* Returns a {@link String} representation of the current {@link TimeValue}.
*
* Note that this method might produce fractional time values (ex 1.6m) which cannot be
* parsed by method like {@link TimeValue#parse(String, String, int)}.
*/
@Override
public String toString() {
if (duration < 0) {
return Long.toString(duration);
}
long nanos = nanos();
if (nanos == 0) {
return "0s";
}
double value = nanos;
String suffix = "nanos";
if (nanos >= C6) {
value = daysFrac();
suffix = "d";
} else if (nanos >= C5) {
value = hoursFrac();
suffix = "h";
} else if (nanos >= C4) {
value = minutesFrac();
suffix = "m";
} else if (nanos >= C3) {
value = secondsFrac();
suffix = "s";
} else if (nanos >= C2) {
value = millisFrac();
suffix = "ms";
} else if (nanos >= C1) {
value = microsFrac();
suffix = "micros";
}
return Strings.format1Decimals(value, suffix);
}
public String getStringRep() {
if (duration < 0) {
return Long.toString(duration);
}
switch (timeUnit) {
case NANOSECONDS:
return duration + "nanos";
case MICROSECONDS:
return duration + "micros";
case MILLISECONDS:
return duration + "ms";
case SECONDS:
return duration + "s";
case MINUTES:
return duration + "m";
case HOURS:
return duration + "h";
case DAYS:
return duration + "d";
default:
throw new IllegalArgumentException("unknown time unit: " + timeUnit.name());
}
}
public static TimeValue parseTimeValue(String sValue, String settingName) {
Objects.requireNonNull(settingName);
Objects.requireNonNull(sValue);
return parseTimeValue(sValue, null, settingName);
}
public static TimeValue parseTimeValue(String sValue, TimeValue defaultValue, String settingName) {
settingName = Objects.requireNonNull(settingName);
if (sValue == null) {
return defaultValue;
}
final String normalized = sValue.toLowerCase(Locale.ROOT).trim();
if (normalized.endsWith("nanos")) {
return new TimeValue(parse(sValue, normalized, 5), TimeUnit.NANOSECONDS);
} else if (normalized.endsWith("micros")) {
return new TimeValue(parse(sValue, normalized, 6), TimeUnit.MICROSECONDS);
} else if (normalized.endsWith("ms")) {
return new TimeValue(parse(sValue, normalized, 2), TimeUnit.MILLISECONDS);
} else if (normalized.endsWith("s")) {
return new TimeValue(parse(sValue, normalized, 1), TimeUnit.SECONDS);
} else if (sValue.endsWith("m")) {
// parsing minutes should be case sensitive as `M` is generally
// accepted to mean months not minutes. This is the only case where
// the upper and lower case forms indicate different time units
return new TimeValue(parse(sValue, normalized, 1), TimeUnit.MINUTES);
} else if (normalized.endsWith("h")) {
return new TimeValue(parse(sValue, normalized, 1), TimeUnit.HOURS);
} else if (normalized.endsWith("d")) {
return new TimeValue(parse(sValue, normalized, 1), TimeUnit.DAYS);
} else if (normalized.matches("-0*1")) {
return TimeValue.MINUS_ONE;
} else if (normalized.matches("0+")) {
return TimeValue.ZERO;
} else {
// Missing units:
throw new ElasticsearchParseException(
"failed to parse setting [{}] with value [{}] as a time value: unit is missing or unrecognized",
settingName,
sValue);
}
}
private static long parse(final String initialInput, final String normalized, final int suffixLength) {
final String s = normalized.substring(0, normalized.length() - suffixLength).trim();
try {
return Long.parseLong(s);
} catch (final NumberFormatException e) {
try {
@SuppressWarnings("unused") final double ignored = Double.parseDouble(s);
throw new ElasticsearchParseException("failed to parse [{}], fractional time values are not supported", e, initialInput);
} catch (final NumberFormatException ignored) {
throw new ElasticsearchParseException("failed to parse [{}]", e, initialInput);
}
}
}
private static final long C0 = 1L;
private static final long C1 = C0 * 1000L;
private static final long C2 = C1 * 1000L;
private static final long C3 = C2 * 1000L;
private static final long C4 = C3 * 60L;
private static final long C5 = C4 * 60L;
private static final long C6 = C5 * 24L;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return this.compareTo(((TimeValue) o)) == 0;
}
@Override
public int hashCode() {
return Double.hashCode(((double) duration) * timeUnit.toNanos(1));
}
public static long nsecToMSec(long ns) {
return ns / NSEC_PER_MSEC;
}
@Override
public int compareTo(TimeValue timeValue) {
double thisValue = ((double) duration) * timeUnit.toNanos(1);
double otherValue = ((double) timeValue.duration) * timeValue.timeUnit.toNanos(1);
return Double.compare(thisValue, otherValue);
}
}