Java tutorial
/* $Id: e4b8682e0e2c1c42ec8b085dbd80a8b0018e73fb $ * * @license * 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 io.coala.time; import static io.coala.log.LogUtil.wrapToString; import java.math.BigDecimal; import java.text.DateFormat; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.temporal.ChronoField; import java.util.Calendar; import java.util.Date; import javax.measure.DecimalMeasure; import javax.measure.Measurable; import javax.measure.Measure; import javax.measure.quantity.Dimensionless; import javax.measure.unit.SI; import javax.measure.unit.Unit; import org.aeonbits.owner.Config; import org.aeonbits.owner.Converter; import org.joda.time.DateTime; import org.joda.time.ReadableDuration; import org.joda.time.ReadableInstant; import org.joda.time.format.DateTimeFormatter; import org.jscience.physics.amount.Amount; import io.coala.json.Wrapper; import io.coala.log.LogUtil.Pretty; import io.coala.math.MeasureUtil; /** * {@linkplain Instant} is a {@link Wrapper} of a {@linkplain TimeSpan} value * measuring a duration since the EPOCH (1970-01-01T00:00:00Z) that provides a * {@link #valueOf(String)} method to allow loading as {@link Converter * configuration} value, as per * {@link org.aeonbits.owner.Converters#CLASS_WITH_VALUE_OF_METHOD} * <p> * We considered various temporal measure implementations, including * <dl> * <dt>Java's native utilities</dt> * <dd>{@link java.util.Date} and {@link java.util.GregorianCalendar}</dd> * <dt></dt> * <dt>The JSR-275 {@code javax.measure} reference implementation v4.3.1 from * <a href="http://jscience.org/">jscience.org</a></dt> * <dd> * <li>takes any value type (e.g. {@linkplain Number}) or granularity (e.g. * {@link SI#NANO(javax.measure.unit.Unit nano)} or * {@link SI#PICO(javax.measure.unit.Unit) pico})</li></dd> * <dt>The JSR-310 {@code javax.time} Java8 extension (or back-port from * <a href="http://www.threeten.org/">threeten.org</a>):</dt> * <dd> * <li>supports nanosecond precision,</li>s * <li>{@linkplain org.threeten.bp.OldInstant} parses strictly ISO8601 format * (millis/nanos) only</li> * <dt>Joda's time API from <a href="http://www.joda.org/">joda.org</a></dt> * <dd> * <li>Allows lenient (lower and upper case) ISO8601 format strings</li> * <li>Joda time offers this * <a href="https://github.com/FasterXML/jackson-datatype-joda">datatype * extension for Jackson</a>.</li> * <li>offers many nice calendar and formatter implementations</li> * <li>will <a href="https://github.com/JodaOrg/joda-time/issues/52">not support * microsecond or nanosecond precision</a></li></dd> * <dt>Apache {@code commons-lang3} Date Utilities</dt> * <dd>limitations similar to Joda's time API (millisecond precision only)</dd> * </dl> * * @date $Date$ * @version $Id: e4b8682e0e2c1c42ec8b085dbd80a8b0018e73fb $ * @author Rick van Krevelen */ @SuppressWarnings({ "unchecked", "rawtypes" }) public class Instant extends Wrapper.Simple<TimeSpan> implements Comparable<Instant> { /** * for {@link Config}'s "natural" value conversion for an {@link Instant} * * @see org.aeonbits.owner.Converters.CLASS_WITH_VALUE_OF_METHOD * @see of(String) */ public static Instant valueOf(final String value) { return of(value); } /** * @param value a {@link String} representation of either: * <ul> * <li>a {@link DecimalMeasure JSR-275 Measure of duration} (e.g. * {@code "123 ms"}); or * <li>as {@code ISO 8601 Period} parsed with * {@link java.time.Duration#parse(CharSequence) JSR-310} or (on * failure) * {@link org.joda.time.format.ISOPeriodFormat#standard() Joda}, * e.g.: * * <pre> * "PT20.345S" -> parses as "20.345 seconds" * "PT15M" -> parses as "15 minutes" (where a minute is 60 seconds) * "PT10H" -> parses as "10 hours" (where an hour is 3600 seconds) * "P2D" -> parses as "2 days" (where a day is 24 hours or 86400 seconds) * "P2DT3H4M" -> parses as "2 days, 3 hours and 4 minutes" * "P-6H3M" -> parses as "-6 hours and +3 minutes" * "-P6H3M" -> parses as "-6 hours and -3 minutes" * "-P-6H+3M" -> parses as "+6 hours and -3 minutes" * </pre> * </ul> * * * @see java.time.Duration#parse(String) * @see org.joda.time.format.ISOPeriodFormat#standard() * @see DecimalMeasure */ public static Instant of(final String value) { return of(TimeSpan.valueOf(value)); } public static Instant of(final ReadableDuration millis) { return of(millis.getMillis(), Units.MILLIS); } public static Instant of(final ReadableInstant instant, final ReadableInstant offset) { return of(instant.getMillis() - offset.getMillis(), Units.MILLIS); } /** * {@link Instant} static factory method * * @param value a{@link ReadableInstant} instant, e.g. {@link DateTime} */ public static Instant of(final Date value, final Date offset) { return of(value.getTime() - offset.getTime(), Units.MILLIS); } /** * {@link Instant} static factory method * * @param value */ public static Instant of(final java.time.Instant value, final java.time.Instant offset) { return of(TimeSpan.of(DecimalMeasure.valueOf( BigDecimal.valueOf(value.get(ChronoField.NANO_OF_SECOND)).add( BigDecimal.valueOf(value.get(ChronoField.INSTANT_SECONDS)).multiply(BigDecimal.TEN.pow(9))), Units.NANOS))); } /** * {@link Instant} static factory method * * @param value the {@link Amount} (of * {@link javax.measure.quantity.Duration Duration} or * {@link javax.measure.unit.Unit#ONE dimensionless}) */ public static Instant of(final Amount value) { return of(TimeSpan.of(value)); } /** * {@link Instant} static factory method * * @param value the {@link Measure} (of * {@link javax.measure.quantity.Duration Duration} or * {@link javax.measure.unit.Unit#ONE dimensionless}) */ public static Instant of(final Measure value) { return of(TimeSpan.of(value)); } /** * {@link Instant} static factory method * * @param units the amount of {@link Dimensionless} time units */ public static Instant of(final Number units) { return of(TimeSpan.of(units)); } /** * {@link Instant} static factory method * * @param units the amount of time units */ public static Instant of(final Number value, final Unit<?> unit) { return of(TimeSpan.of(value, unit)); } /** * {@link Instant} static factory method * * @param value the {@link TimeSpan} */ public static Instant of(final TimeSpan value) { return Util.of(value, Instant.class); } /** the ZERO */ public static final Instant ZERO = of(TimeSpan.ZERO); /** the ONE */ public static final Instant ONE = of(TimeSpan.ONE); public Unit<?> unit() { return unwrap().getUnit(); } @Override public int compareTo(final Instant that) { return Util.compare(this, that); } public Instant multiply(final Measurable<Dimensionless> multiplicand) { return of(unwrap().multiply(multiplicand)); } public Instant multiply(final Number multiplicand) { return of(unwrap().multiply(multiplicand)); } public Instant divide(final Measurable<Dimensionless> divisor) { return of(unwrap().divide(divisor)); } public Instant divide(final Number divisor) { return of(unwrap().divide(divisor)); } public Instant add(final Duration augend) { return of(unwrap().add(augend.unwrap())); } public Instant add(final Measurable<?> augend) { return of(unwrap().add(augend)); } public Instant add(final Number augend) { return of(unwrap().add(augend)); } public Instant subtract(final Duration subtrahend) { return of(unwrap().subtract(subtrahend.unwrap())); } public Duration subtract(final Instant subtrahend) { return Duration.of(unwrap().subtract(subtrahend.unwrap())); } public Instant subtract(final Measurable<?> subtrahend) { return of(unwrap().subtract(subtrahend)); } public Instant subtract(final Number subtrahend) { return of(unwrap().subtract(subtrahend)); } public long toMillisLong() { return unwrap().longValue(Units.MILLIS); } public long toNanosLong() { return unwrap().longValue(Units.NANOS); } public Date toDate(final Date offset) { return new Date(offset.getTime() + toMillisLong()); } public Calendar toDate(final Calendar offset) { final Calendar result = Calendar.getInstance(offset.getTimeZone()); result.setTimeInMillis(offset.getTimeInMillis() + toMillisLong()); return result; } /** @return the Joda {@link ReadableInstant} implementation of an instant */ public DateTime toDate(final ReadableInstant offset) { return new DateTime(offset.getMillis() + toMillisLong(), offset.getZone()); } /** * @return the JSR-310 {@link LocalTime} implementation of a (zone and * date-less) instant */ public LocalTime toDate(final LocalTime offset) { return offset.plusNanos(toNanosLong()); } /** * @return the JSR-310 {@link LocalDateTime} implementation of a (zone-less) * instant */ public LocalDateTime toDate(final LocalDateTime offset) { return offset.plusNanos(toNanosLong()); } /** * @return the JSR-310 {@link java.time.Instant} implementation of an * instant */ public java.time.Instant toDate(final java.time.Instant offset) { return offset.plusNanos(toNanosLong()); } /** @return the JSR-275 {@link Measurable} implementation of an instant */ public TimeSpan toMeasure() { return unwrap(); } /** * @return the JScience {@link Amount} precision implementation of an * instant */ public Amount toAmount() { return MeasureUtil.toAmount(unwrap()); } /** * @param offset the instant that is considered the ZERO * @return the (possibly negative) {@link Duration} of this instant since * specified {@code offset} */ public Duration toDuration(final Instant offset) { return Duration.of(unwrap().subtract(offset.unwrap())); } /** * @param unit * @return */ public Instant to(final Unit unit) { return of(MeasureUtil.toUnit(toMeasure(), unit)); } public Pretty prettify(final int scale) { return unwrap().prettify(scale); } public Pretty prettify(final Unit<?> unit, final int scale) { return unwrap().prettify(unit, scale); } public Pretty prettify(final Date offset) { return wrapToString(() -> toDate(offset).toString()); } public Pretty prettify(final Date offset, final DateFormat formatter) { return wrapToString(() -> formatter.format(toDate(offset))); } public Pretty prettify(final LocalDateTime offset) { return wrapToString(() -> toDate(offset).toString()); } public Pretty prettify(final java.time.Instant offset) { return wrapToString(() -> toDate(offset).toString()); } public Pretty prettify(final java.time.Instant offset, final java.time.format.DateTimeFormatter formatter) { return wrapToString(() -> formatter.format(toDate(offset))); } public Pretty prettify(final DateTime offset) { return wrapToString(() -> toDate(offset).toString()); } /** * @param offset * @param formatter * @return */ public Object prettify(final DateTime offset, final DateTimeFormatter formatter) { return wrapToString(() -> formatter.print(toDate(offset))); } }