Unverified 提交 e85ffecb authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1378 from katzyn/datetime

Add more methods to Interval and remove h2.unlimitedTimeRange
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
*/ */
package org.h2.api; 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.DateTimeUtils; import org.h2.util.DateTimeUtils;
/** /**
...@@ -14,61 +18,74 @@ public final class Interval { ...@@ -14,61 +18,74 @@ public final class Interval {
private final IntervalQualifier qualifier; private final IntervalQualifier qualifier;
/**
* {@code false} for zero or positive intervals, {@code true} for negative
* intervals.
*/
private final boolean negative; 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; 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; private final long remaining;
/** /**
* Creates a new interval. * Creates a new INTERVAL YEAR.
* *
* @param years * @param years
* years * years, |years|&lt;10<sup>18</sup>
* @return interval * @return INTERVAL YEAR
*/ */
public static Interval ofYears(long years) { public static Interval ofYears(long years) {
return new Interval(IntervalQualifier.YEAR, years < 0, Math.abs(years), 0); return new Interval(IntervalQualifier.YEAR, years < 0, Math.abs(years), 0);
} }
/** /**
* Creates a new interval. * Creates a new INTERVAL MONTH.
* *
* @param months * @param months
* months * months, |months|&lt;10<sup>18</sup>
* @return interval * @return INTERVAL MONTH
*/ */
public static Interval ofMonths(long months) { public static Interval ofMonths(long months) {
return new Interval(IntervalQualifier.MONTH, months < 0, Math.abs(months), 0); return new Interval(IntervalQualifier.MONTH, months < 0, Math.abs(months), 0);
} }
/** /**
* Creates a new interval. * Creates a new INTERVAL DAY.
* *
* @param days * @param days
* days * days, |days|&lt;10<sup>18</sup>
* @return interval * @return INTERVAL DAY
*/ */
public static Interval ofDays(long days) { public static Interval ofDays(long days) {
return new Interval(IntervalQualifier.DAY, days < 0, Math.abs(days), 0); return new Interval(IntervalQualifier.DAY, days < 0, Math.abs(days), 0);
} }
/** /**
* Creates a new interval. * Creates a new INTERVAL HOUR.
* *
* @param hours * @param hours
* hours * hours, |hours|&lt;10<sup>18</sup>
* @return interval * @return INTERVAL HOUR
*/ */
public static Interval ofHours(long hours) { public static Interval ofHours(long hours) {
return new Interval(IntervalQualifier.HOUR, hours < 0, Math.abs(hours), 0); return new Interval(IntervalQualifier.HOUR, hours < 0, Math.abs(hours), 0);
} }
/** /**
* Creates a new interval. * Creates a new INTERVAL MINUTE.
* *
* @param minutes * @param minutes
* minutes * minutes, |minutes|&lt;10<sup>18</sup>
* @return interval * @return interval
*/ */
public static Interval ofMinutes(long minutes) { public static Interval ofMinutes(long minutes) {
...@@ -76,25 +93,371 @@ public final class Interval { ...@@ -76,25 +93,371 @@ public final class Interval {
} }
/** /**
* Creates a new interval. * Creates a new INTERVAL SECOND.
*
* @param seconds
* seconds, |seconds|&lt;10<sup>18</sup>
* @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.
*
* <p>
* If both arguments are not equal to zero they should have the same sign.
* </p>
*
* @param seconds
* seconds, |seconds|&lt;10<sup>18</sup>
* @param nanos
* nanoseconds, |nanos|&lt;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 * @param nanos
* nanoseconds (including seconds) * nanoseconds (including seconds)
* @return interval * @return INTERVAL SECOND
*/ */
public static Interval ofNanos(long nanos) { public static Interval ofNanos(long nanos) {
boolean negative = nanos < 0; boolean negative = nanos < 0;
if (negative) { if (negative) {
nanos = -nanos; nanos = -nanos;
if (nanos < 0) { 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.
*
* <p>
* If both arguments are not equal to zero they should have the same sign.
* </p>
*
* @param years
* years, |years|&lt;10<sup>18</sup>
* @param months
* months, |months|&lt;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.
*
* <p>
* If both arguments are not equal to zero they should have the same sign.
* </p>
*
* @param days
* days, |days|&lt;10<sup>18</sup>
* @param hours
* hours, |hours|&lt;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.
*
* <p>
* Non-zero arguments should have the same sign.
* </p>
*
* @param days
* days, |days|&lt;10<sup>18</sup>
* @param hours
* hours, |hours|&lt;24
* @param minutes
* minutes, |minutes|&lt;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.
*
* <p>
* Non-zero arguments should have the same sign.
* </p>
*
* @param days
* days, |days|&lt;10<sup>18</sup>
* @param hours
* hours, |hours|&lt;24
* @param minutes
* minutes, |minutes|&lt;60
* @param seconds
* seconds, |seconds|&lt;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.
*
* <p>
* Non-zero arguments should have the same sign.
* </p>
*
* @param days
* days, |days|&lt;10<sup>18</sup>
* @param hours
* hours, |hours|&lt;24
* @param minutes
* minutes, |minutes|&lt;60
* @param nanos
* nanoseconds, |nanos|&lt;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.
*
* <p>
* If both arguments are not equal to zero they should have the same sign.
* </p>
*
* @param hours
* hours, |hours|&lt;10<sup>18</sup>
* @param minutes
* minutes, |minutes|&lt;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.
*
* <p>
* Non-zero arguments should have the same sign.
* </p>
*
* @param hours
* hours, |hours|&lt;10<sup>18</sup>
* @param minutes
* minutes, |minutes|&lt;60
* @param seconds
* seconds, |seconds|&lt;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.
*
* <p>
* Non-zero arguments should have the same sign.
* </p>
*
* @param hours
* hours, |hours|&lt;10<sup>18</sup>
* @param minutes
* minutes, |minutes|&lt;60
* @param nanos
* nanoseconds, |seconds|&lt;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(); 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.SECOND, negative, nanos / 1_000_000_000, nanos % 1_000_000_000); return new Interval(IntervalQualifier.HOUR_TO_SECOND, negative, hours, minutes * NANOS_PER_MINUTE + nanos);
} }
/** /**
* Creates a new interval. * Creates a new INTERVAL MINUTE TO SECOND
*
* <p>
* If both arguments are not equal to zero they should have the same sign.
* </p>
*
* @param minutes
* minutes, |minutes|&lt;10<sup>18</sup>
* @param seconds
* seconds, |seconds|&lt;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
*
* <p>
* If both arguments are not equal to zero they should have the same sign.
* </p>
*
* @param minutes
* minutes, |minutes|&lt;10<sup>18</sup>
* @param nanos
* nanoseconds, |nanos|&lt;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 * @param qualifier
* qualifier * qualifier
...@@ -103,11 +466,15 @@ public final class Interval { ...@@ -103,11 +466,15 @@ public final class Interval {
* @param leading * @param leading
* value of leading field * value of leading field
* @param remaining * @param remaining
* values of all remaining fields * combined value of all remaining fields
*/ */
public Interval(IntervalQualifier qualifier, boolean negative, long leading, long remaining) { public Interval(IntervalQualifier qualifier, boolean negative, long leading, long remaining) {
this.qualifier = qualifier; this.qualifier = qualifier;
this.negative = DateTimeUtils.validateInterval(qualifier, negative, leading, remaining); try {
this.negative = DateTimeUtils.validateInterval(qualifier, negative, leading, remaining);
} catch (DbException e) {
throw new IllegalArgumentException();
}
this.leading = leading; this.leading = leading;
this.remaining = remaining; this.remaining = remaining;
} }
...@@ -151,6 +518,8 @@ public final class Interval { ...@@ -151,6 +518,8 @@ public final class Interval {
} }
/** /**
* Returns years value, if any.
*
* @return years, or 0 * @return years, or 0
*/ */
public long getYears() { public long getYears() {
...@@ -158,6 +527,8 @@ public final class Interval { ...@@ -158,6 +527,8 @@ public final class Interval {
} }
/** /**
* Returns months value, if any.
*
* @return months, or 0 * @return months, or 0
*/ */
public long getMonths() { public long getMonths() {
...@@ -165,6 +536,8 @@ public final class Interval { ...@@ -165,6 +536,8 @@ public final class Interval {
} }
/** /**
* Returns days value, if any.
*
* @return days, or 0 * @return days, or 0
*/ */
public long getDays() { public long getDays() {
...@@ -172,6 +545,8 @@ public final class Interval { ...@@ -172,6 +545,8 @@ public final class Interval {
} }
/** /**
* Returns hours value, if any.
*
* @return hours, or 0 * @return hours, or 0
*/ */
public long getHours() { public long getHours() {
...@@ -179,6 +554,8 @@ public final class Interval { ...@@ -179,6 +554,8 @@ public final class Interval {
} }
/** /**
* Returns minutes value, if any.
*
* @return minutes, or 0 * @return minutes, or 0
*/ */
public long getMinutes() { public long getMinutes() {
...@@ -186,9 +563,42 @@ public final class Interval { ...@@ -186,9 +563,42 @@ public final class Interval {
} }
/** /**
* 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.
*
* <p>
* 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.
* </p>
*
* @return nanoseconds (including seconds), or 0 * @return nanoseconds (including seconds), or 0
*/ */
public long getNanos() { public long getSecondsAndNanos() {
return DateTimeUtils.nanosFromInterval(qualifier, negative, leading, remaining); return DateTimeUtils.nanosFromInterval(qualifier, negative, leading, remaining);
} }
......
...@@ -383,38 +383,6 @@ public class SysProperties { ...@@ -383,38 +383,6 @@ public class SysProperties {
*/ */
public static final boolean RETURN_OFFSET_DATE_TIME = Utils.getProperty("h2.returnOffsetDateTime", PREVIEW); public static final boolean RETURN_OFFSET_DATE_TIME = Utils.getProperty("h2.returnOffsetDateTime", PREVIEW);
/**
* System property {@code h2.unlimitedTimeRange}, {@code false} by default.
*
* <p>
* Controls limits of TIME data type.
* </p>
*
* <table>
* <thead>
* <tr>
* <th>h2.unlimitedTimeRange</th>
* <th>Minimum TIME value</th>
* <th>Maximum TIME value</th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td>false</td>
* <td>00:00:00.000000000</td>
* <td>23:59:59.999999999</td>
* </tr>
* <tr>
* <td>true</td>
* <td>-2562047:47:16.854775808</td>
* <td>2562047:47:16.854775807</td>
* </tr>
* </tbody>
* </table>
*/
public static final boolean UNLIMITED_TIME_RANGE =
Utils.getProperty("h2.unlimitedTimeRange", false);
/** /**
* System property <code>h2.pgClientEncoding</code> (default: UTF-8).<br /> * System property <code>h2.pgClientEncoding</code> (default: UTF-8).<br />
* Default client encoding for PG server. It is used if the client does not * Default client encoding for PG server. It is used if the client does not
......
...@@ -364,21 +364,17 @@ public class DateTimeUtils { ...@@ -364,21 +364,17 @@ public class DateTimeUtils {
} }
/** /**
* Parse a time string. The format is: [-]hour:minute:second[.nanos] or * Parse a time string. The format is: hour:minute:second[.nanos] or
* alternatively [-]hour.minute.second[.nanos]. * alternatively hour.minute.second[.nanos].
* *
* @param s the string to parse * @param s the string to parse
* @param start the parse index start * @param start the parse index start
* @param end the parse index end * @param end the parse index end
* @param timeOfDay whether the result need to be within 0 (inclusive) and 1
* day (exclusive)
* @return the time in nanoseconds * @return the time in nanoseconds
* @throws IllegalArgumentException if there is a problem * @throws IllegalArgumentException if there is a problem
*/ */
public static long parseTimeNanos(String s, int start, int end, public static long parseTimeNanos(String s, int start, int end) {
boolean timeOfDay) { int hour, minute, second, nanos;
int hour = 0, minute = 0, second = 0;
long nanos = 0;
int s1 = s.indexOf(':', start); int s1 = s.indexOf(':', start);
int s2 = s.indexOf(':', s1 + 1); int s2 = s.indexOf(':', s1 + 1);
int s3 = s.indexOf('.', s2 + 1); int s3 = s.indexOf('.', s2 + 1);
...@@ -388,41 +384,26 @@ public class DateTimeUtils { ...@@ -388,41 +384,26 @@ public class DateTimeUtils {
s1 = s.indexOf('.', start); s1 = s.indexOf('.', start);
s2 = s.indexOf('.', s1 + 1); s2 = s.indexOf('.', s1 + 1);
s3 = s.indexOf('.', s2 + 1); s3 = s.indexOf('.', s2 + 1);
if (s1 <= 0 || s2 <= s1) { if (s1 <= 0 || s2 <= s1) {
throw new IllegalArgumentException(s); throw new IllegalArgumentException(s);
} }
} }
boolean negative;
hour = Integer.parseInt(s.substring(start, s1)); hour = Integer.parseInt(s.substring(start, s1));
if (hour < 0 || hour == 0 && s.charAt(0) == '-') { if (hour < 0 || hour == 0 && s.charAt(0) == '-' || hour >= 24) {
if (timeOfDay) { throw new IllegalArgumentException(s);
/*
* This also forbids -00:00:00 and similar values.
*/
throw new IllegalArgumentException(s);
}
negative = true;
hour = -hour;
} else {
negative = false;
} }
minute = Integer.parseInt(s.substring(s1 + 1, s2)); minute = Integer.parseInt(s.substring(s1 + 1, s2));
if (s3 < 0) { if (s3 < 0) {
second = Integer.parseInt(s.substring(s2 + 1, end)); second = Integer.parseInt(s.substring(s2 + 1, end));
nanos = 0;
} else { } else {
second = Integer.parseInt(s.substring(s2 + 1, s3)); second = Integer.parseInt(s.substring(s2 + 1, s3));
nanos = parseNanos(s, s3 + 1, end); nanos = parseNanos(s, s3 + 1, end);
} }
if (hour >= 2_000_000 || minute < 0 || minute >= 60 || second < 0 if (minute < 0 || minute >= 60 || second < 0 || second >= 60) {
|| second >= 60) {
throw new IllegalArgumentException(s);
}
if (timeOfDay && hour >= 24) {
throw new IllegalArgumentException(s); throw new IllegalArgumentException(s);
} }
nanos += ((((hour * 60L) + minute) * 60) + second) * NANOS_PER_SECOND; return ((((hour * 60L) + minute) * 60) + second) * NANOS_PER_SECOND + nanos;
return negative ? -nanos : nanos;
} }
private static int parseNanos(String s, int start, int end) { private static int parseNanos(String s, int start, int end) {
...@@ -514,7 +495,7 @@ public class DateTimeUtils { ...@@ -514,7 +495,7 @@ public class DateTimeUtils {
} }
} }
} }
nanos = parseTimeNanos(s, dateEnd + 1, timeEnd, true); nanos = parseTimeNanos(s, dateEnd + 1, timeEnd);
if (tz != null) { if (tz != null) {
if (withTimeZone) { if (withTimeZone) {
if (tz != UTC) { if (tz != UTC) {
......
...@@ -9,7 +9,6 @@ import java.sql.PreparedStatement; ...@@ -9,7 +9,6 @@ import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Time; import java.sql.Time;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.SysProperties;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeUtils;
...@@ -69,13 +68,11 @@ public class ValueTime extends Value { ...@@ -69,13 +68,11 @@ public class ValueTime extends Value {
* @return the value * @return the value
*/ */
public static ValueTime fromNanos(long nanos) { public static ValueTime fromNanos(long nanos) {
if (!SysProperties.UNLIMITED_TIME_RANGE) { if (nanos < 0L || nanos >= DateTimeUtils.NANOS_PER_DAY) {
if (nanos < 0L || nanos >= DateTimeUtils.NANOS_PER_DAY) { StringBuilder builder = new StringBuilder();
StringBuilder builder = new StringBuilder(); DateTimeUtils.appendTime(builder, nanos);
DateTimeUtils.appendTime(builder, nanos); throw DbException.get(ErrorCode.INVALID_DATETIME_CONSTANT_2,
throw DbException.get(ErrorCode.INVALID_DATETIME_CONSTANT_2, "TIME", builder.toString());
"TIME", builder.toString());
}
} }
return (ValueTime) Value.cache(new ValueTime(nanos)); return (ValueTime) Value.cache(new ValueTime(nanos));
} }
...@@ -109,7 +106,7 @@ public class ValueTime extends Value { ...@@ -109,7 +106,7 @@ public class ValueTime extends Value {
*/ */
public static ValueTime parse(String s) { public static ValueTime parse(String s) {
try { try {
return fromNanos(DateTimeUtils.parseTimeNanos(s, 0, s.length(), false)); return fromNanos(DateTimeUtils.parseTimeNanos(s, 0, s.length()));
} catch (Exception e) { } catch (Exception e) {
throw DbException.get(ErrorCode.INVALID_DATETIME_CONSTANT_2, throw DbException.get(ErrorCode.INVALID_DATETIME_CONSTANT_2,
e, "TIME", s); e, "TIME", s);
......
...@@ -15,7 +15,6 @@ import java.util.GregorianCalendar; ...@@ -15,7 +15,6 @@ import java.util.GregorianCalendar;
import java.util.TimeZone; import java.util.TimeZone;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.engine.SysProperties;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.test.utils.AssertThrows; import org.h2.test.utils.AssertThrows;
...@@ -119,36 +118,17 @@ public class TestDate extends TestBase { ...@@ -119,36 +118,17 @@ public class TestDate extends TestBase {
assertEquals("00:00:00", ValueTime.fromNanos(0).getString()); assertEquals("00:00:00", ValueTime.fromNanos(0).getString());
assertEquals("23:59:59", ValueTime.parse("23:59:59").getString()); assertEquals("23:59:59", ValueTime.parse("23:59:59").getString());
assertEquals("11:22:33.444555666", ValueTime.parse("11:22:33.444555666").getString()); assertEquals("11:22:33.444555666", ValueTime.parse("11:22:33.444555666").getString());
if (SysProperties.UNLIMITED_TIME_RANGE) { try {
assertEquals("99:59:59", ValueTime.parse("99:59:59").getString()); ValueTime.parse("-00:00:00.000000001");
assertEquals("-00:10:10", ValueTime.parse("-00:10:10").getString()); fail();
assertEquals("-99:02:03.001002003", } catch (DbException ex) {
ValueTime.parse("-99:02:03.001002003").getString()); assertEquals(ErrorCode.INVALID_DATETIME_CONSTANT_2, ex.getErrorCode());
assertEquals("-99:02:03.001002", }
ValueTime.parse("-99:02:03.001002000").getString()); try {
assertEquals("-99:02:03", ValueTime.parse("24:00:00");
ValueTime.parse("-99:02:03.0000000000001").getString()); fail();
assertEquals("1999999:59:59.999999999", } catch (DbException ex) {
ValueTime.parse("1999999:59:59.999999999").getString()); assertEquals(ErrorCode.INVALID_DATETIME_CONSTANT_2, ex.getErrorCode());
assertEquals("-1999999:59:59.999999999",
ValueTime.parse("-1999999:59:59.999999999").getString());
assertEquals("2562047:47:16.854775807",
ValueTime.fromNanos(Long.MAX_VALUE).getString());
assertEquals("-2562047:47:16.854775808",
ValueTime.fromNanos(Long.MIN_VALUE).getString());
} else {
try {
ValueTime.parse("-00:00:00.000000001");
fail();
} catch (DbException ex) {
assertEquals(ErrorCode.INVALID_DATETIME_CONSTANT_2, ex.getErrorCode());
}
try {
ValueTime.parse("24:00:00");
fail();
} catch (DbException ex) {
assertEquals(ErrorCode.INVALID_DATETIME_CONSTANT_2, ex.getErrorCode());
}
} }
ValueTime t1 = ValueTime.parse("11:11:11"); ValueTime t1 = ValueTime.parse("11:11:11");
assertEquals("11:11:11", t1.getTime().toString()); assertEquals("11:11:11", t1.getTime().toString());
...@@ -182,24 +162,6 @@ public class TestDate extends TestBase { ...@@ -182,24 +162,6 @@ public class TestDate extends TestBase {
assertFalse(t2.equals(t1)); assertFalse(t2.equals(t1));
assertEquals(-1, t1.compareTo(t2, null, null)); assertEquals(-1, t1.compareTo(t2, null, null));
assertEquals(1, t2.compareTo(t1, null, null)); assertEquals(1, t2.compareTo(t1, null, null));
if (SysProperties.UNLIMITED_TIME_RANGE) {
assertEquals(-1, t1.negate().getSignum());
assertEquals("-11:11:11", t1.negate().getString());
assertEquals("11:11:11", t1.negate().negate().getString());
assertEquals("33:33:33", t1.add(t2).getString());
assertEquals("33:33:33", t1.multiply(ValueInt.get(4)).subtract(t1).getString());
// can't convert using java.util.Date
assertEquals(
"1969-12-31 23:00:00.0",
ValueTime.parse("-1:00:00").
convertTo(Value.TIMESTAMP).getString());
assertEquals(
"1970-01-01",
ValueTime.parse("-1:00:00").
convertTo(Value.DATE).getString());
}
} }
private void testValueTimestampWithTimezone() { private void testValueTimestampWithTimezone() {
...@@ -323,15 +285,6 @@ public class TestDate extends TestBase { ...@@ -323,15 +285,6 @@ public class TestDate extends TestBase {
ValueTimestamp.parse("-1010-10-10 10:10:10").subtract( ValueTimestamp.parse("-1010-10-10 10:10:10").subtract(
ValueTime.parse("10:10:10")).getString()); ValueTime.parse("10:10:10")).getString());
if (SysProperties.UNLIMITED_TIME_RANGE) {
assertEquals("2001-01-02 01:01:01",
ValueTimestamp.parse("2001-01-01").add(
ValueTime.parse("25:01:01")).getString());
assertEquals("1010-10-10 10:00:00",
ValueTimestamp.parse("1010-10-11 10:10:10").subtract(
ValueTime.parse("24:10:10")).getString());
}
assertEquals(0, DateTimeUtils.absoluteDayFromDateValue( assertEquals(0, DateTimeUtils.absoluteDayFromDateValue(
ValueTimestamp.parse("1970-01-01").getDateValue())); ValueTimestamp.parse("1970-01-01").getDateValue()));
assertEquals(0, ValueTimestamp.parse( assertEquals(0, ValueTimestamp.parse(
......
...@@ -53,11 +53,11 @@ public class TestDateTimeUtils extends TestBase { ...@@ -53,11 +53,11 @@ public class TestDateTimeUtils extends TestBase {
} }
private void testParseTimeNanosDB2Format() { private void testParseTimeNanosDB2Format() {
assertEquals(3723004000000L, DateTimeUtils.parseTimeNanos("01:02:03.004", 0, 12, true)); assertEquals(3723004000000L, DateTimeUtils.parseTimeNanos("01:02:03.004", 0, 12));
assertEquals(3723004000000L, DateTimeUtils.parseTimeNanos("01.02.03.004", 0, 12, true)); assertEquals(3723004000000L, DateTimeUtils.parseTimeNanos("01.02.03.004", 0, 12));
assertEquals(3723000000000L, DateTimeUtils.parseTimeNanos("01:02:03", 0, 8, true)); assertEquals(3723000000000L, DateTimeUtils.parseTimeNanos("01:02:03", 0, 8));
assertEquals(3723000000000L, DateTimeUtils.parseTimeNanos("01.02.03", 0, 8, true)); assertEquals(3723000000000L, DateTimeUtils.parseTimeNanos("01.02.03", 0, 8));
} }
/** /**
......
...@@ -5,14 +5,21 @@ ...@@ -5,14 +5,21 @@
*/ */
package org.h2.test.unit; package org.h2.test.unit;
import static org.h2.util.DateTimeUtils.NANOS_PER_SECOND;
import org.h2.api.Interval; import org.h2.api.Interval;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.util.StringUtils;
/** /**
* Test cases for Interval. * Test cases for Interval.
*/ */
public class TestInterval extends TestBase { public class TestInterval extends TestBase {
private static final long MAX = 999_999_999_999_999_999L;
private static final long MIN = -999_999_999_999_999_999L;
/** /**
* Run just this test. * Run just this test.
* *
...@@ -25,25 +32,585 @@ public class TestInterval extends TestBase { ...@@ -25,25 +32,585 @@ public class TestInterval extends TestBase {
@Override @Override
public void test() throws Exception { public void test() throws Exception {
Interval i; testOfYears();
i = Interval.ofYears(100); testOfMonths();
assertEquals(100, i.getYears()); testOfDays();
assertEquals("INTERVAL '100' YEAR", i.toString()); testOfHours();
i = Interval.ofMonths(100); testOfMinutes();
assertEquals(100, i.getMonths()); testOfSeconds();
assertEquals("INTERVAL '100' MONTH", i.toString()); testOfSeconds2();
i = Interval.ofDays(100); testOfNanos();
assertEquals(100, i.getDays()); testOfYearsMonths();
assertEquals("INTERVAL '100' DAY", i.toString()); testOfDaysHours();
i = Interval.ofHours(100); testOfDaysHoursMinutes();
assertEquals(100, i.getHours()); testOfDaysHoursMinutesSeconds();
assertEquals("INTERVAL '100' HOUR", i.toString()); testOfHoursMinutes();
i = Interval.ofMinutes(100); testOfHoursMinutesSeconds();
assertEquals(100, i.getMinutes()); testOfMinutesSeconds();
assertEquals("INTERVAL '100' MINUTE", i.toString()); }
i = Interval.ofNanos(100_123_456_789L);
assertEquals(100_123_456_789L, i.getNanos()); private void testOfYears() {
assertEquals("INTERVAL '100.123456789' SECOND", i.toString()); testOfYearsGood(0);
testOfYearsGood(100);
testOfYearsGood(-100);
testOfYearsGood(MAX);
testOfYearsGood(MIN);
testOfYearsBad(MAX + 1);
testOfYearsBad(MIN - 1);
testOfYearsBad(Long.MAX_VALUE);
testOfYearsBad(Long.MIN_VALUE);
}
private void testOfYearsGood(long years) {
Interval i = Interval.ofYears(years);
assertEquals(years, i.getYears());
assertEquals("INTERVAL '" + years + "' YEAR", i.toString());
}
private void testOfYearsBad(long years) {
try {
Interval.ofYears(years);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfMonths() {
testOfMonthsGood(0);
testOfMonthsGood(100);
testOfMonthsGood(-100);
testOfMonthsGood(MAX);
testOfMonthsGood(MIN);
testOfMonthsBad(MAX + 1);
testOfMonthsBad(MIN - 1);
testOfMonthsBad(Long.MAX_VALUE);
testOfMonthsBad(Long.MIN_VALUE);
}
private void testOfMonthsGood(long months) {
Interval i = Interval.ofMonths(months);
assertEquals(months, i.getMonths());
assertEquals("INTERVAL '" + months + "' MONTH", i.toString());
}
private void testOfMonthsBad(long months) {
try {
Interval.ofMonths(months);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfDays() {
testOfDaysGood(0);
testOfDaysGood(100);
testOfDaysGood(-100);
testOfDaysGood(MAX);
testOfDaysGood(MIN);
testOfDaysBad(MAX + 1);
testOfDaysBad(MIN - 1);
testOfDaysBad(Long.MAX_VALUE);
testOfDaysBad(Long.MIN_VALUE);
}
private void testOfDaysGood(long days) {
Interval i = Interval.ofDays(days);
assertEquals(days, i.getDays());
assertEquals("INTERVAL '" + days + "' DAY", i.toString());
}
private void testOfDaysBad(long days) {
try {
Interval.ofDays(days);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfHours() {
testOfHoursGood(0);
testOfHoursGood(100);
testOfHoursGood(-100);
testOfHoursGood(MAX);
testOfHoursGood(MIN);
testOfHoursBad(MAX + 1);
testOfHoursBad(MIN - 1);
testOfHoursBad(Long.MAX_VALUE);
testOfHoursBad(Long.MIN_VALUE);
}
private void testOfHoursGood(long hours) {
Interval i = Interval.ofHours(hours);
assertEquals(hours, i.getHours());
assertEquals("INTERVAL '" + hours + "' HOUR", i.toString());
}
private void testOfHoursBad(long hours) {
try {
Interval.ofHours(hours);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfMinutes() {
testOfMinutesGood(0);
testOfMinutesGood(100);
testOfMinutesGood(-100);
testOfMinutesGood(MAX);
testOfMinutesGood(MIN);
testOfMinutesBad(MAX + 1);
testOfMinutesBad(MIN - 1);
testOfMinutesBad(Long.MAX_VALUE);
testOfMinutesBad(Long.MIN_VALUE);
}
private void testOfMinutesGood(long minutes) {
Interval i = Interval.ofMinutes(minutes);
assertEquals(minutes, i.getMinutes());
assertEquals("INTERVAL '" + minutes + "' MINUTE", i.toString());
}
private void testOfMinutesBad(long minutes) {
try {
Interval.ofMinutes(minutes);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfSeconds() {
testOfSecondsGood(0);
testOfSecondsGood(100);
testOfSecondsGood(-100);
testOfSecondsGood(MAX);
testOfSecondsGood(MIN);
testOfSecondsBad(MAX + 1);
testOfSecondsBad(MIN - 1);
testOfSecondsBad(Long.MAX_VALUE);
testOfSecondsBad(Long.MIN_VALUE);
}
private void testOfSecondsGood(long seconds) {
Interval i = Interval.ofSeconds(seconds);
assertEquals(seconds, i.getSeconds());
assertEquals("INTERVAL '" + seconds + "' SECOND", i.toString());
}
private void testOfSecondsBad(long seconds) {
try {
Interval.ofSeconds(seconds);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfSeconds2() {
testOfSeconds2Good(0, 0);
testOfSeconds2Good(0, -2);
testOfSeconds2Good(100, 5);
testOfSeconds2Good(-100, -1);
testOfSeconds2Good(MAX, 999_999_999);
testOfSeconds2Good(MIN, -999_999_999);
testOfSeconds2Bad(0, 1_000_000_000);
testOfSeconds2Bad(0, -1_000_000_000);
testOfSeconds2Bad(MAX + 1, 0);
testOfSeconds2Bad(MIN - 1, 0);
testOfSeconds2Bad(Long.MAX_VALUE, 0);
testOfSeconds2Bad(Long.MIN_VALUE, 0);
testOfSeconds2Bad(0, Integer.MAX_VALUE);
testOfSeconds2Bad(0, Integer.MIN_VALUE);
}
private void testOfSeconds2Good(long seconds, int nanos) {
Interval i = Interval.ofSeconds(seconds, nanos);
assertEquals(seconds, i.getSeconds());
assertEquals(nanos, i.getNanosOfSecond());
if (Math.abs(seconds) < 9_000_000_000L) {
assertEquals(seconds * NANOS_PER_SECOND + nanos, i.getSecondsAndNanos());
}
StringBuilder b = new StringBuilder("INTERVAL '");
if (seconds < 0 || nanos < 0) {
b.append('-');
}
b.append(Math.abs(seconds));
if (nanos != 0) {
b.append('.');
StringUtils.appendZeroPadded(b, 9, Math.abs(nanos));
stripTrailingZeroes(b);
}
b.append("' SECOND");
assertEquals(b.toString(), i.toString());
}
private void testOfSeconds2Bad(long seconds, int nanos) {
try {
Interval.ofSeconds(seconds, nanos);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfNanos() {
testOfNanosGood(0);
testOfNanosGood(100);
testOfNanosGood(-100);
testOfNanosGood(Long.MAX_VALUE);
testOfNanosGood(Long.MIN_VALUE);
}
private void testOfNanosGood(long nanos) {
Interval i = Interval.ofNanos(nanos);
long seconds = nanos / NANOS_PER_SECOND;
long nanosOfSecond = nanos % NANOS_PER_SECOND;
assertEquals(seconds, i.getSeconds());
assertEquals(nanosOfSecond, i.getNanosOfSecond());
assertEquals(nanos, i.getSecondsAndNanos());
StringBuilder b = new StringBuilder("INTERVAL '");
if (nanos < 0) {
b.append('-');
}
b.append(Math.abs(seconds));
if (nanosOfSecond != 0) {
b.append('.');
StringUtils.appendZeroPadded(b, 9, Math.abs(nanosOfSecond));
stripTrailingZeroes(b);
}
b.append("' SECOND");
assertEquals(b.toString(), i.toString());
}
private void testOfYearsMonths() {
testOfYearsMonthsGood(0, 0);
testOfYearsMonthsGood(0, -2);
testOfYearsMonthsGood(100, 5);
testOfYearsMonthsGood(-100, -1);
testOfYearsMonthsGood(MAX, 11);
testOfYearsMonthsGood(MIN, -11);
testOfYearsMonthsBad(0, 12);
testOfYearsMonthsBad(0, -12);
testOfYearsMonthsBad(MAX + 1, 0);
testOfYearsMonthsBad(MIN - 1, 0);
testOfYearsMonthsBad(Long.MAX_VALUE, 0);
testOfYearsMonthsBad(Long.MIN_VALUE, 0);
testOfYearsMonthsBad(0, Integer.MAX_VALUE);
testOfYearsMonthsBad(0, Integer.MIN_VALUE);
}
private void testOfYearsMonthsGood(long years, int months) {
Interval i = Interval.ofYearsMonths(years, months);
assertEquals(years, i.getYears());
assertEquals(months, i.getMonths());
StringBuilder b = new StringBuilder("INTERVAL '");
if (years < 0 || months < 0) {
b.append('-');
}
b.append(Math.abs(years)).append('-').append(Math.abs(months)).append("' YEAR TO MONTH");
assertEquals(b.toString(), i.toString());
}
private void testOfYearsMonthsBad(long years, int months) {
try {
Interval.ofYearsMonths(years, months);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfDaysHours() {
testOfDaysHoursGood(0, 0);
testOfDaysHoursGood(0, -2);
testOfDaysHoursGood(100, 5);
testOfDaysHoursGood(-100, -1);
testOfDaysHoursGood(MAX, 23);
testOfDaysHoursGood(MIN, -23);
testOfDaysHoursBad(0, 24);
testOfDaysHoursBad(0, -24);
testOfDaysHoursBad(MAX + 1, 0);
testOfDaysHoursBad(MIN - 1, 0);
testOfDaysHoursBad(Long.MAX_VALUE, 0);
testOfDaysHoursBad(Long.MIN_VALUE, 0);
testOfDaysHoursBad(0, Integer.MAX_VALUE);
testOfDaysHoursBad(0, Integer.MIN_VALUE);
}
private void testOfDaysHoursGood(long days, int hours) {
Interval i = Interval.ofDaysHours(days, hours);
assertEquals(days, i.getDays());
assertEquals(hours, i.getHours());
StringBuilder b = new StringBuilder("INTERVAL '");
if (days < 0 || hours < 0) {
b.append('-');
}
b.append(Math.abs(days)).append(' ');
StringUtils.appendZeroPadded(b, 2, Math.abs(hours));
b.append("' DAY TO HOUR");
assertEquals(b.toString(), i.toString());
}
private void testOfDaysHoursBad(long days, int hours) {
try {
Interval.ofDaysHours(days, hours);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfDaysHoursMinutes() {
testOfDaysHoursMinutesGood(0, 0, 0);
testOfDaysHoursMinutesGood(0, -2, 0);
testOfDaysHoursMinutesGood(0, 0, -2);
testOfDaysHoursMinutesGood(100, 5, 3);
testOfDaysHoursMinutesGood(-100, -1, -3);
testOfDaysHoursMinutesGood(MAX, 23, 59);
testOfDaysHoursMinutesGood(MIN, -23, -59);
testOfDaysHoursMinutesBad(0, 24, 0);
testOfDaysHoursMinutesBad(0, -24, 0);
testOfDaysHoursMinutesBad(0, 0, 60);
testOfDaysHoursMinutesBad(0, 0, -60);
testOfDaysHoursMinutesBad(MAX + 1, 0, 0);
testOfDaysHoursMinutesBad(MIN - 1, 0, 0);
testOfDaysHoursMinutesBad(Long.MAX_VALUE, 0, 0);
testOfDaysHoursMinutesBad(Long.MIN_VALUE, 0, 0);
testOfDaysHoursMinutesBad(0, Integer.MAX_VALUE, 0);
testOfDaysHoursMinutesBad(0, Integer.MIN_VALUE, 0);
testOfDaysHoursMinutesBad(0, 0, Integer.MAX_VALUE);
testOfDaysHoursMinutesBad(0, 0, Integer.MIN_VALUE);
}
private void testOfDaysHoursMinutesGood(long days, int hours, int minutes) {
Interval i = Interval.ofDaysHoursMinutes(days, hours, minutes);
assertEquals(days, i.getDays());
assertEquals(hours, i.getHours());
assertEquals(minutes, i.getMinutes());
StringBuilder b = new StringBuilder("INTERVAL '");
if (days < 0 || hours < 0 || minutes < 0) {
b.append('-');
}
b.append(Math.abs(days)).append(' ');
StringUtils.appendZeroPadded(b, 2, Math.abs(hours));
b.append(':');
StringUtils.appendZeroPadded(b, 2, Math.abs(minutes));
b.append("' DAY TO MINUTE");
assertEquals(b.toString(), i.toString());
}
private void testOfDaysHoursMinutesBad(long days, int hours, int minutes) {
try {
Interval.ofDaysHoursMinutes(days, hours, minutes);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfDaysHoursMinutesSeconds() {
testOfDaysHoursMinutesSecondsGood(0, 0, 0, 0);
testOfDaysHoursMinutesSecondsGood(0, -2, 0, 0);
testOfDaysHoursMinutesSecondsGood(0, 0, -2, 0);
testOfDaysHoursMinutesSecondsGood(0, 0, 0, -2);
testOfDaysHoursMinutesSecondsGood(100, 5, 3, 4);
testOfDaysHoursMinutesSecondsGood(-100, -1, -3, -4);
testOfDaysHoursMinutesSecondsGood(MAX, 23, 59, 59);
testOfDaysHoursMinutesSecondsGood(MIN, -23, -59, -59);
testOfDaysHoursMinutesSecondsBad(0, 24, 0, 0);
testOfDaysHoursMinutesSecondsBad(0, -24, 0, 0);
testOfDaysHoursMinutesSecondsBad(0, 0, 60, 0);
testOfDaysHoursMinutesSecondsBad(0, 0, -60, 0);
testOfDaysHoursMinutesSecondsBad(0, 0, 0, 60);
testOfDaysHoursMinutesSecondsBad(0, 0, 0, -60);
testOfDaysHoursMinutesSecondsBad(MAX + 1, 0, 0, 0);
testOfDaysHoursMinutesSecondsBad(MIN - 1, 0, 0, 0);
testOfDaysHoursMinutesSecondsBad(Long.MAX_VALUE, 0, 0, 0);
testOfDaysHoursMinutesSecondsBad(Long.MIN_VALUE, 0, 0, 0);
testOfDaysHoursMinutesSecondsBad(0, Integer.MAX_VALUE, 0, 0);
testOfDaysHoursMinutesSecondsBad(0, Integer.MIN_VALUE, 0, 0);
testOfDaysHoursMinutesSecondsBad(0, 0, Integer.MAX_VALUE, 0);
testOfDaysHoursMinutesSecondsBad(0, 0, Integer.MIN_VALUE, 0);
testOfDaysHoursMinutesSecondsBad(0, 0, 0, Integer.MAX_VALUE);
testOfDaysHoursMinutesSecondsBad(0, 0, 0, Integer.MIN_VALUE);
}
private void testOfDaysHoursMinutesSecondsGood(long days, int hours, int minutes, int seconds) {
Interval i = Interval.ofDaysHoursMinutesSeconds(days, hours, minutes, seconds);
assertEquals(days, i.getDays());
assertEquals(hours, i.getHours());
assertEquals(minutes, i.getMinutes());
assertEquals(seconds, i.getSeconds());
assertEquals(0, i.getNanosOfSecond());
assertEquals(seconds * NANOS_PER_SECOND, i.getSecondsAndNanos());
StringBuilder b = new StringBuilder("INTERVAL '");
if (days < 0 || hours < 0 || minutes < 0 || seconds < 0) {
b.append('-');
}
b.append(Math.abs(days)).append(' ');
StringUtils.appendZeroPadded(b, 2, Math.abs(hours));
b.append(':');
StringUtils.appendZeroPadded(b, 2, Math.abs(minutes));
b.append(':');
StringUtils.appendZeroPadded(b, 2, Math.abs(seconds));
b.append("' DAY TO SECOND");
assertEquals(b.toString(), i.toString());
}
private void testOfDaysHoursMinutesSecondsBad(long days, int hours, int minutes, int seconds) {
try {
Interval.ofDaysHoursMinutesSeconds(days, hours, minutes, seconds);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfHoursMinutes() {
testOfHoursMinutesGood(0, 0);
testOfHoursMinutesGood(0, -2);
testOfHoursMinutesGood(100, 5);
testOfHoursMinutesGood(-100, -1);
testOfHoursMinutesGood(MAX, 59);
testOfHoursMinutesGood(MIN, -59);
testOfHoursMinutesBad(0, 60);
testOfHoursMinutesBad(0, -60);
testOfHoursMinutesBad(MAX + 1, 0);
testOfHoursMinutesBad(MIN - 1, 0);
testOfHoursMinutesBad(Long.MAX_VALUE, 0);
testOfHoursMinutesBad(Long.MIN_VALUE, 0);
testOfHoursMinutesBad(0, Integer.MAX_VALUE);
testOfHoursMinutesBad(0, Integer.MIN_VALUE);
}
private void testOfHoursMinutesGood(long hours, int minutes) {
Interval i = Interval.ofHoursMinutes(hours, minutes);
assertEquals(hours, i.getHours());
assertEquals(minutes, i.getMinutes());
StringBuilder b = new StringBuilder("INTERVAL '");
if (hours < 0 || minutes < 0) {
b.append('-');
}
b.append(Math.abs(hours)).append(':');
StringUtils.appendZeroPadded(b, 2, Math.abs(minutes));
b.append("' HOUR TO MINUTE");
assertEquals(b.toString(), i.toString());
}
private void testOfHoursMinutesBad(long hours, int minutes) {
try {
Interval.ofHoursMinutes(hours, minutes);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfHoursMinutesSeconds() {
testOfHoursMinutesSecondsGood(0, 0, 0);
testOfHoursMinutesSecondsGood(0, -2, 0);
testOfHoursMinutesSecondsGood(0, 0, -2);
testOfHoursMinutesSecondsGood(100, 5, 3);
testOfHoursMinutesSecondsGood(-100, -1, -3);
testOfHoursMinutesSecondsGood(MAX, 59, 59);
testOfHoursMinutesSecondsGood(MIN, -59, -59);
testOfHoursMinutesSecondsBad(0, 60, 0);
testOfHoursMinutesSecondsBad(0, -60, 0);
testOfHoursMinutesSecondsBad(0, 0, 60);
testOfHoursMinutesSecondsBad(0, 0, -60);
testOfHoursMinutesSecondsBad(MAX + 1, 0, 0);
testOfHoursMinutesSecondsBad(MIN - 1, 0, 0);
testOfHoursMinutesSecondsBad(Long.MAX_VALUE, 0, 0);
testOfHoursMinutesSecondsBad(Long.MIN_VALUE, 0, 0);
testOfHoursMinutesSecondsBad(0, Integer.MAX_VALUE, 0);
testOfHoursMinutesSecondsBad(0, Integer.MIN_VALUE, 0);
testOfHoursMinutesSecondsBad(0, 0, Integer.MAX_VALUE);
testOfHoursMinutesSecondsBad(0, 0, Integer.MIN_VALUE);
}
private void testOfHoursMinutesSecondsGood(long hours, int minutes, int seconds) {
Interval i = Interval.ofHoursMinutesSeconds(hours, minutes, seconds);
assertEquals(hours, i.getHours());
assertEquals(minutes, i.getMinutes());
assertEquals(seconds, i.getSeconds());
assertEquals(0, i.getNanosOfSecond());
assertEquals(seconds * NANOS_PER_SECOND, i.getSecondsAndNanos());
StringBuilder b = new StringBuilder("INTERVAL '");
if (hours < 0 || minutes < 0 || seconds < 0) {
b.append('-');
}
b.append(Math.abs(hours)).append(':');
StringUtils.appendZeroPadded(b, 2, Math.abs(minutes));
b.append(':');
StringUtils.appendZeroPadded(b, 2, Math.abs(seconds));
b.append("' HOUR TO SECOND");
assertEquals(b.toString(), i.toString());
}
private void testOfHoursMinutesSecondsBad(long hours, int minutes, int seconds) {
try {
Interval.ofHoursMinutesSeconds(hours, minutes, seconds);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private void testOfMinutesSeconds() {
testOfMinutesSecondsGood(0, 0);
testOfMinutesSecondsGood(0, -2);
testOfMinutesSecondsGood(100, 5);
testOfMinutesSecondsGood(-100, -1);
testOfMinutesSecondsGood(MAX, 59);
testOfMinutesSecondsGood(MIN, -59);
testOfMinutesSecondsBad(0, 60);
testOfMinutesSecondsBad(0, -60);
testOfMinutesSecondsBad(MAX + 1, 0);
testOfMinutesSecondsBad(MIN - 1, 0);
testOfMinutesSecondsBad(Long.MAX_VALUE, 0);
testOfMinutesSecondsBad(Long.MIN_VALUE, 0);
testOfMinutesSecondsBad(0, Integer.MAX_VALUE);
testOfMinutesSecondsBad(0, Integer.MIN_VALUE);
}
private void testOfMinutesSecondsGood(long minutes, int seconds) {
Interval i = Interval.ofMinutesSeconds(minutes, seconds);
assertEquals(minutes, i.getMinutes());
assertEquals(seconds, i.getSeconds());
assertEquals(0, i.getNanosOfSecond());
assertEquals(seconds * NANOS_PER_SECOND, i.getSecondsAndNanos());
StringBuilder b = new StringBuilder("INTERVAL '");
if (minutes < 0 || seconds < 0) {
b.append('-');
}
b.append(Math.abs(minutes)).append(':');
StringUtils.appendZeroPadded(b, 2, Math.abs(seconds));
b.append("' MINUTE TO SECOND");
assertEquals(b.toString(), i.toString());
}
private void testOfMinutesSecondsBad(long minutes, int seconds) {
try {
Interval.ofMinutesSeconds(minutes, seconds);
fail();
} catch (IllegalArgumentException e) {
// OK
}
}
private static void stripTrailingZeroes(StringBuilder b) {
int i = b.length() - 1;
if (b.charAt(i) == '0') {
while (b.charAt(--i) == '0') {
// do nothing
}
b.setLength(i + 1);
}
} }
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论