All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cinchapi.concourse.Timestamp Maven / Gradle / Ivy

/*
 * Copyright (c) 2013-2017 Cinchapi Inc.
 *
 * Licensed 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.
 */
package com.cinchapi.concourse;

import java.util.concurrent.TimeUnit;

import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;

import org.joda.time.Chronology;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import com.cinchapi.concourse.annotate.PackagePrivate;
import com.cinchapi.concourse.time.Time;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Longs;

/**
 * A wrapper class for a Unix timestamp with microsecond precision. A
 * {@link Timestamp} is required for historical operations in {@link Concourse}.
 * This class provides interoperability with Joda {@link DateTime} objects with
 * the {@link #fromJoda(DateTime)} and {@link #getJoda()} methods.
 * 
 * @author Jeff Nelson
 */
@Immutable
@ThreadSafe
public final class Timestamp {

    // Joda DateTime uses millisecond instead of microsecond precision, so this
    // class is a wrapper that will handle microseconds so we don't ever lose
    // data that happens within the same millisecond.

    /**
     * Return a {@code Timestamp} that corresponds to the system
     * epoch timestamp with microsecond precision.
     * 
     * @return the timestamp for system epoch
     */
    public static Timestamp epoch() {
        return Timestamp.fromMicros(-1);
    }

    /**
     * Return the {@code Timestamp} that corresponds to the provided joda
     * DateTime object.
     * 
     * @param joda a {@link DateTime} object
     * @return the timestamp for {@code joda}
     */
    public static Timestamp fromJoda(DateTime joda) {
        return new Timestamp(joda);
    }

    /**
     * Return a {@code Timestamp} that corresponds to the provided Unix
     * timestamp with microsecond precision.
     * 
     * @param microseconds the number of microseconds since the Unix epoch
     * @return the timestamp for {@code microseconds}
     */
    public static Timestamp fromMicros(long microseconds) {
        return new Timestamp(microseconds);
    }

    /**
     * Take the {@code description} and return a {@link Timestamp} that can be
     * passed to {@link Concourse driver} API methods.
     * 

* Timestamp description are parsed by Concourse Server, so this method only * returns a wrapper that is meant to be passed over the wire. Timestamps * returned from this method are non-operable and will throw * exceptions if you call methods that would return a precise instant (i.e. * {@link #getJoda()} or {@link #getMicros()}). *

* * @param description a relative or absolute natural language description of * an instant. * @return a hollow {@link Timestamp} that wraps the description */ public static Timestamp fromString(String description) { return new Timestamp(description); } /** * Return a {@code Timestamp} set the current system microsecond time using * ISOChronology in the default time zone. * * @return the current timestamp, not null */ public static Timestamp now() { return new Timestamp(Time.now()); } /** * Return a {@code Timestamp} set to the current system microsecond time * using the specified chronology. * * @param chronology the chronology, not null * @return the current timestamp, not null */ public static Timestamp now(Chronology chronology) { long microseconds = Time.now(); return new Timestamp(microseconds, new DateTime(TimeUnit.MILLISECONDS .convert(microseconds, TimeUnit.MICROSECONDS), chronology)); } /** * Return a {@code Timestamp} set to the current system microsecond time * using ISOChronology in the specified time zone. * * @param zone the time zone, not null * @return the current timestamp, not null */ public static Timestamp now(DateTimeZone zone) { long microseconds = Time.now(); return new Timestamp(microseconds, new DateTime(TimeUnit.MILLISECONDS .convert(microseconds, TimeUnit.MICROSECONDS), zone)); } /** * Parses a {@code Timestamp} from the specified string using a formatter. * * @param str the string to parse, not null * @param formatter the formatter to use, not null * @return the parsed timestamp */ public static Timestamp parse(String str, DateTimeFormatter formatter) { return new Timestamp(DateTime.parse(str, formatter)); } /** * The default formatter that is used to display objects of this class. */ public static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormat .forPattern("E MMM dd, yyyy @ h:mm:ss:SS a z"); /** * A relative or absolute description of an instant that is translated to an * actual microsecond timestamp in Concourse Server. By convention, a * {@link Timestamp} object is considered to be {@link #isString() hollow} * if and only if the value of this variable is non-null. */ private final String description; /** * A {@link DateTime} object that corresponds to this {@link Timestamp}. We * use this for the {@link #toString() string} representation and for any * other comparative operations that need to take things like timezones into * account. */ private final DateTime joda; /** * The number of microseconds since the Unix epoch that identify the instant * represented by this {@link Timestamp}. */ private final long microseconds; /** * Construct a new instance. * * @param joda */ private Timestamp(DateTime joda) { this.joda = joda; this.microseconds = TimeUnit.MICROSECONDS.convert(joda.getMillis(), TimeUnit.MILLISECONDS); this.description = null; } /** * Construct a new instance. * * @param microseconds */ private Timestamp(long microseconds) { this.microseconds = microseconds; this.joda = new DateTime(TimeUnit.MILLISECONDS.convert(microseconds, TimeUnit.MICROSECONDS)); this.description = null; } /** * Construct a new instance. * * @param microseconds * @param joda */ private Timestamp(long microseconds, DateTime joda) { this.microseconds = microseconds; this.joda = joda; this.description = null; } /** * Construct a {@link #isString()} instance. * * @param description the description to be resolved into an instant by * Concourse Server */ private Timestamp(String description) { this.microseconds = 0; this.joda = null; this.description = description; } @Override public boolean equals(Object obj) { if(obj instanceof Timestamp && !isString()) { return Longs.compare(microseconds, ((Timestamp) obj).microseconds) == 0; } // NOTE: By convention, two hollow timestamps are NEVER equal return false; } /** * Return the Joda {@link DateTime} object that corresponds to this * Timestamp. * * @return the corresponding joda DateTime */ public DateTime getJoda() { Preconditions.checkState(!isString(), "Only Concourse Server can parse a DateTime " + "from a Timestamp created from a string."); return joda; } /** * Return the number of microseconds since the Unix epoch that is * represented by this Timestamp. * * @return the microseconds */ public long getMicros() { Preconditions.checkState(!isString(), "Only Concourse Server can parse microseconds " + "from a Timestamp created from a string."); return microseconds; } @Override public int hashCode() { return isString() ? description.hashCode() : Longs.hashCode(microseconds); } @Override public String toString() { return isString() ? description : joda.toString(DEFAULT_FORMATTER); } /** * The {@link com.cinchapi.concourse.thrift.ConcourseService thrift} API * allows specifying timestamps using either microseconds from the unix * epoch ( {@link Long long}) or a natural language description of an * absolute or relative instant ({@link String}). But we can't define * overloaded methods in the {@link Concourse driver} API that take a long * or String for the timestamp parameter because that signatures would be * ambiguous (i.e. does the method {@link Concourse#select(String, String)} * mean {@code select(key, ccl)} or {@code select(ccl, timestring)}?). *

* Therefore, we allow a {@link Timestamp} to be created * {@link #fromString(String) from a string description}, which will be * translated and resolved by Concourse Server. But these objects are * considered to be hollow because the driver and client code is unable to * use the objects in any way. *

*

* For a hollow Timestamp, use the {@link #toString()} method to get the * description. *

* * @return {@code true} if the timestamp was created * {@link #fromString(String) using a description} */ @PackagePrivate boolean isString() { return description != null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy