Skip to content

Instantly share code, notes, and snippets.

@dblevins
Created December 3, 2009 21:11
Show Gist options
  • Save dblevins/248523 to your computer and use it in GitHub Desktop.
Save dblevins/248523 to your computer and use it in GitHub Desktop.
/**
* 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.
*/
import java.beans.PropertyEditorManager;
import java.util.concurrent.TimeUnit;
public class Duration {
public static enum Unit {
// All lowercase so they look good displayed in help
NANOSECONDS(1), MICROSECONDS(1000), MILLISECONDS(1000), SECONDS(1000), MINUTES(60), HOURS(60), DAYS(24), WEEKS(7);
private int multiplier;
Unit(int multiplier) {
this.multiplier = multiplier;
}
public int getMultiplier() {
return multiplier;
}
public long convert(Duration duration) {
return convert(duration.getTime(), duration.getUnit());
}
public static Unit unit(TimeUnit unit) {
switch (unit) {
case NANOSECONDS:
return Unit.NANOSECONDS;
case MICROSECONDS:
return Unit.MICROSECONDS;
case MILLISECONDS:
return Unit.MILLISECONDS;
case SECONDS:
return Unit.SECONDS;
default:
throw new IllegalArgumentException("Unknown TimeUnit " + unit);
}
}
public long convert(long time, TimeUnit unit) {
return this.convert(time, unit(unit));
}
public long convert(long time, Unit unit) {
if (this.ordinal() > unit.ordinal()) {
Unit[] units = Unit.values();
for (int i = unit.ordinal() + 1; i <= this.ordinal(); i++) {
time = time / units[i].getMultiplier();
}
} else if (this.ordinal() < unit.ordinal()) {
Unit[] units = Unit.values();
for (int i = unit.ordinal(); i > this.ordinal(); i--) {
time = time * units[i].getMultiplier();
}
}
return time;
}
}
private long time;
private Unit unit = Unit.MILLISECONDS;
public Duration() {
}
public Duration(long time, Unit unit) {
if (unit == null) throw new NullPointerException("unit");
this.time = time;
this.unit = unit;
}
public Duration(String string) {
parse(string, this);
}
public Duration to(Unit unit) {
return new Duration(unit.convert(this.time, this.unit), unit);
}
public Duration to(TimeUnit timeUnit) {
return to(Unit.unit(timeUnit));
}
public long convert(Unit unit) {
return this.unit.convert(this.time, unit);
}
public long convert(TimeUnit unit) {
return this.unit.convert(this.time, unit);
}
public Unit getUnit() {
return unit;
}
public long getTime() {
return time;
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Duration that = (Duration) o;
Unit base = Unit.values()[Math.min(this.getUnit().ordinal(), that.getUnit().ordinal())];
long a = base.convert(this.getTime(), this.getUnit());
long b = base.convert(that.getTime(), that.getUnit());
return a == b;
}
public int hashCode() {
int result;
result = (int) (time ^ (time >>> 32));
result = 29 * result + (unit != null ? unit.hashCode() : 0);
return result;
}
public String toString() {
if (unit == null) {
return time + "";
} else {
return time + " " + unit;
}
}
public static Duration parse(String text) {
Duration d = new Duration();
parse(text, d);
return d;
}
private static void parse(String text, Duration d) {
text = text.trim();
StringBuilder t = new StringBuilder();
StringBuilder u = new StringBuilder();
int i = 0;
// get the number
for (; i < text.length(); i++) {
char c = text.charAt(i);
if (Character.isDigit(c) || i == 0 && c == '-') {
t.append(c);
} else {
break;
}
}
if (t.length() == 0) {
invalidFormat(text);
}
// skip whitespace
for (; i < text.length(); i++) {
char c = text.charAt(i);
if (Character.isWhitespace(c)) {
} else {
break;
}
}
// get time unit text part
for (; i < text.length(); i++) {
char c = text.charAt(i);
if (Character.isLetter(c)) {
u.append(c);
} else {
invalidFormat(text);
}
}
d.time = Integer.parseInt(t.toString());
d.unit = parseUnit(u.toString());
}
public static Duration parseMultitple(String string) {
String[] strings = string.split(",| and ");
Duration duration = new Duration(0, Unit.MILLISECONDS);
for (String s : strings) {
Duration part = new Duration(s);
duration = duration.add(part);
}
return duration;
}
public Duration add(Duration that) {
Unit base = Unit.values()[Math.min(this.getUnit().ordinal(), that.getUnit().ordinal())];
long a = base.convert(this.getTime(), this.getUnit());
long b = base.convert(that.getTime(), that.getUnit());
return new Duration(a + b, base);
}
public Duration subtract(Duration that) {
Unit base = Unit.values()[Math.min(this.getUnit().ordinal(), that.getUnit().ordinal())];
long a = base.convert(this.getTime(), this.getUnit());
long b = base.convert(that.getTime(), that.getUnit());
return new Duration(a - b, base);
}
private static void invalidFormat(String text) {
throw new IllegalArgumentException("Illegal duration format: '" + text + "'. Valid examples are '10s' or '10 seconds'.");
}
private static Unit parseUnit(String u) {
if (u.length() == 0) return Unit.MILLISECONDS;
if (u.equalsIgnoreCase("NANOSECONDS")) return Unit.NANOSECONDS;
if (u.equalsIgnoreCase("NANOSECOND")) return Unit.NANOSECONDS;
if (u.equalsIgnoreCase("NANOS")) return Unit.NANOSECONDS;
if (u.equalsIgnoreCase("NANO")) return Unit.NANOSECONDS;
if (u.equalsIgnoreCase("NS")) return Unit.NANOSECONDS;
if (u.equalsIgnoreCase("MICROSECONDS")) return Unit.MICROSECONDS;
if (u.equalsIgnoreCase("MICROSECOND")) return Unit.MICROSECONDS;
if (u.equalsIgnoreCase("MICROS")) return Unit.MICROSECONDS;
if (u.equalsIgnoreCase("MICRO")) return Unit.MICROSECONDS;
if (u.equalsIgnoreCase("MILLISECONDS")) return Unit.MILLISECONDS;
if (u.equalsIgnoreCase("MILLISECOND")) return Unit.MILLISECONDS;
if (u.equalsIgnoreCase("MILLIS")) return Unit.MILLISECONDS;
if (u.equalsIgnoreCase("MILLI")) return Unit.MILLISECONDS;
if (u.equalsIgnoreCase("MS")) return Unit.MILLISECONDS;
if (u.equalsIgnoreCase("SECONDS")) return Unit.SECONDS;
if (u.equalsIgnoreCase("SECOND")) return Unit.SECONDS;
if (u.equalsIgnoreCase("SEC")) return Unit.SECONDS;
if (u.equalsIgnoreCase("S")) return Unit.SECONDS;
if (u.equalsIgnoreCase("MINUTES")) return Unit.MINUTES;
if (u.equalsIgnoreCase("MINUTE")) return Unit.MINUTES;
if (u.equalsIgnoreCase("MIN")) return Unit.MINUTES;
if (u.equalsIgnoreCase("M")) return Unit.MINUTES;
if (u.equalsIgnoreCase("HOURS")) return Unit.HOURS;
if (u.equalsIgnoreCase("HOUR")) return Unit.HOURS;
if (u.equalsIgnoreCase("HRS")) return Unit.HOURS;
if (u.equalsIgnoreCase("HR")) return Unit.HOURS;
if (u.equalsIgnoreCase("H")) return Unit.HOURS;
if (u.equalsIgnoreCase("DAYS")) return Unit.DAYS;
if (u.equalsIgnoreCase("DAY")) return Unit.DAYS;
if (u.equalsIgnoreCase("D")) return Unit.DAYS;
if (u.equalsIgnoreCase("WEEKS")) return Unit.WEEKS;
if (u.equalsIgnoreCase("WEEK")) return Unit.WEEKS;
if (u.equalsIgnoreCase("W")) return Unit.WEEKS;
throw new IllegalArgumentException("Unknown time unit '" + u + "'. Supported units " + Join.join(", ", lowercase(Unit.values())));
}
private static String[] lowercase(Unit[] units) {
String[] values = new String[units.length];
for (int i = 0; i < units.length; i++) {
values[i] = units[i].name().toLowerCase();
}
return values;
}
static {
PropertyEditorManager.registerEditor(Duration.class, DurationEditor.class);
}
public static class DurationEditor extends java.beans.PropertyEditorSupport {
public void setAsText(String text) {
Duration d = Duration.parse(text);
setValue(d);
}
}
}
/**
* 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.
*/
import junit.framework.TestCase;
import static Duration.Unit.DAYS;
import static Duration.Unit.HOURS;
import static Duration.Unit.MICROSECONDS;
import static Duration.Unit.MILLISECONDS;
import static Duration.Unit.MINUTES;
import static Duration.Unit.NANOSECONDS;
import static Duration.Unit.SECONDS;
import static Duration.Unit.WEEKS;
public class DurationTest extends TestCase {
public void testConstruction() throws Exception {
// assertEquals(new Duration(1000, MILLISECONDS), new Duration("1000ms"));
// assertEquals(new Duration(1000, MILLISECONDS), new Duration("1000 ms"));
// assertEquals(new Duration(1000, MILLISECONDS), new Duration("1000 ms"));
//
// assertEquals(new Duration(60, SECONDS), new Duration("1m"));
// assertEquals(new Duration(3600, SECONDS), new Duration("1h"));
// assertEquals(new Duration(86400, SECONDS), new Duration("1d"));
//
// assertEquals(new Duration(1000, MICROSECONDS), new Duration("1000 microseconds"));
// assertEquals(new Duration(1000, NANOSECONDS), new Duration("1000 nanoseconds"));
//
assertEquals(new Duration(1, MILLISECONDS), new Duration("1"));
assertEquals(new Duration(234, MILLISECONDS), new Duration("234"));
assertEquals(new Duration(123, MILLISECONDS), new Duration("123"));
assertEquals(new Duration(-1, MILLISECONDS), new Duration("-1"));
}
public void testAddition() throws Exception {
Duration a = new Duration(100, MILLISECONDS);
Duration b = new Duration(200, MILLISECONDS);
assertEquals(new Duration(300, MILLISECONDS), a.add(b));
Duration c = new Duration(2, SECONDS);
assertEquals(new Duration(2300, MILLISECONDS), a.add(b).add(c));
}
public void testMultiple() throws Exception {
assertEquals(new Duration(2300, MILLISECONDS), Duration.parseMultitple("2 seconds and 300 milliseconds"));
assertEquals(new Duration(2300, MILLISECONDS), Duration.parseMultitple("2 seconds, 300 milliseconds"));
assertEquals(new Duration(2300, MILLISECONDS), Duration.parseMultitple("2 seconds,300 milliseconds"));
assertEquals(new Duration(125, SECONDS), Duration.parseMultitple("2 minutes and 5 seconds"));
}
public void testUnitConversion() throws Exception {
assertEquals(2, WEEKS.convert(2, WEEKS));
assertEquals(2 * 7, DAYS.convert(2, WEEKS));
assertEquals(2 * 7 * 24, HOURS.convert(2, WEEKS));
assertEquals(2 * 7 * 24 * 60, MINUTES.convert(2, WEEKS));
assertEquals(2 * 7 * 24 * 60 * 60, SECONDS.convert(2, WEEKS));
assertEquals(2 * 7 * 24 * 60 * 60 * 1000, MILLISECONDS.convert(2, WEEKS));
assertEquals(2 * 1000, MILLISECONDS.convert(2, SECONDS));
assertEquals(2 * 1000 * 1000, MICROSECONDS.convert(2, SECONDS));
assertEquals(2 * 1000 * 1000 * 1000, NANOSECONDS.convert(2, SECONDS));
assertEquals(2, SECONDS.convert(2 * 1000 * 1000 * 1000, NANOSECONDS));
assertEquals(2, SECONDS.convert(2 * 1000 * 1000, MICROSECONDS));
assertEquals(2, SECONDS.convert(2 * 1000, MILLISECONDS));
assertEquals(2, WEEKS.convert(2 * 7 * 24 * 60 * 60 * 1000, MILLISECONDS));
assertEquals(2, WEEKS.convert(2 * 7 * 24 * 60 * 60, SECONDS));
assertEquals(2, WEEKS.convert(2 * 7 * 24 * 60, MINUTES));
assertEquals(2, WEEKS.convert(2 * 7 * 24, HOURS));
assertEquals(2, WEEKS.convert(2 * 7, DAYS));
// The verbose way of doing the above
assertEquals(2, new Duration(2, WEEKS).convert(WEEKS).getTime());
assertEquals(2 * 7, new Duration(2, WEEKS).convert(DAYS).getTime());
assertEquals(2 * 7 * 24, new Duration(2, WEEKS).convert(HOURS).getTime());
assertEquals(2 * 7 * 24 * 60, new Duration(2, WEEKS).convert(MINUTES).getTime());
assertEquals(2 * 7 * 24 * 60 * 60, new Duration(2, WEEKS).convert(SECONDS).getTime());
assertEquals(2 * 7 * 24 * 60 * 60 * 1000, new Duration(2, WEEKS).convert(MILLISECONDS).getTime());
assertEquals(2 * 1000, new Duration(2, SECONDS).convert(MILLISECONDS).getTime());
assertEquals(2 * 1000 * 1000, new Duration(2, SECONDS).convert(MICROSECONDS).getTime());
assertEquals(2 * 1000 * 1000 * 1000, new Duration(2, SECONDS).convert(NANOSECONDS).getTime());
assertEquals(2, new Duration(2 * 1000 * 1000 * 1000, NANOSECONDS).convert(SECONDS).getTime());
assertEquals(2, new Duration(2 * 1000 * 1000, MICROSECONDS).convert(SECONDS).getTime());
assertEquals(2, new Duration(2 * 1000, MILLISECONDS).convert(SECONDS).getTime());
assertEquals(2, new Duration(2 * 7 * 24 * 60 * 60 * 1000, MILLISECONDS).convert(WEEKS).getTime());
assertEquals(2, new Duration(2 * 7 * 24 * 60 * 60, SECONDS).convert(WEEKS).getTime());
assertEquals(2, new Duration(2 * 7 * 24 * 60, MINUTES).convert(WEEKS).getTime());
assertEquals(2, new Duration(2 * 7 * 24, HOURS).convert(WEEKS).getTime());
assertEquals(2, new Duration(2 * 7, DAYS).convert(WEEKS).getTime());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment