提交 43fbbf1e authored 作者: Thomas Mueller's avatar Thomas Mueller

Date, time, and timestamp data type processing has been re-implemented.

上级 891cef2f
...@@ -350,8 +350,8 @@ public class SysProperties { ...@@ -350,8 +350,8 @@ public class SysProperties {
/** /**
* System property <code>h2.storeLocalTime</code> (default: false).<br /> * System property <code>h2.storeLocalTime</code> (default: false).<br />
* Store the local time in milliseconds since 1970 in the database file. If * Store the local time. If disabled, the daylight saving offset is not
* disabled, the daylight saving offset is not taken into account. * taken into account.
*/ */
public static final boolean STORE_LOCAL_TIME = Utils.getProperty("h2.storeLocalTime", false); public static final boolean STORE_LOCAL_TIME = Utils.getProperty("h2.storeLocalTime", false);
......
...@@ -471,7 +471,12 @@ public class Data { ...@@ -471,7 +471,12 @@ public class Data {
case Value.TIME: case Value.TIME:
if (SysProperties.STORE_LOCAL_TIME) { if (SysProperties.STORE_LOCAL_TIME) {
writeByte((byte) LOCAL_TIME); writeByte((byte) LOCAL_TIME);
writeVarLong(((ValueTime) v).getNanos()); ValueTime t = (ValueTime) v;
long nanos = t.getNanos();
long millis = nanos / 1000000;
nanos -= millis * 1000000;
writeVarLong(millis);
writeVarLong(nanos);
} else { } else {
writeByte((byte) type); writeByte((byte) type);
writeVarLong(DateTimeUtils.getTimeLocalWithoutDst(v.getTime())); writeVarLong(DateTimeUtils.getTimeLocalWithoutDst(v.getTime()));
...@@ -494,8 +499,11 @@ public class Data { ...@@ -494,8 +499,11 @@ public class Data {
writeByte((byte) LOCAL_TIMESTAMP); writeByte((byte) LOCAL_TIMESTAMP);
ValueTimestamp ts = (ValueTimestamp) v; ValueTimestamp ts = (ValueTimestamp) v;
long dateValue = ts.getDateValue(); long dateValue = ts.getDateValue();
long nanos = ts.getNanos();
writeVarLong(dateValue); writeVarLong(dateValue);
long nanos = ts.getNanos();
long millis = nanos / 1000000;
nanos -= millis * 1000000;
writeVarLong(millis);
writeVarLong(nanos); writeVarLong(nanos);
} else { } else {
Timestamp ts = v.getTimestamp(); Timestamp ts = v.getTimestamp();
...@@ -683,21 +691,23 @@ public class Data { ...@@ -683,21 +691,23 @@ public class Data {
return ValueDecimal.get(new BigDecimal(b, scale)); return ValueDecimal.get(new BigDecimal(b, scale));
} }
case LOCAL_DATE: { case LOCAL_DATE: {
return ValueDate.get(readVarLong()); return ValueDate.fromDateValue(readVarLong());
} }
case Value.DATE: { case Value.DATE: {
long x = readVarLong() * MILLIS_PER_MINUTE; long x = readVarLong() * MILLIS_PER_MINUTE;
return ValueDate.get(new Date(DateTimeUtils.getTimeUTCWithoutDst(x))); return ValueDate.get(new Date(DateTimeUtils.getTimeUTCWithoutDst(x)));
} }
case LOCAL_TIME: case LOCAL_TIME: {
return ValueTime.get(readVarLong()); long nanos = readVarLong() * 1000000 + readVarLong();
return ValueTime.fromNanos(nanos);
}
case Value.TIME: case Value.TIME:
// need to normalize the year, month and day // need to normalize the year, month and day
return ValueTime.get(new Time(DateTimeUtils.getTimeUTCWithoutDst(readVarLong()))); return ValueTime.get(new Time(DateTimeUtils.getTimeUTCWithoutDst(readVarLong())));
case LOCAL_TIMESTAMP: { case LOCAL_TIMESTAMP: {
long dateValue = readVarLong(); long dateValue = readVarLong();
long nanos = readVarLong(); long nanos = readVarLong() * 1000000 + readVarLong();
return ValueTimestamp.get(dateValue, nanos); return ValueTimestamp.fromDateValueAndNanos(dateValue, nanos);
} }
case Value.TIMESTAMP: { case Value.TIMESTAMP: {
Timestamp ts = new Timestamp(DateTimeUtils.getTimeUTCWithoutDst(readVarLong())); Timestamp ts = new Timestamp(DateTimeUtils.getTimeUTCWithoutDst(readVarLong()));
...@@ -895,7 +905,10 @@ public class Data { ...@@ -895,7 +905,10 @@ public class Data {
} }
case Value.TIME: case Value.TIME:
if (SysProperties.STORE_LOCAL_TIME) { if (SysProperties.STORE_LOCAL_TIME) {
return 1 + getVarLongLen(((ValueTime) v).getNanos()); long nanos = ((ValueTime) v).getNanos();
long millis = nanos / 1000000;
nanos -= millis * 1000000;
return 1 + getVarLongLen(millis) + getVarLongLen(nanos);
} }
return 1 + getVarLongLen(DateTimeUtils.getTimeLocalWithoutDst(v.getTime())); return 1 + getVarLongLen(DateTimeUtils.getTimeLocalWithoutDst(v.getTime()));
case Value.DATE: { case Value.DATE: {
...@@ -911,7 +924,9 @@ public class Data { ...@@ -911,7 +924,9 @@ public class Data {
ValueTimestamp ts = (ValueTimestamp) v; ValueTimestamp ts = (ValueTimestamp) v;
long dateValue = ts.getDateValue(); long dateValue = ts.getDateValue();
long nanos = ts.getNanos(); long nanos = ts.getNanos();
return 1 + getVarLongLen(dateValue) + getVarLongLen(nanos); long millis = nanos / 1000000;
nanos -= millis * 1000000;
return 1 + getVarLongLen(dateValue) + getVarLongLen(millis) + getVarLongLen(nanos);
} }
Timestamp ts = v.getTimestamp(); Timestamp ts = v.getTimestamp();
return 1 + getVarLongLen(DateTimeUtils.getTimeLocalWithoutDst(ts)) + getVarIntLen(ts.getNanos()); return 1 + getVarLongLen(DateTimeUtils.getTimeLocalWithoutDst(ts)) + getVarIntLen(ts.getNanos());
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
*/ */
package org.h2.table; package org.h2.table;
import java.sql.Date;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import org.h2.command.Parser; import org.h2.command.Parser;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
...@@ -27,6 +27,7 @@ import org.h2.util.MathUtils; ...@@ -27,6 +27,7 @@ import org.h2.util.MathUtils;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueDate;
import org.h2.value.ValueInt; import org.h2.value.ValueInt;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
...@@ -284,15 +285,11 @@ public class Column { ...@@ -284,15 +285,11 @@ public class Column {
if (dt.decimal) { if (dt.decimal) {
value = ValueInt.get(0).convertTo(type); value = ValueInt.get(0).convertTo(type);
} else if (dt.type == Value.TIMESTAMP) { } else if (dt.type == Value.TIMESTAMP) {
// TODO value = ValueTimestamp.get(new Timestamp(session.getTransactionStart()));
value = ValueTimestamp.get(new Timestamp(System.currentTimeMillis()));
} else if (dt.type == Value.TIME) { } else if (dt.type == Value.TIME) {
// TODO value = ValueTime.fromNanos(0);
// need to normalize
value = ValueTime.get(Time.valueOf("0:0:0"));
} else if (dt.type == Value.DATE) { } else if (dt.type == Value.DATE) {
// TODO value = ValueDate.get(new Date(session.getTransactionStart()));
value = ValueTimestamp.get(new Timestamp(System.currentTimeMillis())).convertTo(dt.type);
} else { } else {
value = ValueString.get("").convertTo(type); value = ValueString.get("").convertTo(type);
} }
......
...@@ -626,7 +626,7 @@ public class DateTimeUtils { ...@@ -626,7 +626,7 @@ public class DateTimeUtils {
nanos -= d * NANOS_PER_DAY; nanos -= d * NANOS_PER_DAY;
absoluteDay += d; absoluteDay += d;
} }
return ValueTimestamp.get(dateValueFromAbsoluteDay(absoluteDay), nanos); return ValueTimestamp.fromDateValueAndNanos(dateValueFromAbsoluteDay(absoluteDay), nanos);
} }
public static long absoluteDayFromDateValue(long dateValue) { public static long absoluteDayFromDateValue(long dateValue) {
......
...@@ -471,21 +471,21 @@ public class Transfer { ...@@ -471,21 +471,21 @@ public class Transfer {
return ValueByte.get(readByte()); return ValueByte.get(readByte());
case Value.DATE: case Value.DATE:
if (version >= Constants.TCP_PROTOCOL_VERSION_9) { if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
return ValueDate.get(readLong()); return ValueDate.fromDateValue(readLong());
} else if (version >= Constants.TCP_PROTOCOL_VERSION_7) { } else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
return ValueDate.get(new Date(DateTimeUtils.getTimeUTCWithoutDst(readLong()))); return ValueDate.get(new Date(DateTimeUtils.getTimeUTCWithoutDst(readLong())));
} }
return ValueDate.get(new Date(readLong())); return ValueDate.get(new Date(readLong()));
case Value.TIME: case Value.TIME:
if (version >= Constants.TCP_PROTOCOL_VERSION_9) { if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
return ValueTime.get(readLong()); return ValueTime.fromNanos(readLong());
} else if (version >= Constants.TCP_PROTOCOL_VERSION_7) { } else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
return ValueTime.get(new Time(DateTimeUtils.getTimeUTCWithoutDst(readLong()))); return ValueTime.get(new Time(DateTimeUtils.getTimeUTCWithoutDst(readLong())));
} }
return ValueTime.get(new Time(readLong())); return ValueTime.get(new Time(readLong()));
case Value.TIMESTAMP: { case Value.TIMESTAMP: {
if (version >= Constants.TCP_PROTOCOL_VERSION_9) { if (version >= Constants.TCP_PROTOCOL_VERSION_9) {
return ValueTimestamp.get(readLong(), readLong()); return ValueTimestamp.fromDateValueAndNanos(readLong(), readLong());
} else if (version >= Constants.TCP_PROTOCOL_VERSION_7) { } else if (version >= Constants.TCP_PROTOCOL_VERSION_7) {
Timestamp ts = new Timestamp(DateTimeUtils.getTimeUTCWithoutDst(readLong())); Timestamp ts = new Timestamp(DateTimeUtils.getTimeUTCWithoutDst(readLong()));
ts.setNanos(readInt()); ts.setNanos(readInt());
......
...@@ -684,9 +684,9 @@ public abstract class Value { ...@@ -684,9 +684,9 @@ public abstract class Value {
case TIME: case TIME:
// because the time has set the date to 1970-01-01, // because the time has set the date to 1970-01-01,
// this will be the result // this will be the result
return ValueDate.get(DateTimeUtils.dateValue(1970, 1, 1)); return ValueDate.fromDateValue(DateTimeUtils.dateValue(1970, 1, 1));
case TIMESTAMP: case TIMESTAMP:
return ValueDate.get(((ValueTimestamp) this).getDateValue()); return ValueDate.fromDateValue(((ValueTimestamp) this).getDateValue());
} }
break; break;
} }
...@@ -695,9 +695,9 @@ public abstract class Value { ...@@ -695,9 +695,9 @@ public abstract class Value {
case DATE: case DATE:
// need to normalize the year, month and day // need to normalize the year, month and day
// because a date has the time set to 0, the result will be 0 // because a date has the time set to 0, the result will be 0
return ValueTime.get(0); return ValueTime.fromNanos(0);
case TIMESTAMP: case TIMESTAMP:
return ValueTime.get(((ValueTimestamp) this).getNanos()); return ValueTime.fromNanos(((ValueTimestamp) this).getNanos());
} }
break; break;
} }
...@@ -706,7 +706,7 @@ public abstract class Value { ...@@ -706,7 +706,7 @@ public abstract class Value {
case TIME: case TIME:
return DateTimeUtils.normalizeTimestamp(0, ((ValueTime) this).getNanos()); return DateTimeUtils.normalizeTimestamp(0, ((ValueTime) this).getNanos());
case DATE: case DATE:
return ValueTimestamp.get(((ValueDate) this).getDateValue(), 0); return ValueTimestamp.fromDateValueAndNanos(((ValueDate) this).getDateValue(), 0);
} }
break; break;
} }
......
...@@ -37,6 +37,26 @@ public class ValueDate extends Value { ...@@ -37,6 +37,26 @@ public class ValueDate extends Value {
this.dateValue = dateValue; this.dateValue = dateValue;
} }
/**
* Get or create a date value for the given date.
*
* @param dateValue the date value
* @return the value
*/
public static ValueDate fromDateValue(long dateValue) {
return (ValueDate) Value.cache(new ValueDate(dateValue));
}
/**
* Get or create a date value for the given date.
*
* @param date the date
* @return the value
*/
public static ValueDate get(Date date) {
return fromDateValue(DateTimeUtils.dateValueFromDate(date.getTime()));
}
/** /**
* Parse a string to a ValueDate. * Parse a string to a ValueDate.
* *
...@@ -45,84 +65,64 @@ public class ValueDate extends Value { ...@@ -45,84 +65,64 @@ public class ValueDate extends Value {
*/ */
public static ValueDate parse(String s) { public static ValueDate parse(String s) {
try { try {
return get(DateTimeUtils.parseDateValue(s, 0, s.length())); return fromDateValue(DateTimeUtils.parseDateValue(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, "DATE", s); e, "DATE", s);
} }
} }
public Date getDate() {
return DateTimeUtils.convertDateValueToDate(dateValue);
}
public long getDateValue() { public long getDateValue() {
return dateValue; return dateValue;
} }
public String getSQL() { public Date getDate() {
return "DATE '" + getString() + "'"; return DateTimeUtils.convertDateValueToDate(dateValue);
} }
public int getType() { public int getType() {
return Value.DATE; return Value.DATE;
} }
protected int compareSecure(Value o, CompareMode mode) {
return MathUtils.compareLong(dateValue, ((ValueDate) o).dateValue);
}
public String getString() { public String getString() {
StringBuilder buff = new StringBuilder(DISPLAY_SIZE); StringBuilder buff = new StringBuilder(DISPLAY_SIZE);
appendDate(buff, dateValue); appendDate(buff, dateValue);
return buff.toString(); return buff.toString();
} }
public String getSQL() {
return "DATE '" + getString() + "'";
}
public long getPrecision() { public long getPrecision() {
return PRECISION; return PRECISION;
} }
public int hashCode() { public int getDisplaySize() {
return (int) (dateValue ^ (dateValue >>> 32)); return DISPLAY_SIZE;
} }
public Object getObject() { protected int compareSecure(Value o, CompareMode mode) {
return getDate(); return MathUtils.compareLong(dateValue, ((ValueDate) o).dateValue);
} }
public void set(PreparedStatement prep, int parameterIndex) throws SQLException { public boolean equals(Object other) {
prep.setDate(parameterIndex, getDate()); if (this == other) {
return true;
} }
return other instanceof ValueDate && dateValue == (((ValueDate) other).dateValue);
/**
* Get or create a date value for the given date.
*
* @param date the date
* @return the value
*/
public static ValueDate get(Date date) {
return get(DateTimeUtils.dateValueFromDate(date.getTime()));
} }
/** public int hashCode() {
* Get or create a date value for the given date. return (int) (dateValue ^ (dateValue >>> 32));
*
* @param dateValue the date value
* @return the value
*/
public static ValueDate get(long dateValue) {
return (ValueDate) Value.cache(new ValueDate(dateValue));
} }
public int getDisplaySize() { public Object getObject() {
return DISPLAY_SIZE; return getDate();
} }
public boolean equals(Object other) { public void set(PreparedStatement prep, int parameterIndex) throws SQLException {
if (this == other) { prep.setDate(parameterIndex, getDate());
return true;
}
return other instanceof ValueDate && dateValue == (((ValueDate) other).dateValue);
} }
static void appendDate(StringBuilder buff, long dateValue) { static void appendDate(StringBuilder buff, long dateValue) {
......
...@@ -37,6 +37,26 @@ public class ValueTime extends Value { ...@@ -37,6 +37,26 @@ public class ValueTime extends Value {
this.nanos = nanos; this.nanos = nanos;
} }
/**
* Get or create a time value.
*
* @param nanos the nanoseconds
* @return the value
*/
public static ValueTime fromNanos(long nanos) {
return (ValueTime) Value.cache(new ValueTime(nanos));
}
/**
* Get or create a time value for the given time.
*
* @param time the time
* @return the value
*/
public static ValueTime get(Time time) {
return fromNanos(DateTimeUtils.nanosFromDate(time.getTime()));
}
/** /**
* Parse a string to a ValueTime. * Parse a string to a ValueTime.
* *
...@@ -46,102 +66,82 @@ public class ValueTime extends Value { ...@@ -46,102 +66,82 @@ public class ValueTime extends Value {
public static ValueTime parse(String s) { public static ValueTime parse(String s) {
try { try {
return get(DateTimeUtils.parseTimeNanos(s, 0, s.length(), false)); return fromNanos(DateTimeUtils.parseTimeNanos(s, 0, s.length(), false));
} 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);
} }
} }
public Time getTime() {
return DateTimeUtils.convertNanoToTime(nanos);
}
public long getNanos() { public long getNanos() {
return nanos; return nanos;
} }
public String getSQL() { public Time getTime() {
return "TIME '" + getString() + "'"; return DateTimeUtils.convertNanoToTime(nanos);
} }
public int getType() { public int getType() {
return Value.TIME; return Value.TIME;
} }
protected int compareSecure(Value o, CompareMode mode) {
return MathUtils.compareLong(nanos, ((ValueTime) o).nanos);
}
public String getString() { public String getString() {
StringBuilder buff = new StringBuilder(DISPLAY_SIZE); StringBuilder buff = new StringBuilder(DISPLAY_SIZE);
appendTime(buff, nanos, false); appendTime(buff, nanos, false);
return buff.toString(); return buff.toString();
} }
public String getSQL() {
return "TIME '" + getString() + "'";
}
public long getPrecision() { public long getPrecision() {
return PRECISION; return PRECISION;
} }
public int hashCode() { public int getDisplaySize() {
return (int) (nanos ^ (nanos >>> 32)); return DISPLAY_SIZE;
} }
public Object getObject() { protected int compareSecure(Value o, CompareMode mode) {
return getTime(); return MathUtils.compareLong(nanos, ((ValueTime) o).nanos);
} }
public void set(PreparedStatement prep, int parameterIndex) throws SQLException { public boolean equals(Object other) {
prep.setTime(parameterIndex, getTime()); if (this == other) {
return true;
} }
return other instanceof ValueTime && nanos == (((ValueTime) other).nanos);
/**
* Get or create a time value for the given time.
*
* @param time the time
* @return the value
*/
public static ValueTime get(Time time) {
return get(DateTimeUtils.nanosFromDate(time.getTime()));
} }
/** public int hashCode() {
* Get or create a time value. return (int) (nanos ^ (nanos >>> 32));
*
* @param nanos the nanoseconds
* @return the value
*/
public static ValueTime get(long nanos) {
return (ValueTime) Value.cache(new ValueTime(nanos));
} }
public int getDisplaySize() { public Object getObject() {
return DISPLAY_SIZE; return getTime();
} }
public boolean equals(Object other) { public void set(PreparedStatement prep, int parameterIndex) throws SQLException {
if (this == other) { prep.setTime(parameterIndex, getTime());
return true;
}
return other instanceof ValueTime && nanos == (((ValueTime) other).nanos);
} }
public Value add(Value v) { public Value add(Value v) {
ValueTime t = (ValueTime) v.convertTo(Value.TIME); ValueTime t = (ValueTime) v.convertTo(Value.TIME);
return ValueTime.get(nanos + t.getNanos()); return ValueTime.fromNanos(nanos + t.getNanos());
} }
public Value subtract(Value v) { public Value subtract(Value v) {
ValueTime t = (ValueTime) v.convertTo(Value.TIME); ValueTime t = (ValueTime) v.convertTo(Value.TIME);
return ValueTime.get(nanos - t.getNanos()); return ValueTime.fromNanos(nanos - t.getNanos());
} }
public Value multiply(Value v) { public Value multiply(Value v) {
return ValueTime.get((long) (nanos * v.getDouble())); return ValueTime.fromNanos((long) (nanos * v.getDouble()));
} }
public Value divide(Value v) { public Value divide(Value v) {
return ValueTime.get((long) (nanos / v.getDouble())); return ValueTime.fromNanos((long) (nanos / v.getDouble()));
} }
public int getSignum() { public int getSignum() {
...@@ -149,7 +149,7 @@ public class ValueTime extends Value { ...@@ -149,7 +149,7 @@ public class ValueTime extends Value {
} }
public Value negate() { public Value negate() {
return ValueTime.get(-nanos); return ValueTime.fromNanos(-nanos);
} }
static void appendTime(StringBuilder buff, long n, boolean alwaysAddMillis) { static void appendTime(StringBuilder buff, long n, boolean alwaysAddMillis) {
......
...@@ -47,22 +47,6 @@ public class ValueTimestamp extends Value { ...@@ -47,22 +47,6 @@ public class ValueTimestamp extends Value {
this.nanos = nanos; this.nanos = nanos;
} }
public Timestamp getTimestamp() {
return DateTimeUtils.convertDateValueToTimestamp(dateValue, nanos);
}
public long getDateValue() {
return dateValue;
}
public long getNanos() {
return nanos;
}
public String getSQL() {
return "TIMESTAMP '" + getString() + "'";
}
/** /**
* Get or create a date value for the given date. * Get or create a date value for the given date.
* *
...@@ -70,10 +54,24 @@ public class ValueTimestamp extends Value { ...@@ -70,10 +54,24 @@ public class ValueTimestamp extends Value {
* @param nanos the nanoseconds * @param nanos the nanoseconds
* @return the value * @return the value
*/ */
public static ValueTimestamp get(long dateValue, long nanos) { public static ValueTimestamp fromDateValueAndNanos(long dateValue, long nanos) {
return (ValueTimestamp) Value.cache(new ValueTimestamp(dateValue, nanos)); return (ValueTimestamp) Value.cache(new ValueTimestamp(dateValue, nanos));
} }
/**
* Get or create a timestamp value for the given timestamp.
*
* @param timestamp the timestamp
* @return the value
*/
public static ValueTimestamp get(Timestamp timestamp) {
long ms = timestamp.getTime();
long dateValue = DateTimeUtils.dateValueFromDate(ms);
long nanos = DateTimeUtils.nanosFromDate(ms);
nanos += timestamp.getNanos() % 1000000;
return fromDateValueAndNanos(dateValue, nanos);
}
/** /**
* Parse a string to a ValueTimestamp. This method supports the format * Parse a string to a ValueTimestamp. This method supports the format
* +/-year-month-day hour:minute:seconds.fractional and an optional timezone * +/-year-month-day hour:minute:seconds.fractional and an optional timezone
...@@ -93,7 +91,7 @@ public class ValueTimestamp extends Value { ...@@ -93,7 +91,7 @@ public class ValueTimestamp extends Value {
private static ValueTimestamp parseTry(String s) { private static ValueTimestamp parseTry(String s) {
int dateEnd = s.indexOf(' '); int dateEnd = s.indexOf(' ');
if (dateEnd <= 0) { if (dateEnd < 0) {
// ISO 8601 compatibility // ISO 8601 compatibility
dateEnd = s.indexOf('T'); dateEnd = s.indexOf('T');
} }
...@@ -114,9 +112,6 @@ public class ValueTimestamp extends Value { ...@@ -114,9 +112,6 @@ public class ValueTimestamp extends Value {
if (s.endsWith("Z")) { if (s.endsWith("Z")) {
tz = TimeZone.getTimeZone("UTC"); tz = TimeZone.getTimeZone("UTC");
timeEnd--; timeEnd--;
while (s.charAt(timeEnd - 1) == ' ') {
timeEnd--;
}
} else { } else {
int timeZoneStart = s.indexOf('+', dateEnd); int timeZoneStart = s.indexOf('+', dateEnd);
if (timeZoneStart < 0) { if (timeZoneStart < 0) {
...@@ -129,8 +124,15 @@ public class ValueTimestamp extends Value { ...@@ -129,8 +124,15 @@ public class ValueTimestamp extends Value {
throw new IllegalArgumentException(tzName); throw new IllegalArgumentException(tzName);
} }
timeEnd = timeZoneStart; timeEnd = timeZoneStart;
while (s.charAt(timeEnd - 1) == ' ') { } else {
timeEnd--; timeZoneStart = s.indexOf(' ', dateEnd + 1);
if (timeZoneStart > 0) {
String tzName = s.substring(timeZoneStart + 1);
tz = TimeZone.getTimeZone(tzName);
if (!tz.getID().startsWith(tzName)) {
throw new IllegalArgumentException(tzName);
}
timeEnd = timeZoneStart;
} }
} }
} }
...@@ -153,24 +155,26 @@ public class ValueTimestamp extends Value { ...@@ -153,24 +155,26 @@ public class ValueTimestamp extends Value {
nanos += (ms - DateTimeUtils.absoluteDayFromDateValue(dateValue) * DateTimeUtils.MILLIS_PER_DAY) * 1000000; nanos += (ms - DateTimeUtils.absoluteDayFromDateValue(dateValue) * DateTimeUtils.MILLIS_PER_DAY) * 1000000;
} }
} }
return ValueTimestamp.get(dateValue, nanos); return ValueTimestamp.fromDateValueAndNanos(dateValue, nanos);
} }
public int getType() { public long getDateValue() {
return Value.TIMESTAMP; return dateValue;
} }
protected int compareSecure(Value o, CompareMode mode) { public long getNanos() {
ValueTimestamp t = (ValueTimestamp) o; return nanos;
int c = MathUtils.compareLong(dateValue, t.dateValue);
if (c != 0) {
return c;
} }
return MathUtils.compareLong(nanos, t.nanos);
public Timestamp getTimestamp() {
return DateTimeUtils.convertDateValueToTimestamp(dateValue, nanos);
}
public int getType() {
return Value.TIMESTAMP;
} }
public String getString() { public String getString() {
// TODO verify display size
StringBuilder buff = new StringBuilder(DISPLAY_SIZE); StringBuilder buff = new StringBuilder(DISPLAY_SIZE);
ValueDate.appendDate(buff, dateValue); ValueDate.appendDate(buff, dateValue);
buff.append(' '); buff.append(' ');
...@@ -178,6 +182,10 @@ public class ValueTimestamp extends Value { ...@@ -178,6 +182,10 @@ public class ValueTimestamp extends Value {
return buff.toString(); return buff.toString();
} }
public String getSQL() {
return "TIMESTAMP '" + getString() + "'";
}
public long getPrecision() { public long getPrecision() {
return PRECISION; return PRECISION;
} }
...@@ -186,30 +194,8 @@ public class ValueTimestamp extends Value { ...@@ -186,30 +194,8 @@ public class ValueTimestamp extends Value {
return DEFAULT_SCALE; return DEFAULT_SCALE;
} }
public int hashCode() { public int getDisplaySize() {
return (int) (dateValue ^ (dateValue >>> 32) ^ nanos ^ (nanos >>> 32)); return DISPLAY_SIZE;
}
public Object getObject() {
return getTimestamp();
}
public void set(PreparedStatement prep, int parameterIndex) throws SQLException {
prep.setTimestamp(parameterIndex, getTimestamp());
}
/**
* Get or create a timestamp value for the given timestamp.
*
* @param timestamp the timestamp
* @return the value
*/
public static ValueTimestamp get(Timestamp timestamp) {
long ms = timestamp.getTime();
long dateValue = DateTimeUtils.dateValueFromDate(ms);
long nanos = DateTimeUtils.nanosFromDate(ms);
nanos += timestamp.getNanos() % 1000000;
return get(dateValue, nanos);
} }
public Value convertScale(boolean onlyToSmallerScale, int targetScale) { public Value convertScale(boolean onlyToSmallerScale, int targetScale) {
...@@ -228,11 +214,16 @@ public class ValueTimestamp extends Value { ...@@ -228,11 +214,16 @@ public class ValueTimestamp extends Value {
if (n2 == n) { if (n2 == n) {
return this; return this;
} }
return get(dateValue, n2); return fromDateValueAndNanos(dateValue, n2);
} }
public int getDisplaySize() { protected int compareSecure(Value o, CompareMode mode) {
return DISPLAY_SIZE; ValueTimestamp t = (ValueTimestamp) o;
int c = MathUtils.compareLong(dateValue, t.dateValue);
if (c != 0) {
return c;
}
return MathUtils.compareLong(nanos, t.nanos);
} }
public boolean equals(Object other) { public boolean equals(Object other) {
...@@ -245,8 +236,19 @@ public class ValueTimestamp extends Value { ...@@ -245,8 +236,19 @@ public class ValueTimestamp extends Value {
return dateValue == x.dateValue && nanos == x.nanos; return dateValue == x.dateValue && nanos == x.nanos;
} }
public int hashCode() {
return (int) (dateValue ^ (dateValue >>> 32) ^ nanos ^ (nanos >>> 32));
}
public Object getObject() {
return getTimestamp();
}
public void set(PreparedStatement prep, int parameterIndex) throws SQLException {
prep.setTimestamp(parameterIndex, getTimestamp());
}
public Value add(Value v) { public Value add(Value v) {
// TODO test sum of timestamps, dates, times
ValueTimestamp t = (ValueTimestamp) v.convertTo(Value.TIMESTAMP); ValueTimestamp t = (ValueTimestamp) v.convertTo(Value.TIMESTAMP);
long d1 = DateTimeUtils.absoluteDayFromDateValue(dateValue); long d1 = DateTimeUtils.absoluteDayFromDateValue(dateValue);
long d2 = DateTimeUtils.absoluteDayFromDateValue(t.dateValue); long d2 = DateTimeUtils.absoluteDayFromDateValue(t.dateValue);
...@@ -254,7 +256,6 @@ public class ValueTimestamp extends Value { ...@@ -254,7 +256,6 @@ public class ValueTimestamp extends Value {
} }
public Value subtract(Value v) { public Value subtract(Value v) {
// TODO test sum of timestamps, dates, times
ValueTimestamp t = (ValueTimestamp) v.convertTo(Value.TIMESTAMP); ValueTimestamp t = (ValueTimestamp) v.convertTo(Value.TIMESTAMP);
long d1 = DateTimeUtils.absoluteDayFromDateValue(dateValue); long d1 = DateTimeUtils.absoluteDayFromDateValue(dateValue);
long d2 = DateTimeUtils.absoluteDayFromDateValue(t.dateValue); long d2 = DateTimeUtils.absoluteDayFromDateValue(t.dateValue);
......
...@@ -42,7 +42,6 @@ public class TestDateStorage extends TestBase { ...@@ -42,7 +42,6 @@ public class TestDateStorage extends TestBase {
testCurrentTimeZone(); testCurrentTimeZone();
} }
private void testMoveDatabaseToAnotherTimezone() throws SQLException { private void testMoveDatabaseToAnotherTimezone() throws SQLException {
if (config.memory) { if (config.memory) {
return; return;
......
...@@ -385,7 +385,7 @@ select count(scriptSimple.public.test.id) from scriptSimple.public.test; ...@@ -385,7 +385,7 @@ select count(scriptSimple.public.test.id) from scriptSimple.public.test;
update scriptSimple.public.test set scriptSimple.public.test.id=1; update scriptSimple.public.test set scriptSimple.public.test.id=1;
drop table scriptSimple.public.test; drop table scriptSimple.public.test;
select year(timestamp '2007-07-26 18:44:26.109000 +02:00'); select year(timestamp '2007-07-26T18:44:26.109000+02:00');
> 2007; > 2007;
create table test(id int primary key); create table test(id int primary key);
......
...@@ -15,11 +15,11 @@ import java.util.Calendar; ...@@ -15,11 +15,11 @@ import java.util.Calendar;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.TimeZone; import java.util.TimeZone;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.message.DbException;
import org.h2.store.Data; import org.h2.store.Data;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.util.DateTimeUtils; import org.h2.util.DateTimeUtils;
import org.h2.util.New; import org.h2.util.New;
import org.h2.util.Profiler;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueDate; import org.h2.value.ValueDate;
import org.h2.value.ValueDouble; import org.h2.value.ValueDouble;
...@@ -48,24 +48,19 @@ public class TestDate extends TestBase { ...@@ -48,24 +48,19 @@ public class TestDate extends TestBase {
} }
public void test() throws SQLException { public void test() throws SQLException {
int test;
//Profiler prof = new Profiler();
//prof.startCollecting();
testValueDate(); testValueDate();
testValueTime(); testValueTime();
testValueTimestamp(); testValueTimestamp();
testValidDate(); testValidDate();
testAbsoluteDay(); testAbsoluteDay();
testCalculateLocalMillis(); testCalculateLocalMillis();
testTimeOperationsAcrossTimeZones(); testTimeOperationsAcrossTimeZones();
testDateTimeUtils(); testDateTimeUtils();
//System.out.println(prof.getTop(5));
} }
private void testValueDate() { private void testValueDate() {
assertEquals("2000-01-01", ValueDate.get(Date.valueOf("2000-01-01")).getString()); assertEquals("2000-01-01", ValueDate.get(Date.valueOf("2000-01-01")).getString());
assertEquals("0-00-00", ValueDate.get(0).getString()); assertEquals("0-00-00", ValueDate.fromDateValue(0).getString());
assertEquals("9999-12-31", ValueDate.parse("9999-12-31").getString()); assertEquals("9999-12-31", ValueDate.parse("9999-12-31").getString());
assertEquals("-9999-12-31", ValueDate.parse("-9999-12-31").getString()); assertEquals("-9999-12-31", ValueDate.parse("-9999-12-31").getString());
assertEquals( assertEquals(
...@@ -121,7 +116,7 @@ int test; ...@@ -121,7 +116,7 @@ int test;
private void testValueTime() { private void testValueTime() {
assertEquals("10:20:30", ValueTime.get(Time.valueOf("10:20:30")).getString()); assertEquals("10:20:30", ValueTime.get(Time.valueOf("10:20:30")).getString());
assertEquals("00:00:00", ValueTime.get(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("99:59:59", ValueTime.parse("99:59:59").getString()); assertEquals("99:59:59", ValueTime.parse("99:59:59").getString());
assertEquals("-99:02:03.001002003", ValueTime.parse("-99:02:03.001002003").getString()); assertEquals("-99:02:03.001002003", ValueTime.parse("-99:02:03.001002003").getString());
...@@ -184,7 +179,7 @@ int test; ...@@ -184,7 +179,7 @@ int test;
Timestamp.valueOf("2001-02-03 04:05:06")).getString()); Timestamp.valueOf("2001-02-03 04:05:06")).getString());
assertEquals("2001-02-03 04:05:06.001002003", ValueTimestamp.get( assertEquals("2001-02-03 04:05:06.001002003", ValueTimestamp.get(
Timestamp.valueOf("2001-02-03 04:05:06.001002003")).getString()); Timestamp.valueOf("2001-02-03 04:05:06.001002003")).getString());
assertEquals("0-00-00 00:00:00.0", ValueTimestamp.get(0, 0).getString()); assertEquals("0-00-00 00:00:00.0", ValueTimestamp.fromDateValueAndNanos(0, 0).getString());
assertEquals("9999-12-31 23:59:59.0", assertEquals("9999-12-31 23:59:59.0",
ValueTimestamp.parse("9999-12-31 23:59:59").getString()); ValueTimestamp.parse("9999-12-31 23:59:59").getString());
...@@ -262,6 +257,25 @@ int test; ...@@ -262,6 +257,25 @@ int test;
assertEquals("-1010-10-10 00:00:00.0", assertEquals("-1010-10-10 00:00:00.0",
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());
assertEquals(0, DateTimeUtils.absoluteDayFromDateValue(ValueTimestamp.parse("1970-01-01").getDateValue()));
assertEquals(0, ValueTimestamp.parse("1970-01-01").getNanos());
assertEquals(0, ValueTimestamp.parse("1970-01-01 00:00:00.000 UTC").getTimestamp().getTime());
assertEquals(0, ValueTimestamp.parse("+1970-01-01T00:00:00.000Z").getTimestamp().getTime());
assertEquals(0, ValueTimestamp.parse("1970-01-01T00:00:00.000+00:00").getTimestamp().getTime());
assertEquals(0, ValueTimestamp.parse("1970-01-01T00:00:00.000-00:00").getTimestamp().getTime());
try {
ValueTimestamp.parse("1970-01-01 00:00:00.000 ABC");
fail();
} catch (DbException e) {
// expected
}
try {
ValueTimestamp.parse("1970-01-01T00:00:00.000+ABC");
fail();
} catch (DbException e) {
// expected
}
} }
private void testAbsoluteDay() { private void testAbsoluteDay() {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论