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

org.apache.brooklyn.util.time.Duration Maven / Gradle / Ivy

Go to download

Utility classes and methods developed for Brooklyn but not dependendent on Brooklyn or much else

There is a newer version: 1.1.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF 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.apache.brooklyn.util.time;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.concurrent.TimeUnit;

import javax.annotation.Nullable;

import org.apache.brooklyn.util.text.Strings;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;

/** simple class determines a length of time */
public class Duration implements Comparable, Serializable {

    private static final long serialVersionUID = -2303909964519279617L;
    
    public static final Duration ZERO = of(0, null);
    public static final Duration ONE_MILLISECOND = of(1, TimeUnit.MILLISECONDS);
    public static final Duration ONE_SECOND = of(1, TimeUnit.SECONDS);
    public static final Duration FIVE_SECONDS = of(5, TimeUnit.SECONDS);
    public static final Duration TEN_SECONDS = of(10, TimeUnit.SECONDS);
    public static final Duration THIRTY_SECONDS = of(30, TimeUnit.SECONDS);
    public static final Duration ONE_MINUTE = of(1, TimeUnit.MINUTES);
    public static final Duration TWO_MINUTES = of(2, TimeUnit.MINUTES);
    public static final Duration FIVE_MINUTES = of(5, TimeUnit.MINUTES);
    public static final Duration ONE_HOUR = of(1, TimeUnit.HOURS);
    public static final Duration ONE_DAY = of(1, TimeUnit.DAYS);
    
    /** longest supported duration, 2^{63}-1 nanoseconds, approx ten billion seconds, or 300 years */ 
    public static final Duration PRACTICALLY_FOREVER = of(Long.MAX_VALUE, TimeUnit.NANOSECONDS);

    private final long nanos;

    public Duration(long value, TimeUnit unit) {
        if (value != 0) {
            Preconditions.checkNotNull(unit, "Cannot accept null timeunit (unless value is 0)");
        } else {
            unit = TimeUnit.MILLISECONDS;
        }
        nanos = TimeUnit.NANOSECONDS.convert(value, unit);
    }

    @Override
    public int compareTo(Duration o) {
        return ((Long)toNanoseconds()).compareTo(o.toNanoseconds());
    }

    @Override
    public String toString() {
        return Time.makeTimeStringExact(this);
    }

    public String toStringRounded() {
        return Time.makeTimeStringRounded(this);
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Duration)) return false;
        return toMilliseconds() == ((Duration)o).toMilliseconds();
    }

    @Override
    public int hashCode() {
        return Long.valueOf(toMilliseconds()).hashCode();
    }

    /** converts to the given {@link TimeUnit}, using {@link TimeUnit#convert(long, TimeUnit)} which rounds _down_
     * (so 1 nanosecond converted to milliseconds gives 0 milliseconds, and -1 ns gives -1 ms) */
    public long toUnit(TimeUnit unit) {
        return unit.convert(nanos, TimeUnit.NANOSECONDS);
    }

    /** as {@link #toUnit(TimeUnit)} but rounding as indicated
     * (rather than always taking the floor which is TimeUnit's default behaviour) */
    public long toUnit(TimeUnit unit, RoundingMode rounding) {
        long result = unit.convert(nanos, TimeUnit.NANOSECONDS);
        long check = TimeUnit.NANOSECONDS.convert(result, unit);
        if (check==nanos || rounding==null || rounding==RoundingMode.UNNECESSARY) return result;
        return new BigDecimal(nanos).divide(new BigDecimal(unit.toNanos(1)), rounding).longValue();
    }

    /** as {@link #toUnit(TimeUnit)} but rounding away from zero,
     * so 1 ns converted to ms gives 1 ms, and -1 ns gives 1ms */
    public long toUnitRoundingUp(TimeUnit unit) {
        return toUnit(unit, RoundingMode.UP);
    }

    public long toMilliseconds() {
        return toUnit(TimeUnit.MILLISECONDS);
    }

    /** as {@link #toMilliseconds()} but rounding away from zero (so 1 nanosecond gets rounded to 1 millisecond);
     * see {@link #toUnitRoundingUp(TimeUnit)}; provided as a convenience on top of {@link #toUnit(TimeUnit, RoundingMode)}
     * as this is a common case (when you want to make sure you wait at least a certain amount of time) */
    public long toMillisecondsRoundingUp() {
        return toUnitRoundingUp(TimeUnit.MILLISECONDS);
    }

    public long toNanoseconds() {
        return nanos;
    }

    public long toSeconds() {
        return toUnit(TimeUnit.SECONDS);
    }

    /** number of nanoseconds of this duration */
    public long nanos() {
        return nanos;
    }

    /** 
     * See {@link Time#parseElapsedTime(String)}; 
     * also accepts "forever" (and for those who prefer things exceedingly accurate, "practically_forever").
     * If null or blank or 'null' is passed in, then null will be returned. 
     * Also see {@link #of(Object)}.
     */
    public static Duration parse(String textualDescription) {
        if (Strings.isBlank(textualDescription)) return null;
        if ("null".equalsIgnoreCase(textualDescription)) return null;
        
        if ("forever".equalsIgnoreCase(textualDescription)) return Duration.PRACTICALLY_FOREVER;
        if ("practicallyforever".equalsIgnoreCase(textualDescription)) return Duration.PRACTICALLY_FOREVER;
        if ("practically_forever".equalsIgnoreCase(textualDescription)) return Duration.PRACTICALLY_FOREVER;
        
        return new Duration((long) Time.parseElapsedTimeAsDouble(textualDescription), TimeUnit.MILLISECONDS);
    }

    /** creates new {@link Duration} instance of the given length of time */
    public static Duration days(Number n) {
        return new Duration((long) (n.doubleValue() * TimeUnit.DAYS.toNanos(1)), TimeUnit.NANOSECONDS);
    }

    /** creates new {@link Duration} instance of the given length of time */
    public static Duration hours(Number n) {
        return new Duration((long) (n.doubleValue() * TimeUnit.HOURS.toNanos(1)), TimeUnit.NANOSECONDS);
    }

    /** creates new {@link Duration} instance of the given length of time */
    public static Duration minutes(Number n) {
        return new Duration((long) (n.doubleValue() * TimeUnit.MINUTES.toNanos(1)), TimeUnit.NANOSECONDS);
    }

    /** creates new {@link Duration} instance of the given length of time */
    public static Duration seconds(Number n) {
        return new Duration((long) (n.doubleValue() * TimeUnit.SECONDS.toNanos(1)), TimeUnit.NANOSECONDS);
    }

    /** creates new {@link Duration} instance of the given length of time */
    public static Duration millis(Number n) {
        return new Duration((long) (n.doubleValue() * TimeUnit.MILLISECONDS.toNanos(1)), TimeUnit.NANOSECONDS);
    }

    /** creates new {@link Duration} instance of the given length of time */
    public static Duration micros(Number n) {
        return new Duration((long) (n.doubleValue() * TimeUnit.MICROSECONDS.toNanos(1)), TimeUnit.NANOSECONDS);
    }

    /** creates new {@link Duration} instance of the given length of time */
    public static Duration nanos(Number n) {
        return new Duration(n.longValue(), TimeUnit.NANOSECONDS);
    }

    public static Function millisToStringRounded() { return millisToStringRounded; }
    private static Function millisToStringRounded = new Function() {
            @Override
            @Nullable
            public String apply(@Nullable Number input) {
                if (input == null) return null;
                return Duration.millis(input).toStringRounded();
            }
        };

    public static Function secondsToStringRounded() { return secondsToStringRounded; }
    private static Function secondsToStringRounded = new Function() {
            @Override
            @Nullable
            public String apply(@Nullable Number input) {
                if (input == null) return null;
                return Duration.seconds(input).toStringRounded();
            }
        };

    /**
     * Converts the given object to a Duration by attempting the following in order:
     * 
    *
  1. return null if the object is null
  2. *
  3. {@link #parse(String) parse} the object as a string
  4. *
  5. treat numbers as milliseconds
  6. *
  7. obtain the elapsed time of a {@link Stopwatch}
  8. *
  9. invoke the object's toMilliseconds method, if one exists.
  10. *
* If none of these cases work the method throws an {@link IllegalArgumentException}. */ public static Duration of(Object o) { if (o == null) return null; if (o instanceof Duration) return (Duration)o; if (o instanceof String) return parse((String)o); if (o instanceof Number) return millis((Number)o); if (o instanceof Stopwatch) return millis(((Stopwatch)o).elapsed(TimeUnit.MILLISECONDS)); try { // this allows it to work with groovy TimeDuration Method millisMethod = o.getClass().getMethod("toMilliseconds"); return millis((Long)millisMethod.invoke(o)); } catch (Exception e) { // probably no such method } throw new IllegalArgumentException("Cannot convert "+o+" (type "+o.getClass()+") to a duration"); } public static Duration of(long value, TimeUnit unit) { return new Duration(value, unit); } public static Duration max(Duration first, Duration second) { return checkNotNull(first, "first").nanos >= checkNotNull(second, "second").nanos ? first : second; } public static Duration min(Duration first, Duration second) { return checkNotNull(first, "first").nanos <= checkNotNull(second, "second").nanos ? first : second; } public static Duration untilUtc(long millisSinceEpoch) { return millis(millisSinceEpoch - System.currentTimeMillis()); } public static Duration sinceUtc(long millisSinceEpoch) { return millis(System.currentTimeMillis() - millisSinceEpoch); } public Duration add(Duration other) { return nanos(nanos() + other.nanos()); } public Duration subtract(Duration other) { return nanos(nanos() - other.nanos()); } public Duration multiply(long x) { return nanos(nanos() * x); } /** @deprecated since 0.10.0 use {@link #multiply} instead. */ @Deprecated public Duration times(long x) { return multiply(x); } /** as #multiply(long), but approximate due to the division (nano precision) */ public Duration multiply(double d) { return nanos(nanos() * d); } public Duration half() { return multiply(0.5); } /** see {@link Time#sleep(long)} */ public static void sleep(Duration duration) { Time.sleep(duration); } /** returns a new started {@link CountdownTimer} with this duration */ public CountdownTimer countdownTimer() { return CountdownTimer.newInstanceStarted(this); } public boolean isPositive() { return nanos() > 0; } public boolean isNegative() { return nanos() < 0; } public boolean isLongerThan(Duration x) { return compareTo(x) > 0; } public boolean isLongerThan(Stopwatch stopwatch) { return isLongerThan(Duration.millis(stopwatch.elapsed(TimeUnit.MILLISECONDS))); } public boolean isShorterThan(Duration x) { return compareTo(x) < 0; } public boolean isShorterThan(Stopwatch stopwatch) { return isShorterThan(Duration.millis(stopwatch.elapsed(TimeUnit.MILLISECONDS))); } /** returns the larger of this value or the argument */ public Duration lowerBound(Duration alternateMinimumValue) { if (isShorterThan(alternateMinimumValue)) return alternateMinimumValue; return this; } /** returns the smaller of this value or the argument */ public Duration upperBound(Duration alternateMaximumValue) { if (isLongerThan(alternateMaximumValue)) return alternateMaximumValue; return this; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy