/* This file is part of GNUnet. Copyright (C) 2011, 2012 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.gnunet.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Positive amount of time with no point of reference. * * @author Florian Dold */ public final class RelativeTime implements Comparable { private static final Logger logger = LoggerFactory .getLogger(RelativeTime.class); public static final RelativeTime MICROSECOND = new RelativeTime(1); public static final RelativeTime MILLISECOND = MICROSECOND.multiply(1000); public static final RelativeTime SECOND = MILLISECOND.multiply(1000); public static final RelativeTime MINUTE = SECOND.multiply(60); public static final RelativeTime HOUR = MINUTE.multiply(60); public static final RelativeTime DAY = HOUR.multiply(24); public static final RelativeTime WEEK = DAY.multiply(7); public static final RelativeTime MONTH = DAY.multiply(30); public static final RelativeTime YEAR = DAY.multiply(365); public static final RelativeTime ZERO = new RelativeTime(0); public static final RelativeTime FOREVER = new RelativeTime(Long.MAX_VALUE); public static final RelativeTime STD_BACKOFF = MILLISECOND; public static final RelativeTime STD_BACKOFF_MAX = MINUTE.multiply(15); /** * Time offset in microseconds. */ private final long rel_value_us; /** * Create a new RelativeTime value, with a given time in milliseconds. * * @param abs_value time in milliseconds */ public RelativeTime(final long abs_value) { this.rel_value_us = abs_value; } public static RelativeTime fromMilliseconds(final long ms) { return new RelativeTime(ms * 1000); } public static RelativeTime fromMicroseconds(final long us) { return new RelativeTime(us); } /** * Add relative times together. * * @param other * the other timestamp * * @return this + other */ public RelativeTime add(final RelativeTime other) { if (this.rel_value_us == Long.MAX_VALUE || other.rel_value_us == Long.MAX_VALUE) { return RelativeTime.FOREVER; } final long new_rel_value = this.rel_value_us + other.rel_value_us; // check for numeric overflow if (new_rel_value < this.rel_value_us) { logger.warn("time overflow"); return RelativeTime.FOREVER; } return new RelativeTime(new_rel_value); } /** * Divide relative time by a given factor. * * @param factor * integer to divide by * @return FOREVER if this=FOREVER or factor=0; otherwise this/factor */ public RelativeTime divide(final int factor) { if (factor == 0 || this.rel_value_us == Long.MAX_VALUE) { return RelativeTime.FOREVER; } return new RelativeTime(this.rel_value_us / factor); } /** * Returns the amount of time in milliseconds. * * @return the amount of time in milliseconds */ public long getMicroseconds() { return rel_value_us; } /** * Return the maximum of two relative time values. * * @return max(t1, t2) */ public static RelativeTime max(RelativeTime t1, RelativeTime t2) { return t1.rel_value_us >= t2.rel_value_us ? t1 : t2; } /** * Return the minimum of two relative time values. * * @return min(this, other) */ public static RelativeTime min(RelativeTime t1, RelativeTime t2) { return t1.rel_value_us <= t2.rel_value_us ? t1 : t2; } /** * Multiply relative time by a given factor. * * @return FOREVER if this=FOREVER or on overflow; otherwise this*factor */ public RelativeTime multiply(final int factor) { if (factor == 0) { return RelativeTime.ZERO; } final long ret = this.rel_value_us * factor; // check for numeric overflow if (ret / factor != rel_value_us) { logger.warn("time overflow"); return RelativeTime.FOREVER; } return new RelativeTime(ret); } /** * Subtract relative timestamp from the other. * * @param other * second timestamp * @return ZERO if other>=this (including both FOREVER), FOREVER if * this=FOREVER, this-other otherwise */ public RelativeTime subtract(final RelativeTime other) { if (this.rel_value_us >= other.rel_value_us) { return RelativeTime.ZERO; } else if (this.rel_value_us == Long.MAX_VALUE) { return this; } else { return new RelativeTime(this.rel_value_us - other.rel_value_us); } } /** * Converts relative time to an absolute time in the future. * * @return timestamp that is in the future, or FOREVER if this=FOREVER (or * if we would overflow) */ public AbsoluteTime toAbsolute() { return AbsoluteTime.now().add(this); } public boolean isForever() { return rel_value_us == FOREVER.rel_value_us; } public boolean equals(Object o) { return (o instanceof RelativeTime) && ((RelativeTime) o).rel_value_us == rel_value_us; } @Override public int hashCode() { return (int) this.rel_value_us; } @Override public int compareTo(RelativeTime other) { if (this.rel_value_us < other.rel_value_us) { return -1; } if (this.rel_value_us > other.rel_value_us) { return 1; } return 0; } @Override public String toString() { if (this.isForever()) { return "RelativeTime(FOREVER)"; } return "RelativeTime("+this.rel_value_us +")"; } public RelativeTimeMessage toNetwork() { long rval = this.rel_value_us; assert rval >= 0; if (rval == FOREVER.rel_value_us) { rval = -1L; /* 0xFFFFFFFFFFFFFFFF for network format! */ } return new RelativeTimeMessage(rval); } public static RelativeTime fromNetwork(RelativeTimeMessage m) { if (m.value__ < 0) { return RelativeTime.FOREVER; } else { return new RelativeTime(m.value__); } } public RelativeTime backoff() { return RelativeTime.min(STD_BACKOFF_MAX, this.multiply(2)); } public long getSeconds() { return rel_value_us / (1000 * 1000); } public static RelativeTime fromSeconds(long i) { RelativeTime relativeTime = new RelativeTime(i * 1000 * 1000); return relativeTime; } }