Unverified 提交 01d01c39 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #893 from katzyn/datetime

TIMESTAMP WITHOUT TIME ZONE, TIMEZONE_HOUR, and TIMEZONE_MINUTE
......@@ -2309,7 +2309,7 @@ TIME '23:59:59'
"
"Other Grammar","Timestamp","
TIMESTAMP 'yyyy-MM-dd hh:mm:ss[.nnnnnnnnn]'
TIMESTAMP [ WITHOUT TIME ZONE ] 'yyyy-MM-dd hh:mm:ss[.nnnnnnnnn]'
","
A timestamp literal. The limitations are the same as for the Java data type
""java.sql.Timestamp"", but for compatibility with other databases the suggested
......@@ -2319,7 +2319,7 @@ TIMESTAMP '2005-12-31 23:59:59'
"
"Other Grammar","Timestamp with time zone","
TIMESTAMP 'yyyy-MM-dd hh:mm:ss[.nnnnnnnnn]
TIMESTAMP WITH TIME ZONE 'yyyy-MM-dd hh:mm:ss[.nnnnnnnnn]
[Z | { - | + } timeZoneOffsetString | timeZoneNameString ]'
","
A timestamp with time zone literal.
......@@ -2459,7 +2459,7 @@ DATE
"
"Data Types","TIMESTAMP Type","
{ TIMESTAMP | DATETIME | SMALLDATETIME }
{ TIMESTAMP [ WITHOUT TIME ZONE ] | DATETIME | SMALLDATETIME }
","
The timestamp data type. The format is yyyy-MM-dd hh:mm:ss[.nnnnnnnnn].
Stored internally as a BCD-encoded date, and nanoseconds since midnight.
......@@ -3697,6 +3697,7 @@ The same units as in the EXTRACT function are supported.
This method returns a value with the same type as specified value if unit is compatible with this value.
If specified unit is a HOUR, MINUTE, SECOND, MILLISECOND, etc and value is a DATE value DATEADD returns combined TIMESTAMP.
Units DAY, MONTH, YEAR, WEEK, etc are not allowed for TIME values.
Units TIMEZONE_HOUR and TIMEZONE_MINUTE are only allowed for TIMESTAMP WITH TIME ZONE values.
","
DATEADD('MONTH', 1, DATE '2001-01-31')
"
......@@ -3708,7 +3709,8 @@ Returns the the number of crossed unit boundaries between two timestamps.
This method returns a long.
The string indicates the unit.
The same units as in the EXTRACT function are supported.
If timestamps have time zone offset component it is ignored.
Only TIMEZONE_HOUR and TIMEZONE_MINUTE units use the time zone offset component.
With all other units if timestamps have time zone offset component it is ignored.
","
DATEDIFF('YEAR', T1.CREATED, T2.CREATED)
"
......@@ -3749,7 +3751,8 @@ DAY_OF_YEAR(CREATED)
EXTRACT ( { YEAR | YY | MONTH | MM | QUARTER | WEEK | ISO_WEEK
| DAY | DD | DAY_OF_YEAR | DOY
| HOUR | HH | MINUTE | MI | SECOND | SS | EPOCH
| MILLISECOND | MS | MICROSECOND | MCS | NANOSECOND | NS }
| MILLISECOND | MS | MICROSECOND | MCS | NANOSECOND | NS
| TIMEZONE_HOUR | TIMEZONE_MINUTE }
FROM timestamp )
","
Returns a specific value from a timestamps.
......
......@@ -3137,17 +3137,30 @@ public class Parser {
read("FOR");
Sequence sequence = readSequence();
r = new SequenceValue(sequence);
} else if (equalsToken("TIMESTAMP", name) && readIf("WITH")) {
read("TIME");
read("ZONE");
if (currentTokenType != VALUE
|| currentValue.getType() != Value.STRING) {
throw getSyntaxError();
} else if (equalsToken("TIMESTAMP", name)) {
if (readIf("WITH")) {
read("TIME");
read("ZONE");
if (currentTokenType != VALUE
|| currentValue.getType() != Value.STRING) {
throw getSyntaxError();
}
String timestamp = currentValue.getString();
read();
r = ValueExpression.get(ValueTimestampTimeZone.parse(timestamp));
} else {
if (readIf("WITHOUT")) {
read("TIME");
read("ZONE");
}
if (currentTokenType != VALUE
|| currentValue.getType() != Value.STRING) {
throw getSyntaxError();
}
String timestamp = currentValue.getString();
read();
r = ValueExpression.get(ValueTimestamp.parse(timestamp, database.getMode()));
}
String timestamp = currentValue.getString();
read();
r = ValueExpression
.get(ValueTimestampTimeZone.parse(timestamp));
} else if (currentTokenType == VALUE &&
currentValue.getType() == Value.STRING) {
if (equalsToken("DATE", name) ||
......@@ -3160,8 +3173,7 @@ public class Parser {
String time = currentValue.getString();
read();
r = ValueExpression.get(ValueTime.parse(time));
} else if (equalsToken("TIMESTAMP", name) ||
equalsToken("TS", name)) {
} else if (equalsToken("TS", name)) {
String timestamp = currentValue.getString();
read();
r = ValueExpression
......@@ -4340,6 +4352,10 @@ public class Parser {
read("ZONE");
original += " WITH TIME ZONE";
}
} else if (readIf("WITHOUT")) {
read("TIME");
read("ZONE");
original += " WITHOUT TIME ZONE";
}
} else {
regular = true;
......
......@@ -112,7 +112,8 @@ public class Function extends Expression implements FunctionCall {
/**
* Pseudo functions for DATEADD, DATEDIFF, and EXTRACT.
*/
public static final int MILLISECOND = 126, EPOCH = 127, MICROSECOND = 128, NANOSECOND = 129;
public static final int MILLISECOND = 126, EPOCH = 127, MICROSECOND = 128, NANOSECOND = 129,
TIMEZONE_HOUR = 130, TIMEZONE_MINUTE = 131;
public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152,
IDENTITY = 153, SCOPE_IDENTITY = 154, AUTOCOMMIT = 155,
......@@ -209,6 +210,8 @@ public class Function extends Expression implements FunctionCall {
DATE_PART.put("MCS", MICROSECOND);
DATE_PART.put("NANOSECOND", NANOSECOND);
DATE_PART.put("NS", NANOSECOND);
DATE_PART.put("TIMEZONE_HOUR", TIMEZONE_HOUR);
DATE_PART.put("TIMEZONE_MINUTE", TIMEZONE_MINUTE);
// SOUNDEX_INDEX
String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R";
......@@ -1921,6 +1924,16 @@ public class Function extends Expression implements FunctionCall {
break;
case NANOSECOND:
break;
case TIMEZONE_HOUR:
count *= 60;
//$FALL-THROUGH$
case TIMEZONE_MINUTE: {
if (!(v instanceof ValueTimestampTimeZone)) {
throw DbException.getUnsupportedException("DATEADD " + part);
}
count += ((ValueTimestampTimeZone) v).getTimeZoneOffsetMins();
return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, timeNanos, (short) count);
}
default:
throw DbException.getUnsupportedException("DATEADD " + part);
}
......@@ -2013,6 +2026,26 @@ public class Function extends Expression implements FunctionCall {
- (DateTimeUtils.monthFromDateValue(dateValue1) - 1) / 3;
case YEAR:
return DateTimeUtils.yearFromDateValue(dateValue2) - DateTimeUtils.yearFromDateValue(dateValue1);
case TIMEZONE_HOUR:
case TIMEZONE_MINUTE: {
int offsetMinutes1;
if (v1 instanceof ValueTimestampTimeZone) {
offsetMinutes1 = ((ValueTimestampTimeZone) v1).getTimeZoneOffsetMins();
} else {
offsetMinutes1 = DateTimeUtils.getTimeZoneOffsetMillis(null, dateValue1, a1[1]);
}
int offsetMinutes2;
if (v2 instanceof ValueTimestampTimeZone) {
offsetMinutes2 = ((ValueTimestampTimeZone) v2).getTimeZoneOffsetMins();
} else {
offsetMinutes2 = DateTimeUtils.getTimeZoneOffsetMillis(null, dateValue2, a2[1]);
}
if (field == TIMEZONE_HOUR) {
return (offsetMinutes2 / 60) - (offsetMinutes1 / 60);
} else {
return offsetMinutes2 - offsetMinutes1;
}
}
default:
throw DbException.getUnsupportedException("DATEDIFF " + part);
}
......@@ -2886,39 +2919,52 @@ public class Function extends Expression implements FunctionCall {
long dateValue = a[0];
long timeNanos = a[1];
switch (field) {
case Function.YEAR:
case YEAR:
return DateTimeUtils.yearFromDateValue(dateValue);
case Function.MONTH:
case MONTH:
return DateTimeUtils.monthFromDateValue(dateValue);
case Function.DAY_OF_MONTH:
case DAY_OF_MONTH:
return DateTimeUtils.dayFromDateValue(dateValue);
case Function.HOUR:
case HOUR:
return (int) (timeNanos / 3_600_000_000_000L % 24);
case Function.MINUTE:
case MINUTE:
return (int) (timeNanos / 60_000_000_000L % 60);
case Function.SECOND:
case SECOND:
return (int) (timeNanos / 1_000_000_000 % 60);
case Function.MILLISECOND:
case MILLISECOND:
return (int) (timeNanos / 1_000_000 % 1_000);
case Function.MICROSECOND:
case MICROSECOND:
return (int) (timeNanos / 1_000 % 1_000_000);
case Function.NANOSECOND:
case NANOSECOND:
return (int) (timeNanos % 1_000_000_000);
case Function.DAY_OF_YEAR:
case DAY_OF_YEAR:
return DateTimeUtils.getDayOfYear(dateValue);
case Function.DAY_OF_WEEK:
case DAY_OF_WEEK:
return DateTimeUtils.getSundayDayOfWeek(dateValue);
case Function.WEEK:
case WEEK:
GregorianCalendar gc = DateTimeUtils.getCalendar();
return DateTimeUtils.getWeekOfYear(dateValue, gc.getFirstDayOfWeek() - 1, gc.getMinimalDaysInFirstWeek());
case Function.QUARTER:
case QUARTER:
return (DateTimeUtils.monthFromDateValue(dateValue) - 1) / 3 + 1;
case Function.ISO_YEAR:
case ISO_YEAR:
return DateTimeUtils.getIsoWeekYear(dateValue);
case Function.ISO_WEEK:
case ISO_WEEK:
return DateTimeUtils.getIsoWeekOfYear(dateValue);
case Function.ISO_DAY_OF_WEEK:
case ISO_DAY_OF_WEEK:
return DateTimeUtils.getIsoDayOfWeek(dateValue);
case TIMEZONE_HOUR:
case TIMEZONE_MINUTE: {
int offsetMinutes;
if (date instanceof ValueTimestampTimeZone) {
offsetMinutes = ((ValueTimestampTimeZone) date).getTimeZoneOffsetMins();
} else {
offsetMinutes = DateTimeUtils.getTimeZoneOffsetMillis(null, dateValue, timeNanos);
}
if (field == TIMEZONE_HOUR) {
return offsetMinutes / 60;
}
return offsetMinutes % 60;
}
}
throw DbException.getUnsupportedException("getDatePart(" + date + ", " + field + ')');
}
......
......@@ -302,7 +302,8 @@ public class DataType {
add(Value.TIMESTAMP, Types.TIMESTAMP, "Timestamp",
createDate(ValueTimestamp.PRECISION, "TIMESTAMP",
ValueTimestamp.DEFAULT_SCALE, ValueTimestamp.DISPLAY_SIZE),
new String[]{"TIMESTAMP", "DATETIME", "DATETIME2", "SMALLDATETIME"},
new String[]{"TIMESTAMP", "TIMESTAMP WITHOUT TIME ZONE",
"DATETIME", "DATETIME2", "SMALLDATETIME"},
// 24 for ValueTimestamp, 32 for java.sql.Timestamp
56
);
......
......@@ -2,3 +2,26 @@
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
CREATE TABLE TEST(T1 TIMESTAMP, T2 TIMESTAMP WITHOUT TIME ZONE);
> ok
INSERT INTO TEST(T1, T2) VALUES (TIMESTAMP '2010-01-01 10:00:00', TIMESTAMP WITHOUT TIME ZONE '2010-01-01 10:00:00');
> update count: 1
SELECT T1, T2, T1 = T2 FROM TEST;
> T1 T2 T1 = T2
> --------------------- --------------------- -------
> 2010-01-01 10:00:00.0 2010-01-01 10:00:00.0 TRUE
> rows: 1
SELECT COLUMN_NAME, DATA_TYPE, TYPE_NAME, COLUMN_TYPE FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'TEST' ORDER BY ORDINAL_POSITION;
> COLUMN_NAME DATA_TYPE TYPE_NAME COLUMN_TYPE
> ----------- --------- --------- ---------------------------
> T1 93 TIMESTAMP TIMESTAMP
> T2 93 TIMESTAMP TIMESTAMP WITHOUT TIME ZONE
> rows (ordered): 2
DROP TABLE TEST;
> ok
......@@ -149,3 +149,15 @@ SELECT TIMESTAMPADD('DAY', 10, TIMESTAMP '2000-01-05 15:00:30.123456789');
> -----------------------------------------
> 2000-01-15 15:00:30.123456789
> rows: 1
SELECT TIMESTAMPADD('TIMEZONE_HOUR', 1, TIMESTAMP WITH TIME ZONE '2010-01-01 10:00:00+07:30') AS T;
> T
> ---------------------------
> 2010-01-01 10:00:00.0+08:30
> rows: 1
SELECT TIMESTAMPADD('TIMEZONE_MINUTE', -45, TIMESTAMP WITH TIME ZONE '2010-01-01 10:00:00+07:30') AS T;
> T
> ---------------------------
> 2010-01-01 10:00:00.0+06:45
> rows: 1
......@@ -241,3 +241,17 @@ SELECT DATEDIFF('QUARTER', DATE '-1000-01-01', DATE '2000-01-01');
> -----
> 12000
> rows: 1
SELECT DATEDIFF('TIMEZONE_HOUR', TIMESTAMP WITH TIME ZONE '2010-01-01 10:00:00+01',
TIMESTAMP WITH TIME ZONE '2012-02-02 12:00:00+02');
> 1
> -
> 1
> rows: 1
SELECT DATEDIFF('TIMEZONE_MINUTE', TIMESTAMP WITH TIME ZONE '2010-01-01 10:00:00+01:15',
TIMESTAMP WITH TIME ZONE '2012-02-02 12:00:00+02');
> 45
> --
> 45
> rows: 1
......@@ -55,3 +55,27 @@ select EXTRACT (EPOCH from timestamp with time zone '2000-01-03 12:00:00.123456+
select extract(EPOCH from '2001-02-03 14:15:16');
> 981209716
SELECT EXTRACT(TIMEZONE_HOUR FROM TIMESTAMP WITH TIME ZONE '2010-01-02 5:00:00+07:15');
> 7
> -
> 7
> rows: 1
SELECT EXTRACT(TIMEZONE_HOUR FROM TIMESTAMP WITH TIME ZONE '2010-01-02 5:00:00-08:30');
> -8
> --
> -8
> rows: 1
SELECT EXTRACT(TIMEZONE_MINUTE FROM TIMESTAMP WITH TIME ZONE '2010-01-02 5:00:00+07:15');
> 15
> --
> 15
> rows: 1
SELECT EXTRACT(TIMEZONE_MINUTE FROM TIMESTAMP WITH TIME ZONE '2010-01-02 5:00:00-08:30');
> -30
> ---
> -30
> rows: 1
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论