805 lines
18 KiB
Java
805 lines
18 KiB
Java
package eu.dnetlib.miscutils.datetime;
|
|
|
|
/*
|
|
* HumanTime.java
|
|
*
|
|
* Created on 06.10.2008
|
|
*
|
|
* Copyright (c) 2008 Johann Burkard (<mailto:jb@eaio.com>) <http://eaio.com>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
import java.io.Externalizable;
|
|
import java.io.IOException;
|
|
import java.io.ObjectInput;
|
|
import java.io.ObjectOutput;
|
|
import java.util.Iterator;
|
|
|
|
/**
|
|
* HumanTime parses and formats time deltas for easier reading by humans. It can format time information without losing
|
|
* information but its main purpose is to generate more easily understood approximations. <h3>Using HumanTime</h3>
|
|
* <p>
|
|
* Use HumanTime by creating an instance that contains the time delta ({@link HumanTime#HumanTime(long)}), create an
|
|
* empty instance through ({@link HumanTime#HumanTime()}) and set the delta using the {@link #y()}, {@link #d()},
|
|
* {@link #h()}, {@link #s()} and {@link #ms()} methods or parse a {@link CharSequence} representation (
|
|
* {@link #eval(CharSequence)}). Parsing ignores whitespace and is case insensitive.
|
|
* </p>
|
|
* <h3>HumanTime format</h3>
|
|
* <p>
|
|
* HumanTime will format time deltas in years ("y"), days ("d"), hours ("h"), minutes ("m"), seconds ("s") and
|
|
* milliseconds ("ms"), separated by a blank character. For approximate representations, the time delta will be round up
|
|
* or down if necessary.
|
|
* </p>
|
|
* <h3>HumanTime examples</h3>
|
|
* <ul>
|
|
* <li>HumanTime.eval("1 d 1d 2m 3m").getExactly() = "2 d 5 m"</li>
|
|
* <li>HumanTime.eval("2m8d2h4m").getExactly() = "8 d 2 h 6 m"</li>
|
|
* <li>HumanTime.approximately("2 d 8 h 20 m 50 s") = "2 d 8 h"</li>
|
|
* <li>HumanTime.approximately("55m") = "1 h"</li>
|
|
* </ul>
|
|
* <h3>Implementation details</h3>
|
|
* <ul>
|
|
* <li>The time delta can only be increased.</li>
|
|
* <li>Instances of this class are thread safe.</li>
|
|
* <li>Getters using the Java Beans naming conventions are provided for use in environments like JSP or with expression
|
|
* languages like OGNL. See {@link #getApproximately()} and {@link #getExactly()}.</li>
|
|
* <li>To keep things simple, a year consists of 365 days.</li>
|
|
* </ul>
|
|
*
|
|
* @author <a href="mailto:jb@eaio.com">Johann Burkard</a>
|
|
* @version $Id: HumanTime.java 323 2008-10-08 19:06:22Z Johann $
|
|
* @see #eval(CharSequence)
|
|
* @see #approximately(CharSequence)
|
|
* @see <a href="http://johannburkard.de/blog/programming/java/date-formatting-parsing-humans-humantime.html">Date
|
|
* Formatting and Parsing for Humans in Java with HumanTime</a>
|
|
*/
|
|
public class HumanTime implements Externalizable, Comparable<HumanTime>, Cloneable {
|
|
|
|
/**
|
|
* The serial version UID.
|
|
*/
|
|
private static final long serialVersionUID = 5179328390732826722L;
|
|
|
|
/**
|
|
* One second.
|
|
*/
|
|
private static final long SECOND = 1000;
|
|
|
|
/**
|
|
* One minute.
|
|
*/
|
|
private static final long MINUTE = SECOND * 60;
|
|
|
|
/**
|
|
* One hour.
|
|
*/
|
|
private static final long HOUR = MINUTE * 60;
|
|
|
|
/**
|
|
* One day.
|
|
*/
|
|
private static final long DAY = HOUR * 24;
|
|
|
|
/**
|
|
* One year.
|
|
*/
|
|
private static final long YEAR = DAY * 365;
|
|
|
|
/**
|
|
* Percentage of what is round up or down.
|
|
*/
|
|
private static final int CEILING_PERCENTAGE = 15;
|
|
|
|
/**
|
|
* Parsing state.
|
|
*/
|
|
static enum State {
|
|
|
|
NUMBER, IGNORED, UNIT
|
|
|
|
}
|
|
|
|
static State getState(char c) {
|
|
State out;
|
|
switch (c) {
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
out = State.NUMBER;
|
|
break;
|
|
case 's':
|
|
case 'm':
|
|
case 'h':
|
|
case 'd':
|
|
case 'y':
|
|
case 'S':
|
|
case 'M':
|
|
case 'H':
|
|
case 'D':
|
|
case 'Y':
|
|
out = State.UNIT;
|
|
break;
|
|
default:
|
|
out = State.IGNORED;
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Parses a {@link CharSequence} argument and returns a {@link HumanTime} instance.
|
|
*
|
|
* @param s
|
|
* the char sequence, may not be <code>null</code>
|
|
* @return an instance, never <code>null</code>
|
|
*/
|
|
public static HumanTime eval(final CharSequence s) {
|
|
HumanTime out = new HumanTime(0L);
|
|
|
|
int num = 0;
|
|
|
|
int start = 0;
|
|
int end = 0;
|
|
|
|
State oldState = State.IGNORED;
|
|
|
|
for (char c : new Iterable<Character>() {
|
|
|
|
/**
|
|
* @see java.lang.Iterable#iterator()
|
|
*/
|
|
@Override
|
|
public Iterator<Character> iterator() {
|
|
return new Iterator<Character>() {
|
|
|
|
private int p = 0;
|
|
|
|
/**
|
|
* @see java.util.Iterator#hasNext()
|
|
*/
|
|
@Override
|
|
public boolean hasNext() {
|
|
return p < s.length();
|
|
}
|
|
|
|
/**
|
|
* @see java.util.Iterator#next()
|
|
*/
|
|
@Override
|
|
public Character next() {
|
|
return s.charAt(p++);
|
|
}
|
|
|
|
/**
|
|
* @see java.util.Iterator#remove()
|
|
*/
|
|
@Override
|
|
public void remove() {
|
|
throw new UnsupportedOperationException();
|
|
}
|
|
|
|
};
|
|
}
|
|
|
|
}) {
|
|
State newState = getState(c);
|
|
if (oldState != newState) {
|
|
if (oldState == State.NUMBER && (newState == State.IGNORED || newState == State.UNIT)) {
|
|
num = Integer.parseInt(s.subSequence(start, end).toString());
|
|
} else if (oldState == State.UNIT && (newState == State.IGNORED || newState == State.NUMBER)) {
|
|
out.nTimes(s.subSequence(start, end).toString(), num);
|
|
num = 0;
|
|
}
|
|
start = end;
|
|
}
|
|
++end;
|
|
oldState = newState;
|
|
}
|
|
if (oldState == State.UNIT) {
|
|
out.nTimes(s.subSequence(start, end).toString(), num);
|
|
}
|
|
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* Parses and formats the given char sequence, preserving all data.
|
|
* <p>
|
|
* Equivalent to <code>eval(in).getExactly()</code>
|
|
*
|
|
* @param in
|
|
* the char sequence, may not be <code>null</code>
|
|
* @return a formatted String, never <code>null</code>
|
|
*/
|
|
public static String exactly(CharSequence in) {
|
|
return eval(in).getExactly();
|
|
}
|
|
|
|
/**
|
|
* Formats the given time delta, preserving all data.
|
|
* <p>
|
|
* Equivalent to <code>new HumanTime(in).getExactly()</code>
|
|
*
|
|
* @param l
|
|
* the time delta
|
|
* @return a formatted String, never <code>null</code>
|
|
*/
|
|
public static String exactly(long l) {
|
|
return new HumanTime(l).getExactly();
|
|
}
|
|
|
|
/**
|
|
* Parses and formats the given char sequence, potentially removing some data to make the output easier to
|
|
* understand.
|
|
* <p>
|
|
* Equivalent to <code>eval(in).getApproximately()</code>
|
|
*
|
|
* @param in
|
|
* the char sequence, may not be <code>null</code>
|
|
* @return a formatted String, never <code>null</code>
|
|
*/
|
|
public static String approximately(CharSequence in) {
|
|
return eval(in).getApproximately();
|
|
}
|
|
|
|
/**
|
|
* Formats the given time delta, preserving all data.
|
|
* <p>
|
|
* Equivalent to <code>new HumanTime(l).getApproximately()</code>
|
|
*
|
|
* @param l
|
|
* the time delta
|
|
* @return a formatted String, never <code>null</code>
|
|
*/
|
|
public static String approximately(long l) {
|
|
return new HumanTime(l).getApproximately();
|
|
}
|
|
|
|
/**
|
|
* The time delta.
|
|
*/
|
|
private long delta;
|
|
|
|
/**
|
|
* No-argument Constructor for HumanTime.
|
|
* <p>
|
|
* Equivalent to calling <code>new HumanTime(0L)</code>.
|
|
*/
|
|
public HumanTime() {
|
|
this(0L);
|
|
}
|
|
|
|
/**
|
|
* Constructor for HumanTime.
|
|
*
|
|
* @param delta
|
|
* the initial time delta, interpreted as a positive number
|
|
*/
|
|
public HumanTime(long delta) {
|
|
super();
|
|
this.delta = Math.abs(delta);
|
|
}
|
|
|
|
private void nTimes(String unit, int n) {
|
|
if ("ms".equalsIgnoreCase(unit)) {
|
|
ms(n);
|
|
} else if ("s".equalsIgnoreCase(unit)) {
|
|
s(n);
|
|
} else if ("m".equalsIgnoreCase(unit)) {
|
|
m(n);
|
|
} else if ("h".equalsIgnoreCase(unit)) {
|
|
h(n);
|
|
} else if ("d".equalsIgnoreCase(unit)) {
|
|
d(n);
|
|
} else if ("y".equalsIgnoreCase(unit)) {
|
|
y(n);
|
|
}
|
|
}
|
|
|
|
private long upperCeiling(long x) {
|
|
return (x / 100) * (100 - CEILING_PERCENTAGE);
|
|
}
|
|
|
|
private long lowerCeiling(long x) {
|
|
return (x / 100) * CEILING_PERCENTAGE;
|
|
}
|
|
|
|
private String ceil(long d, long n) {
|
|
return Integer.toString((int) Math.ceil((double) d / n));
|
|
}
|
|
|
|
private String floor(long d, long n) {
|
|
return Integer.toString((int) Math.floor((double) d / n));
|
|
}
|
|
|
|
/**
|
|
* Adds one year to the time delta.
|
|
*
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime y() {
|
|
return y(1);
|
|
}
|
|
|
|
/**
|
|
* Adds n years to the time delta.
|
|
*
|
|
* @param n
|
|
* n
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime y(int n) {
|
|
delta += YEAR * Math.abs(n);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds one day to the time delta.
|
|
*
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime d() {
|
|
return d(1);
|
|
}
|
|
|
|
/**
|
|
* Adds n days to the time delta.
|
|
*
|
|
* @param n
|
|
* n
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime d(int n) {
|
|
delta += DAY * Math.abs(n);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds one hour to the time delta.
|
|
*
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime h() {
|
|
return h(1);
|
|
}
|
|
|
|
/**
|
|
* Adds n hours to the time delta.
|
|
*
|
|
* @param n
|
|
* n
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime h(int n) {
|
|
delta += HOUR * Math.abs(n);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds one month to the time delta.
|
|
*
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime m() {
|
|
return m(1);
|
|
}
|
|
|
|
/**
|
|
* Adds n months to the time delta.
|
|
*
|
|
* @param n
|
|
* n
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime m(int n) {
|
|
delta += MINUTE * Math.abs(n);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds one second to the time delta.
|
|
*
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime s() {
|
|
return s(1);
|
|
}
|
|
|
|
/**
|
|
* Adds n seconds to the time delta.
|
|
*
|
|
* @param n
|
|
* seconds
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime s(int n) {
|
|
delta += SECOND * Math.abs(n);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Adds one millisecond to the time delta.
|
|
*
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime ms() {
|
|
return ms(1);
|
|
}
|
|
|
|
/**
|
|
* Adds n milliseconds to the time delta.
|
|
*
|
|
* @param n
|
|
* n
|
|
* @return this HumanTime object
|
|
*/
|
|
public HumanTime ms(int n) {
|
|
delta += Math.abs(n);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Returns a human-formatted representation of the time delta.
|
|
*
|
|
* @return a formatted representation of the time delta, never <code>null</code>
|
|
*/
|
|
public String getExactly() {
|
|
return getExactly(new StringBuilder()).toString();
|
|
}
|
|
|
|
/**
|
|
* Appends a human-formatted representation of the time delta to the given {@link Appendable} object.
|
|
*
|
|
* @param <T>
|
|
* the return type
|
|
* @param a
|
|
* the Appendable object, may not be <code>null</code>
|
|
* @return the given Appendable object, never <code>null</code>
|
|
*/
|
|
public <T extends Appendable> T getExactly(T a) {
|
|
try {
|
|
boolean prependBlank = false;
|
|
long d = delta;
|
|
if (d >= YEAR) {
|
|
a.append(floor(d, YEAR));
|
|
a.append(' ');
|
|
a.append('y');
|
|
prependBlank = true;
|
|
}
|
|
d %= YEAR;
|
|
if (d >= DAY) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(floor(d, DAY));
|
|
a.append(' ');
|
|
a.append('d');
|
|
prependBlank = true;
|
|
}
|
|
d %= DAY;
|
|
if (d >= HOUR) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(floor(d, HOUR));
|
|
a.append(' ');
|
|
a.append('h');
|
|
prependBlank = true;
|
|
}
|
|
d %= HOUR;
|
|
if (d >= MINUTE) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(floor(d, MINUTE));
|
|
a.append(' ');
|
|
a.append('m');
|
|
prependBlank = true;
|
|
}
|
|
d %= MINUTE;
|
|
if (d >= SECOND) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(floor(d, SECOND));
|
|
a.append(' ');
|
|
a.append('s');
|
|
prependBlank = true;
|
|
}
|
|
d %= SECOND;
|
|
if (d > 0) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(Integer.toString((int) d));
|
|
a.append(' ');
|
|
a.append('m');
|
|
a.append('s');
|
|
}
|
|
} catch (IOException ex) {
|
|
// What were they thinking...
|
|
}
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* Returns an approximate, human-formatted representation of the time delta.
|
|
*
|
|
* @return a formatted representation of the time delta, never <code>null</code>
|
|
*/
|
|
public String getApproximately() {
|
|
return getApproximately(new StringBuilder()).toString();
|
|
}
|
|
|
|
/**
|
|
* Appends an approximate, human-formatted representation of the time delta to the given {@link Appendable} object.
|
|
*
|
|
* @param <T>
|
|
* the return type
|
|
* @param a
|
|
* the Appendable object, may not be <code>null</code>
|
|
* @return the given Appendable object, never <code>null</code>
|
|
*/
|
|
public <T extends Appendable> T getApproximately(T a) {
|
|
|
|
try {
|
|
int parts = 0;
|
|
boolean rounded = false;
|
|
boolean prependBlank = false;
|
|
long d = delta;
|
|
long mod = d % YEAR;
|
|
|
|
if (mod >= upperCeiling(YEAR)) {
|
|
a.append(ceil(d, YEAR));
|
|
a.append(' ');
|
|
a.append('y');
|
|
++parts;
|
|
rounded = true;
|
|
prependBlank = true;
|
|
} else if (d >= YEAR) {
|
|
a.append(floor(d, YEAR));
|
|
a.append(' ');
|
|
a.append('y');
|
|
++parts;
|
|
rounded = mod <= lowerCeiling(YEAR);
|
|
prependBlank = true;
|
|
}
|
|
|
|
if (!rounded) {
|
|
d %= YEAR;
|
|
mod = d % DAY;
|
|
|
|
if (mod >= upperCeiling(DAY)) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(ceil(d, DAY));
|
|
a.append(' ');
|
|
a.append('d');
|
|
++parts;
|
|
rounded = true;
|
|
prependBlank = true;
|
|
} else if (d >= DAY) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(floor(d, DAY));
|
|
a.append(' ');
|
|
a.append('d');
|
|
++parts;
|
|
rounded = mod <= lowerCeiling(DAY);
|
|
prependBlank = true;
|
|
}
|
|
|
|
if (parts < 2) {
|
|
d %= DAY;
|
|
mod = d % HOUR;
|
|
|
|
if (mod >= upperCeiling(HOUR)) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(ceil(d, HOUR));
|
|
a.append(' ');
|
|
a.append('h');
|
|
++parts;
|
|
rounded = true;
|
|
prependBlank = true;
|
|
} else if (d >= HOUR && !rounded) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(floor(d, HOUR));
|
|
a.append(' ');
|
|
a.append('h');
|
|
++parts;
|
|
rounded = mod <= lowerCeiling(HOUR);
|
|
prependBlank = true;
|
|
}
|
|
|
|
if (parts < 2) {
|
|
d %= HOUR;
|
|
mod = d % MINUTE;
|
|
|
|
if (mod >= upperCeiling(MINUTE)) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(ceil(d, MINUTE));
|
|
a.append(' ');
|
|
a.append('m');
|
|
++parts;
|
|
rounded = true;
|
|
prependBlank = true;
|
|
} else if (d >= MINUTE && !rounded) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(floor(d, MINUTE));
|
|
a.append(' ');
|
|
a.append('m');
|
|
++parts;
|
|
rounded = mod <= lowerCeiling(MINUTE);
|
|
prependBlank = true;
|
|
}
|
|
|
|
if (parts < 2) {
|
|
d %= MINUTE;
|
|
mod = d % SECOND;
|
|
|
|
if (mod >= upperCeiling(SECOND)) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(ceil(d, SECOND));
|
|
a.append(' ');
|
|
a.append('s');
|
|
++parts;
|
|
rounded = true;
|
|
prependBlank = true;
|
|
} else if (d >= SECOND && !rounded) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(floor(d, SECOND));
|
|
a.append(' ');
|
|
a.append('s');
|
|
++parts;
|
|
rounded = mod <= lowerCeiling(SECOND);
|
|
prependBlank = true;
|
|
}
|
|
|
|
if (parts < 2) {
|
|
d %= SECOND;
|
|
|
|
if (d > 0 && !rounded) {
|
|
if (prependBlank) {
|
|
a.append(' ');
|
|
}
|
|
a.append(Integer.toString((int) d));
|
|
a.append(' ');
|
|
a.append('m');
|
|
a.append('s');
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
} catch (IOException ex) {
|
|
// What were they thinking...
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* Returns the time delta.
|
|
*
|
|
* @return the time delta
|
|
*/
|
|
public long getDelta() {
|
|
return delta;
|
|
}
|
|
|
|
/**
|
|
* @see java.lang.Object#equals(java.lang.Object)
|
|
*/
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (this == obj) {
|
|
return true;
|
|
}
|
|
if (!(obj instanceof HumanTime)) {
|
|
return false;
|
|
}
|
|
return delta == ((HumanTime) obj).delta;
|
|
}
|
|
|
|
/**
|
|
* Returns a 32-bit representation of the time delta.
|
|
*
|
|
* @see java.lang.Object#hashCode()
|
|
*/
|
|
@Override
|
|
public int hashCode() {
|
|
return (int) (delta ^ (delta >> 32));
|
|
}
|
|
|
|
/**
|
|
* Returns a String representation of this.
|
|
* <p>
|
|
* The output is identical to {@link #getExactly()}.
|
|
*
|
|
* @see java.lang.Object#toString()
|
|
* @see #getExactly()
|
|
* @return a String, never <code>null</code>
|
|
*/
|
|
@Override
|
|
public String toString() {
|
|
return getExactly();
|
|
}
|
|
|
|
/**
|
|
* Compares this HumanTime to another HumanTime.
|
|
*
|
|
* @param t
|
|
* the other instance, may not be <code>null</code>
|
|
* @return which one is greater
|
|
*/
|
|
@Override
|
|
public int compareTo(HumanTime t) {
|
|
return delta == t.delta ? 0 : (delta < t.delta ? -1 : 1);
|
|
}
|
|
|
|
/**
|
|
* Deep-clones this object.
|
|
*
|
|
* @see java.lang.Object#clone()
|
|
* @throws CloneNotSupportedException
|
|
*/
|
|
@Override
|
|
public Object clone() throws CloneNotSupportedException {
|
|
return super.clone();
|
|
}
|
|
|
|
/**
|
|
* @see java.io.Externalizable#readExternal(java.io.ObjectInput)
|
|
*/
|
|
@Override
|
|
public void readExternal(ObjectInput in) throws IOException {
|
|
delta = in.readLong();
|
|
}
|
|
|
|
/**
|
|
* @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
|
|
*/
|
|
@Override
|
|
public void writeExternal(ObjectOutput out) throws IOException {
|
|
out.writeLong(delta);
|
|
}
|
|
|
|
}
|