/*
* Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package ucar.nc2.units;
import ucar.unidata.util.Format;
import ucar.units.ConversionException;
import java.util.StringTokenizer;
import java.util.Date;
import java.util.Calendar;
/**
* Handles Units that are time durations, eg in seconds, hours, days, years.
* It keeps track of the original unit name, rather than converting to canonical "seconds".
* The unit name never changes, but the value may.
* <p>
* This is a wrapper around ucar.units.
* The underlying ucar.units.Unit always has a value of "1.0", ie is a base unit.
*
* @author John Caron
*/
public class TimeUnit extends SimpleUnit {
private double value;
private double factor = 1.0;
private String unitString;
//private Unit uu;
/**
* Constructor from a String.
* @param text [value] <time unit> eg "hours" or "13 hours". Time unit is from udunits.
* @throws Exception is bad format
*/
public TimeUnit(String text) throws Exception {
super();
if (text == null) {
this.value = 1.0;
this.unitString = "secs";
this.uu = SimpleUnit.makeUnit( unitString); // always a base unit
return;
}
StringTokenizer stoker = new StringTokenizer(text);
int ntoke = stoker.countTokens();
if (ntoke == 1) {
this.value = 1.0;
this.unitString = stoker.nextToken();
} else if (ntoke == 2){
this.value = Double.parseDouble(stoker.nextToken());
this.unitString = stoker.nextToken();
} else
throw new IllegalArgumentException("Not TimeUnit = "+text);
uu = SimpleUnit.makeUnit( unitString); // always a base unit
factor = uu.convertTo( 1.0, SimpleUnit.secsUnit);
}
/**
* Constructor from a value and a unit name.
* @param value amount of the unit.
* @param unitString Time unit string from udunits.
* @throws Exception if parse fails
*/
public TimeUnit(double value, String unitString) throws Exception {
this.value = value;
this.unitString = unitString;
uu = SimpleUnit.makeUnit( unitString);
factor = uu.convertTo( 1.0, SimpleUnit.secsUnit);
}
/**
* Copy Constructor.
* @param src copy from here
*/
public TimeUnit( TimeUnit src) {
this.value = src.getValue();
this.unitString = src.getUnitString();
uu = src.uu;
factor = src.getFactor();
}
/** Get the value. */
@Override
public double getValue() { return value; }
/** Get the factor that converts this unit to seconds.
* getValueInSeconds = factor * value
* @return factor that converts this unit to seconds.
*/
public double getFactor() { return factor; }
/** Set the value in the original units.
* @param value set value, must be in units of this
*/
public void setValue( double value) {
this.value = value;
}
/** Get the "base" unit String, eg "secs" or "days" */
@Override
public String getUnitString() { return unitString; }
/** String representation. */
@Override
public String toString() {
return Format.d(value, 5) + " "+unitString;
}
/** Get the time duration in seconds.
* @return get current value in units of seconds
*/
public double getValueInSeconds() {
return factor * value;
}
/** Get the time duration in seconds of the specified value.
* @param value convert this value, must be in units of this
* @return get the value in units of seconds
*/
public double getValueInSeconds(double value) {
return factor * value;
}
/**
* Set the value, using the given number of seconds.
* @param secs : number of seconds; convert this to the units of this TimeUnit.
*/
public void setValueInSeconds( double secs) {
value = secs/factor;
}
// override
/** Convert given value of this unit to the new unit.
* <em>NOTE: the current value of this unit ignored, the given value is used instead.
* This is different than ucar.units or SimpleUnit.</em>
* @param value in the units of this "base unit"
* @param outputUnit convert to this base type, must be convertible to units of "seconds"
* @return new value in the units of the "outputUnit
* @throws ConversionException
*/
public double convertTo(double value, TimeUnit outputUnit) throws ConversionException {
return uu.convertTo( value, outputUnit.uu);
}
/**
* Add the time amount to the given Date, return a new Date.
* @param d add to this Date
* @return Date with getValueInSeconds() added to it.
*/
public Date add( Date d) {
Calendar cal = Calendar.getInstance();
cal.setTime( d);
cal.add( Calendar.SECOND, (int) getValueInSeconds());
return cal.getTime();
}
/** TimeUnits with same value and unitString are equal */
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TimeUnit)) return false;
return o.hashCode() == this.hashCode();
}
/** Override hashcode to be consistent with equals. */
@Override
public int hashCode() {
if (hashCode == 0) {
int result = 17;
result = 37*result + unitString.hashCode();
result = 37*result + (int) (1000.0 * value);
hashCode = result;
}
return hashCode;
}
private int hashCode = 0;
}