/*
* Copyright (c) 2006 Stiftung Deutsches Elektronen-Synchroton,
* Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
*
* THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS.
* WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. 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. SHOULD THE SOFTWARE PROVE DEFECTIVE
* IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR
* CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
* NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
* DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
* OR MODIFICATIONS.
* THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION,
* USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS
* PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY
* AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM
*/
package org.csstudio.data.values.internal;
import java.util.Calendar;
import org.csstudio.data.values.ITimestamp;
/** Implementation of the {@link ITimestamp} interface.
* @author Sven Wende
* @author Kay Kasemir
*/
public final class Timestamp implements ITimestamp
{
private static final long serialVersionUID = 1L;
/** Milliseconds per second. */
public static final long millis_per_sec = 1000L;
/** Nanoseconds per millisecond. */
public static final long nanos_per_milli = 1000000L;
/** Nanoseconds per second. */
public static final long nanos_per_sec = 1000000000L;
/** Seconds since epoch. */
private final long seconds;
/** Nanoseconds within the seconds.
* <p>
* Normalized, i.e. within 0..nanos_per_milli. */
private final long nanoseconds;
/** Constructor with seconds and nanoseconds since epoch.
* @param seconds Seconds since epoch
* @param nanoseconds Nanoseconds within seconds
*/
public Timestamp(long seconds, long nanoseconds)
{
if (nanoseconds < 0 || nanoseconds >= nanos_per_sec)
{
long fullsecs = nanoseconds / nanos_per_sec;
seconds += fullsecs;
nanoseconds -= fullsecs * nanos_per_sec;
}
this.seconds = seconds;
this.nanoseconds = nanoseconds;
}
/** Constructor with fractional seconds since epoch.
* @param seconds Seconds since epoch
*/
public Timestamp(final double seconds)
{
this.seconds = (long) seconds;
this.nanoseconds = (long) ((seconds - this.seconds) * 1e9);
}
/** {@inheritDoc} */
@Override
public long seconds()
{
return seconds;
}
/** {@inheritDoc} */
@Override
public long nanoseconds()
{
return nanoseconds;
}
/** {@inheritDoc} */
@Override
public boolean isValid()
{
return seconds > 0 || nanoseconds > 0;
}
/** {@inheritDoc} */
@Override
public double toDouble()
{
return seconds + nanoseconds() / 1e9;
}
/** {@inheritDoc} */
@Override
public Calendar toCalendar()
{
final Calendar result = Calendar.getInstance();
result.setTimeInMillis(seconds * millis_per_sec
+ nanoseconds / nanos_per_milli);
return result;
}
/** {@inheritDoc} */
@Override
public java.sql.Timestamp toSQLTimestamp()
{
// Only millisecond resolution
java.sql.Timestamp stamp = new java.sql.Timestamp(seconds * 1000 +
nanoseconds / 1000000);
// Set nanoseconds (again), but this call uses the full
// nanosecond resolution
stamp.setNanos((int) nanoseconds);
return stamp;
}
/** {@inheritDoc} */
@Override
@SuppressWarnings("nls")
public String format(final Format format)
{
final Calendar cal = toCalendar();
// Formatting the time as a string is expensive.
// JProfiler comparison of this String.format() code with
// with custom StringBuilder.append(...) code seemed to save
// very little CPU time, but String.format() is a lot easier to read.
switch (format)
{
case Date:
return String.format("%04d/%02d/%02d",
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH)+1,
cal.get(Calendar.DAY_OF_MONTH));
case DateTime:
return String.format("%04d/%02d/%02d %02d:%02d",
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH)+1,
cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE));
case DateTimeSeconds:
return String.format("%04d/%02d/%02d %02d:%02d:%02d",
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH)+1,
cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
cal.get(Calendar.SECOND));
default:
// case Full:
return String.format("%04d/%02d/%02d %02d:%02d:%02d.%09d",
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH)+1,
cal.get(Calendar.DAY_OF_MONTH),
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
cal.get(Calendar.SECOND),
nanoseconds);
}
}
/** @return The formatted time with full detail. */
@Override
public String toString()
{
return format(Format.Full);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isGreaterThan(final ITimestamp other)
{
if (seconds > other.seconds())
{
return true;
}
if (seconds < other.seconds())
{
return false;
}
// Seconds tie, let nanoseconds decide.
return nanoseconds > other.nanoseconds();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isGreaterOrEqual(final ITimestamp other)
{
if (seconds > other.seconds())
{
return true;
}
if (seconds < other.seconds())
{
return false;
}
// Seconds tie, let nanoseconds decide.
return nanoseconds >= other.nanoseconds();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isLessThan(final ITimestamp other)
{
return !isGreaterOrEqual(other);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isLessOrEqual(final ITimestamp other)
{
return !isGreaterThan(other);
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(final Object obj)
{
if (!(obj instanceof ITimestamp))
{
return false;
}
ITimestamp rhs = (ITimestamp) obj;
return rhs.seconds() == seconds && rhs.nanoseconds() == nanoseconds;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = prime + (int) (nanoseconds ^ (nanoseconds >>> 32));
result = prime * result + (int) (seconds ^ (seconds >>> 32));
return result;
}
/**
* {@inheritDoc}
*/
@Override
public int compareTo(final ITimestamp rhs)
{
if (isGreaterThan(rhs))
{
return 1;
}
if (equals(rhs))
{
return 0;
}
return -1;
}
}