org.jooq.types.DayToSecond Maven / Gradle / Ivy
/**
* Copyright (c) 2009-2016, Data Geekery GmbH (http://www.datageekery.com)
* All rights reserved.
*
* 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.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.types;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jooq.Field;
import org.jooq.SQLDialect;
import org.jooq.tools.Convert;
import org.jooq.tools.StringUtils;
/**
* An implementation for the SQL standard INTERVAL DAY TO SECOND
* data type.
*
* DayToSecond
is a {@link Number} whose {@link Number#intValue()}
* represents the (truncated) number of milliseconds of the interval,
* {@link Number#doubleValue()} represents the approximative number of
* milliseconds (including hours, minutes, seconds, nanoseconds) of the
* interval.
*
* Note: only a few databases actually support this data type on its own. You
* can still use it for date time arithmetic in other databases, though, through
* {@link Field#add(Field)} and {@link Field#sub(Field)} Databases that have
* been observed to natively support INTERVAL
data types are:
*
* - {@link SQLDialect#HSQLDB}
* - {@link SQLDialect#INGRES}
* - {@link SQLDialect#ORACLE}
* - {@link SQLDialect#POSTGRES}
*
*
* These dialects have been observed to partially support INTERVAL
* data types in date time arithmetic functions, such as
* TIMESTAMPADD
, and TIMESTAMPDIFF
:
*
* - {@link SQLDialect#CUBRID}
* - {@link SQLDialect#MARIADB}
* - {@link SQLDialect#MYSQL}
*
*
* @author Lukas Eder
* @see Interval
*/
public final class DayToSecond extends Number implements Interval, Comparable {
/**
* Generated UID
*/
private static final long serialVersionUID = -3853596481984643811L;
private static final Pattern PATTERN = Pattern.compile("(\\+|-)?(?:(\\d+) )?(\\d+):(\\d+):(\\d+)(?:\\.(\\d+))?");
private final boolean negative;
private final int days;
private final int hours;
private final int minutes;
private final int seconds;
private final int nano;
/**
* Create a new day-hour interval.
*/
public DayToSecond(int days) {
this(days, 0, 0, 0, 0, false);
}
/**
* Create a new day-hour interval.
*/
public DayToSecond(int days, int hours) {
this(days, hours, 0, 0, 0, false);
}
/**
* Create a new day-hour interval.
*/
public DayToSecond(int days, int hours, int minutes) {
this(days, hours, minutes, 0, 0, false);
}
/**
* Create a new day-hour interval.
*/
public DayToSecond(int days, int hours, int minutes, int seconds) {
this(days, hours, minutes, seconds, 0, false);
}
/**
* Create a new day-hour interval.
*/
public DayToSecond(int days, int hours, int minutes, int seconds, int nano) {
this(days, hours, minutes, seconds, nano, false);
}
private DayToSecond(int days, int hours, int minutes, int seconds, int nano, boolean negative) {
// Perform normalisation. Specifically, Postgres may return intervals
// such as 24:00:00, 25:13:15, etc...
if (nano >= 1000000000) {
seconds += (nano / 1000000000);
nano %= 1000000000;
}
if (seconds >= 60) {
minutes += (seconds / 60);
seconds %= 60;
}
if (minutes >= 60) {
hours += (minutes / 60);
minutes %= 60;
}
if (hours >= 24) {
days += (hours / 24);
hours %= 24;
}
this.negative = negative;
this.days = days;
this.hours = hours;
this.minutes = minutes;
this.seconds = seconds;
this.nano = nano;
}
/**
* Parse a string representation of a INTERVAL DAY TO SECOND
*
* @param string A string representation of the form
* [+|-][days] [hours]:[minutes]:[seconds].[fractional seconds]
* @return The parsed INTERVAL DAY TO SECOND
object, or
* null
if the string could not be parsed.
*/
public static DayToSecond valueOf(String string) {
if (string != null) {
// Accept also doubles as the number of days
try {
return valueOf(Double.valueOf(string));
}
catch (NumberFormatException e) {
Matcher matcher = PATTERN.matcher(string);
if (matcher.find()) {
boolean negative = "-".equals(matcher.group(1));
int days = Convert.convert(matcher.group(2), int.class);
int hours = Convert.convert(matcher.group(3), int.class);
int minutes = Convert.convert(matcher.group(4), int.class);
int seconds = Convert.convert(matcher.group(5), int.class);
int nano = Convert.convert(StringUtils.rightPad(matcher.group(6), 9, "0"), int.class);
return new DayToSecond(days, hours, minutes, seconds, nano, negative);
}
}
}
return null;
}
/**
* Load a {@link Double} representation of a INTERVAL DAY TO SECOND
*
* @param milli The number of milliseconds as a fractional number
* @return The loaded INTERVAL DAY TO SECOND
object
*/
public static DayToSecond valueOf(double milli) {
double abs = Math.abs(milli);
int n = (int) ((abs % 1000) * 1000000.0); abs = Math.floor(abs / 1000);
int s = (int) (abs % 60); abs = Math.floor(abs / 60);
int m = (int) (abs % 60); abs = Math.floor(abs / 60);
int h = (int) (abs % 24); abs = Math.floor(abs / 24);
int d = (int) abs;
DayToSecond result = new DayToSecond(d, h, m, s, n);
if (milli < 0) {
result = result.neg();
}
return result;
}
// -------------------------------------------------------------------------
// XXX Number API
// -------------------------------------------------------------------------
@Override
public final int intValue() {
return (int) doubleValue();
}
@Override
public final long longValue() {
return (long) doubleValue();
}
@Override
public final float floatValue() {
return (float) doubleValue();
}
@Override
public final double doubleValue() {
return getTotalMilli();
}
// -------------------------------------------------------------------------
// XXX Interval API
// -------------------------------------------------------------------------
@Override
public final DayToSecond neg() {
return new DayToSecond(days, hours, minutes, seconds, nano, !negative);
}
@Override
public final DayToSecond abs() {
return new DayToSecond(days, hours, minutes, seconds, nano, false);
}
/**
* Get the day-part of this interval
*/
public final int getDays() {
return days;
}
/**
* Get the hour-part of this interval
*/
public final int getHours() {
return hours;
}
/**
* Get the minute-part of this interval
*/
public final int getMinutes() {
return minutes;
}
/**
* Get the second-part of this interval
*/
public final int getSeconds() {
return seconds;
}
/**
* Get the (truncated) milli-part of this interval
*/
public final int getMilli() {
return nano / 1000000;
}
/**
* Get the (truncated) micro-part of this interval
*/
public final int getMicro() {
return nano / 1000;
}
/**
* Get the nano-part of this interval
*/
public final int getNano() {
return nano;
}
/**
* Get the whole interval in days
*/
public final double getTotalDays() {
return getSign() * (
nano / (24.0 * 3600.0 * 1000000000.0) +
seconds / (24.0 * 3600.0) +
minutes / (24.0 * 60.0) +
hours / 24.0 +
days);
}
/**
* Get the whole interval in hours
*/
public final double getTotalHours() {
return getSign() * (
nano / (3600.0 * 1000000000.0) +
seconds / 3600.0 +
minutes / 60.0 +
hours +
24.0 * days);
}
/**
* Get the whole interval in minutes
*/
public final double getTotalMinutes() {
return getSign() * (
nano / (60.0 * 1000000000.0) +
seconds / 60.0 +
minutes +
60.0 * hours +
60.0 * 24.0 * days);
}
/**
* Get the whole interval in seconds
*/
public final double getTotalSeconds() {
return getSign() * (
nano / 1000000000.0 +
seconds +
60.0 * minutes +
3600.0 * hours +
3600.0 * 24.0 * days);
}
/**
* Get the whole interval in milli-seconds
*/
public final double getTotalMilli() {
return getSign() * (
nano / 1000000.0 +
1000.0 * seconds +
1000.0 * 60.0 * minutes +
1000.0 * 3600.0 * hours +
1000.0 * 3600.0 * 24.0 * days);
}
/**
* Get the whole interval in micro-seconds
*/
public final double getTotalMicro() {
return getSign() * (
nano / 1000.0 +
1000000.0 * seconds +
1000000.0 * 60.0 * minutes +
1000000.0 * 3600.0 * hours +
1000000.0 * 3600.0 * 24.0 * days);
}
/**
* Get the whole interval in nano-seconds
*/
public final double getTotalNano() {
return getSign() * (
nano +
1000000000.0 * seconds +
1000000000.0 * 60.0 * minutes +
1000000000.0 * 3600.0 * hours +
1000000000.0 * 3600.0 * 24.0 * days);
}
@Override
public final int getSign() {
return negative ? -1 : 1;
}
// -------------------------------------------------------------------------
// XXX Comparable and Object API
// -------------------------------------------------------------------------
@Override
public final int compareTo(DayToSecond that) {
if (days < that.days) {
return -1;
}
if (days > that.days) {
return 1;
}
if (hours < that.hours) {
return -1;
}
if (hours > that.hours) {
return 1;
}
if (minutes < that.minutes) {
return -1;
}
if (minutes > that.minutes) {
return 1;
}
if (seconds < that.seconds) {
return -1;
}
if (seconds > that.seconds) {
return 1;
}
if (nano < that.nano) {
return -1;
}
if (nano > that.nano) {
return 1;
}
return 0;
}
@Override
public final int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + days;
result = prime * result + hours;
result = prime * result + minutes;
result = prime * result + nano;
result = prime * result + seconds;
return result;
}
@Override
public final boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DayToSecond other = (DayToSecond) obj;
if (days != other.days)
return false;
if (hours != other.hours)
return false;
if (minutes != other.minutes)
return false;
if (nano != other.nano)
return false;
if (seconds != other.seconds)
return false;
return true;
}
@Override
public final String toString() {
StringBuilder sb = new StringBuilder();
sb.append(negative ? "-" : "+");
sb.append(days);
sb.append(" ");
if (hours < 10)
sb.append("0");
sb.append(hours);
sb.append(":");
if (minutes < 10)
sb.append("0");
sb.append(minutes);
sb.append(":");
if (seconds < 10)
sb.append("0");
sb.append(seconds);
sb.append(".");
sb.append(StringUtils.leftPad("" + nano, 9, "0"));
return sb.toString();
}
}