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

org.h2.api.Interval Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2004-2023 H2 Group. Multiple-Licensed under the MPL 2.0,
 * and the EPL 1.0 (https://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 */
package org.h2.api;

import static org.h2.util.DateTimeUtils.NANOS_PER_MINUTE;
import static org.h2.util.DateTimeUtils.NANOS_PER_SECOND;

import org.h2.message.DbException;
import org.h2.util.IntervalUtils;

/**
 * INTERVAL representation for result sets.
 */
public final class Interval {

    private final IntervalQualifier qualifier;

    /**
     * {@code false} for zero or positive intervals, {@code true} for negative
     * intervals.
     */
    private final boolean negative;

    /**
     * Non-negative long with value of leading field. For INTERVAL SECOND
     * contains only integer part of seconds.
     */
    private final long leading;

    /**
     * Non-negative long with combined value of all remaining field, or 0 for
     * single-field intervals, with exception for INTERVAL SECOND that uses this
     * field to store fractional part of seconds measured in nanoseconds.
     */
    private final long remaining;

    /**
     * Creates a new INTERVAL YEAR.
     *
     * @param years
     *            years, |years|<1018
     * @return INTERVAL YEAR
     */
    public static Interval ofYears(long years) {
        return new Interval(IntervalQualifier.YEAR, years < 0, Math.abs(years), 0);
    }

    /**
     * Creates a new INTERVAL MONTH.
     *
     * @param months
     *            months, |months|<1018
     * @return INTERVAL MONTH
     */
    public static Interval ofMonths(long months) {
        return new Interval(IntervalQualifier.MONTH, months < 0, Math.abs(months), 0);
    }

    /**
     * Creates a new INTERVAL DAY.
     *
     * @param days
     *            days, |days|<1018
     * @return INTERVAL DAY
     */
    public static Interval ofDays(long days) {
        return new Interval(IntervalQualifier.DAY, days < 0, Math.abs(days), 0);
    }

    /**
     * Creates a new INTERVAL HOUR.
     *
     * @param hours
     *            hours, |hours|<1018
     * @return INTERVAL HOUR
     */
    public static Interval ofHours(long hours) {
        return new Interval(IntervalQualifier.HOUR, hours < 0, Math.abs(hours), 0);
    }

    /**
     * Creates a new INTERVAL MINUTE.
     *
     * @param minutes
     *            minutes, |minutes|<1018
     * @return interval
     */
    public static Interval ofMinutes(long minutes) {
        return new Interval(IntervalQualifier.MINUTE, minutes < 0, Math.abs(minutes), 0);
    }

    /**
     * Creates a new INTERVAL SECOND.
     *
     * @param seconds
     *            seconds, |seconds|<1018
     * @return INTERVAL SECOND
     */
    public static Interval ofSeconds(long seconds) {
        return new Interval(IntervalQualifier.SECOND, seconds < 0, Math.abs(seconds), 0);
    }

    /**
     * Creates a new INTERVAL SECOND.
     *
     * 

* If both arguments are not equal to zero they should have the same sign. *

* * @param seconds * seconds, |seconds|<1018 * @param nanos * nanoseconds, |nanos|<1,000,000,000 * @return INTERVAL SECOND */ public static Interval ofSeconds(long seconds, int nanos) { // Interval is negative if any field is negative boolean negative = (seconds | nanos) < 0; if (negative) { // Ensure that all fields are negative or zero if (seconds > 0 || nanos > 0) { throw new IllegalArgumentException(); } // Make them positive seconds = -seconds; nanos = -nanos; // Long.MIN_VALUE and Integer.MIN_VALUE will be rejected by // constructor } return new Interval(IntervalQualifier.SECOND, negative, seconds, nanos); } /** * Creates a new INTERVAL SECOND. * * @param nanos * nanoseconds (including seconds) * @return INTERVAL SECOND */ public static Interval ofNanos(long nanos) { boolean negative = nanos < 0; if (negative) { nanos = -nanos; if (nanos < 0) { // Long.MIN_VALUE = -9_223_372_036_854_775_808L return new Interval(IntervalQualifier.SECOND, true, 9_223_372_036L, 854_775_808); } } return new Interval(IntervalQualifier.SECOND, negative, nanos / NANOS_PER_SECOND, nanos % NANOS_PER_SECOND); } /** * Creates a new INTERVAL YEAR TO MONTH. * *

* If both arguments are not equal to zero they should have the same sign. *

* * @param years * years, |years|<1018 * @param months * months, |months|<12 * @return INTERVAL YEAR TO MONTH */ public static Interval ofYearsMonths(long years, int months) { // Interval is negative if any field is negative boolean negative = (years | months) < 0; if (negative) { // Ensure that all fields are negative or zero if (years > 0 || months > 0) { throw new IllegalArgumentException(); } // Make them positive years = -years; months = -months; // Long.MIN_VALUE and Integer.MIN_VALUE will be rejected by // constructor } return new Interval(IntervalQualifier.YEAR_TO_MONTH, negative, years, months); } /** * Creates a new INTERVAL DAY TO HOUR. * *

* If both arguments are not equal to zero they should have the same sign. *

* * @param days * days, |days|<1018 * @param hours * hours, |hours|<24 * @return INTERVAL DAY TO HOUR */ public static Interval ofDaysHours(long days, int hours) { // Interval is negative if any field is negative boolean negative = (days | hours) < 0; if (negative) { // Ensure that all fields are negative or zero if (days > 0 || hours > 0) { throw new IllegalArgumentException(); } // Make them positive days = -days; hours = -hours; // Long.MIN_VALUE and Integer.MIN_VALUE will be rejected by // constructor } return new Interval(IntervalQualifier.DAY_TO_HOUR, negative, days, hours); } /** * Creates a new INTERVAL DAY TO MINUTE. * *

* Non-zero arguments should have the same sign. *

* * @param days * days, |days|<1018 * @param hours * hours, |hours|<24 * @param minutes * minutes, |minutes|<60 * @return INTERVAL DAY TO MINUTE */ public static Interval ofDaysHoursMinutes(long days, int hours, int minutes) { // Interval is negative if any field is negative boolean negative = (days | hours | minutes) < 0; if (negative) { // Ensure that all fields are negative or zero if (days > 0 || hours > 0 || minutes > 0) { throw new IllegalArgumentException(); } // Make them positive days = -days; hours = -hours; minutes = -minutes; if ((hours | minutes) < 0) { // Integer.MIN_VALUE throw new IllegalArgumentException(); } // days = Long.MIN_VALUE will be rejected by constructor } // Check only minutes. // Overflow in days or hours will be detected by constructor if (minutes >= 60) { throw new IllegalArgumentException(); } return new Interval(IntervalQualifier.DAY_TO_MINUTE, negative, days, hours * 60L + minutes); } /** * Creates a new INTERVAL DAY TO SECOND. * *

* Non-zero arguments should have the same sign. *

* * @param days * days, |days|<1018 * @param hours * hours, |hours|<24 * @param minutes * minutes, |minutes|<60 * @param seconds * seconds, |seconds|<60 * @return INTERVAL DAY TO SECOND */ public static Interval ofDaysHoursMinutesSeconds(long days, int hours, int minutes, int seconds) { return ofDaysHoursMinutesNanos(days, hours, minutes, seconds * NANOS_PER_SECOND); } /** * Creates a new INTERVAL DAY TO SECOND. * *

* Non-zero arguments should have the same sign. *

* * @param days * days, |days|<1018 * @param hours * hours, |hours|<24 * @param minutes * minutes, |minutes|<60 * @param nanos * nanoseconds, |nanos|<60,000,000,000 * @return INTERVAL DAY TO SECOND */ public static Interval ofDaysHoursMinutesNanos(long days, int hours, int minutes, long nanos) { // Interval is negative if any field is negative boolean negative = (days | hours | minutes | nanos) < 0; if (negative) { // Ensure that all fields are negative or zero if (days > 0 || hours > 0 || minutes > 0 || nanos > 0) { throw new IllegalArgumentException(); } // Make them positive days = -days; hours = -hours; minutes = -minutes; nanos = -nanos; if ((hours | minutes | nanos) < 0) { // Integer.MIN_VALUE, Long.MIN_VALUE throw new IllegalArgumentException(); } // days = Long.MIN_VALUE will be rejected by constructor } // Check only minutes and nanoseconds. // Overflow in days or hours will be detected by constructor if (minutes >= 60 || nanos >= NANOS_PER_MINUTE) { throw new IllegalArgumentException(); } return new Interval(IntervalQualifier.DAY_TO_SECOND, negative, days, (hours * 60L + minutes) * NANOS_PER_MINUTE + nanos); } /** * Creates a new INTERVAL HOUR TO MINUTE. * *

* If both arguments are not equal to zero they should have the same sign. *

* * @param hours * hours, |hours|<1018 * @param minutes * minutes, |minutes|<60 * @return INTERVAL HOUR TO MINUTE */ public static Interval ofHoursMinutes(long hours, int minutes) { // Interval is negative if any field is negative boolean negative = (hours | minutes) < 0; if (negative) { // Ensure that all fields are negative or zero if (hours > 0 || minutes > 0) { throw new IllegalArgumentException(); } // Make them positive hours = -hours; minutes = -minutes; // Long.MIN_VALUE and Integer.MIN_VALUE will be rejected by // constructor } return new Interval(IntervalQualifier.HOUR_TO_MINUTE, negative, hours, minutes); } /** * Creates a new INTERVAL HOUR TO SECOND. * *

* Non-zero arguments should have the same sign. *

* * @param hours * hours, |hours|<1018 * @param minutes * minutes, |minutes|<60 * @param seconds * seconds, |seconds|<60 * @return INTERVAL HOUR TO SECOND */ public static Interval ofHoursMinutesSeconds(long hours, int minutes, int seconds) { return ofHoursMinutesNanos(hours, minutes, seconds * NANOS_PER_SECOND); } /** * Creates a new INTERVAL HOUR TO SECOND. * *

* Non-zero arguments should have the same sign. *

* * @param hours * hours, |hours|<1018 * @param minutes * minutes, |minutes|<60 * @param nanos * nanoseconds, |seconds|<60,000,000,000 * @return INTERVAL HOUR TO SECOND */ public static Interval ofHoursMinutesNanos(long hours, int minutes, long nanos) { // Interval is negative if any field is negative boolean negative = (hours | minutes | nanos) < 0; if (negative) { // Ensure that all fields are negative or zero if (hours > 0 || minutes > 0 || nanos > 0) { throw new IllegalArgumentException(); } // Make them positive hours = -hours; minutes = -minutes; nanos = -nanos; if ((minutes | nanos) < 0) { // Integer.MIN_VALUE, Long.MIN_VALUE throw new IllegalArgumentException(); } // hours = Long.MIN_VALUE will be rejected by constructor } // Check only nanoseconds. // Overflow in hours or minutes will be detected by constructor if (nanos >= NANOS_PER_MINUTE) { throw new IllegalArgumentException(); } return new Interval(IntervalQualifier.HOUR_TO_SECOND, negative, hours, minutes * NANOS_PER_MINUTE + nanos); } /** * Creates a new INTERVAL MINUTE TO SECOND. * *

* If both arguments are not equal to zero they should have the same sign. *

* * @param minutes * minutes, |minutes|<1018 * @param seconds * seconds, |seconds|<60 * @return INTERVAL MINUTE TO SECOND */ public static Interval ofMinutesSeconds(long minutes, int seconds) { return ofMinutesNanos(minutes, seconds * NANOS_PER_SECOND); } /** * Creates a new INTERVAL MINUTE TO SECOND. * *

* If both arguments are not equal to zero they should have the same sign. *

* * @param minutes * minutes, |minutes|<1018 * @param nanos * nanoseconds, |nanos|<60,000,000,000 * @return INTERVAL MINUTE TO SECOND */ public static Interval ofMinutesNanos(long minutes, long nanos) { // Interval is negative if any field is negative boolean negative = (minutes | nanos) < 0; if (negative) { // Ensure that all fields are negative or zero if (minutes > 0 || nanos > 0) { throw new IllegalArgumentException(); } // Make them positive minutes = -minutes; nanos = -nanos; // Long.MIN_VALUE will be rejected by constructor } return new Interval(IntervalQualifier.MINUTE_TO_SECOND, negative, minutes, nanos); } /** * Creates a new interval. Do not use this constructor, use static methods * instead. * * @param qualifier * qualifier * @param negative * whether interval is negative * @param leading * value of leading field * @param remaining * combined value of all remaining fields */ public Interval(IntervalQualifier qualifier, boolean negative, long leading, long remaining) { this.qualifier = qualifier; try { this.negative = IntervalUtils.validateInterval(qualifier, negative, leading, remaining); } catch (DbException e) { throw new IllegalArgumentException(); } this.leading = leading; this.remaining = remaining; } /** * Returns qualifier of this interval. * * @return qualifier */ public IntervalQualifier getQualifier() { return qualifier; } /** * Returns where the interval is negative. * * @return where the interval is negative */ public boolean isNegative() { return negative; } /** * Returns value of leading field of this interval. For {@code SECOND} * intervals returns integer part of seconds. * * @return value of leading field */ public long getLeading() { return leading; } /** * Returns combined value of remaining fields of this interval. For * {@code SECOND} intervals returns nanoseconds. * * @return combined value of remaining fields */ public long getRemaining() { return remaining; } /** * Returns years value, if any. * * @return years, or 0 */ public long getYears() { return IntervalUtils.yearsFromInterval(qualifier, negative, leading, remaining); } /** * Returns months value, if any. * * @return months, or 0 */ public long getMonths() { return IntervalUtils.monthsFromInterval(qualifier, negative, leading, remaining); } /** * Returns days value, if any. * * @return days, or 0 */ public long getDays() { return IntervalUtils.daysFromInterval(qualifier, negative, leading, remaining); } /** * Returns hours value, if any. * * @return hours, or 0 */ public long getHours() { return IntervalUtils.hoursFromInterval(qualifier, negative, leading, remaining); } /** * Returns minutes value, if any. * * @return minutes, or 0 */ public long getMinutes() { return IntervalUtils.minutesFromInterval(qualifier, negative, leading, remaining); } /** * Returns value of integer part of seconds, if any. * * @return seconds, or 0 */ public long getSeconds() { if (qualifier == IntervalQualifier.SECOND) { return negative ? -leading : leading; } return getSecondsAndNanos() / NANOS_PER_SECOND; } /** * Returns value of fractional part of seconds (in nanoseconds), if any. * * @return nanoseconds, or 0 */ public long getNanosOfSecond() { if (qualifier == IntervalQualifier.SECOND) { return negative ? -remaining : remaining; } return getSecondsAndNanos() % NANOS_PER_SECOND; } /** * Returns seconds value measured in nanoseconds, if any. * *

* This method returns a long value that cannot fit all possible values of * INTERVAL SECOND. For a very large intervals of this type use * {@link #getSeconds()} and {@link #getNanosOfSecond()} instead. This * method can be safely used for intervals of other day-time types. *

* * @return nanoseconds (including seconds), or 0 */ public long getSecondsAndNanos() { return IntervalUtils.nanosFromInterval(qualifier, negative, leading, remaining); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + qualifier.hashCode(); result = prime * result + (negative ? 1231 : 1237); result = prime * result + (int) (leading ^ leading >>> 32); result = prime * result + (int) (remaining ^ remaining >>> 32); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof Interval)) { return false; } Interval other = (Interval) obj; return qualifier == other.qualifier && negative == other.negative && leading == other.leading && remaining == other.remaining; } @Override public String toString() { return IntervalUtils.appendInterval(new StringBuilder(), getQualifier(), negative, leading, remaining) .toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy