Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
73ac0e4d
Unverified
提交
73ac0e4d
authored
2月 01, 2018
作者:
Noel Grandin
提交者:
GitHub
2月 01, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #825 from katzyn/misc
Merge code for parsing and formatting timestamp values
上级
2a3b8cfb
b1aaab04
显示空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
257 行增加
和
332 行删除
+257
-332
TimestampWithTimeZone.java
h2/src/main/org/h2/api/TimestampWithTimeZone.java
+1
-57
DateTimeUtils.java
h2/src/main/org/h2/util/DateTimeUtils.java
+234
-13
ValueDate.java
h2/src/main/org/h2/value/ValueDate.java
+1
-23
ValueTime.java
h2/src/main/org/h2/value/ValueTime.java
+2
-51
ValueTimestamp.java
h2/src/main/org/h2/value/ValueTimestamp.java
+3
-96
ValueTimestampTimeZone.java
h2/src/main/org/h2/value/ValueTimestampTimeZone.java
+3
-91
timestamp-with-timezone.sql
...org/h2/test/scripts/datatypes/timestamp-with-timezone.sql
+13
-1
没有找到文件。
h2/src/main/org/h2/api/TimestampWithTimeZone.java
浏览文件 @
73ac0e4d
...
@@ -7,7 +7,6 @@ package org.h2.api;
...
@@ -7,7 +7,6 @@ package org.h2.api;
import
java.io.Serializable
;
import
java.io.Serializable
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.StringUtils
;
/**
/**
* How we expose "TIMESTAMP WITH TIMEZONE" in our ResultSets.
* How we expose "TIMESTAMP WITH TIMEZONE" in our ResultSets.
...
@@ -110,62 +109,7 @@ public class TimestampWithTimeZone implements Serializable, Cloneable {
...
@@ -110,62 +109,7 @@ public class TimestampWithTimeZone implements Serializable, Cloneable {
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
StringBuilder
buff
=
new
StringBuilder
();
return
DateTimeUtils
.
timestampTimeZoneToString
(
dateValue
,
timeNanos
,
timeZoneOffsetMins
);
int
y
=
DateTimeUtils
.
yearFromDateValue
(
dateValue
);
int
month
=
DateTimeUtils
.
monthFromDateValue
(
dateValue
);
int
d
=
DateTimeUtils
.
dayFromDateValue
(
dateValue
);
if
(
y
>
0
&&
y
<
10000
)
{
StringUtils
.
appendZeroPadded
(
buff
,
4
,
y
);
}
else
{
buff
.
append
(
y
);
}
buff
.
append
(
'-'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
month
);
buff
.
append
(
'-'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
d
);
buff
.
append
(
' '
);
long
nanos
=
timeNanos
;
long
ms
=
nanos
/
1000000
;
nanos
-=
ms
*
1000000
;
long
s
=
ms
/
1000
;
ms
-=
s
*
1000
;
long
min
=
s
/
60
;
s
-=
min
*
60
;
long
h
=
min
/
60
;
min
-=
h
*
60
;
StringUtils
.
appendZeroPadded
(
buff
,
2
,
h
);
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
min
);
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
s
);
buff
.
append
(
'.'
);
int
start
=
buff
.
length
();
StringUtils
.
appendZeroPadded
(
buff
,
3
,
ms
);
if
(
nanos
>
0
)
{
StringUtils
.
appendZeroPadded
(
buff
,
6
,
nanos
);
}
for
(
int
i
=
buff
.
length
()
-
1
;
i
>
start
;
i
--)
{
if
(
buff
.
charAt
(
i
)
!=
'0'
)
{
break
;
}
buff
.
deleteCharAt
(
i
);
}
short
tz
=
timeZoneOffsetMins
;
if
(
tz
<
0
)
{
buff
.
append
(
'-'
);
tz
=
(
short
)
-
tz
;
}
else
{
buff
.
append
(
'+'
);
}
int
hours
=
tz
/
60
;
tz
-=
hours
*
60
;
int
mins
=
tz
;
StringUtils
.
appendZeroPadded
(
buff
,
2
,
hours
);
if
(
mins
!=
0
)
{
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
mins
);
}
return
buff
.
toString
();
}
}
@Override
@Override
...
...
h2/src/main/org/h2/util/DateTimeUtils.java
浏览文件 @
73ac0e4d
...
@@ -15,6 +15,7 @@ import java.util.GregorianCalendar;
...
@@ -15,6 +15,7 @@ import java.util.GregorianCalendar;
import
java.util.Locale
;
import
java.util.Locale
;
import
java.util.TimeZone
;
import
java.util.TimeZone
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.ErrorCode
;
import
org.h2.engine.Mode
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.value.Value
;
import
org.h2.value.Value
;
import
org.h2.value.ValueDate
;
import
org.h2.value.ValueDate
;
...
@@ -434,6 +435,108 @@ public class DateTimeUtils {
...
@@ -434,6 +435,108 @@ public class DateTimeUtils {
return
negative
?
-
nanos
:
nanos
;
return
negative
?
-
nanos
:
nanos
;
}
}
/**
* See:
* https://stackoverflow.com/questions/3976616/how-to-find-nth-occurrence-of-character-in-a-string#answer-3976656
*/
private
static
int
findNthIndexOf
(
String
str
,
char
chr
,
int
n
)
{
int
pos
=
str
.
indexOf
(
chr
);
while
(--
n
>
0
&&
pos
!=
-
1
)
pos
=
str
.
indexOf
(
chr
,
pos
+
1
);
return
pos
;
}
/**
* Parses timestamp value from the specified string.
*
* @param s
* string to parse
* @param mode
* database mode, or {@code null}
* @param withTimeZone
* if {@code true} return {@link ValueTimestampTimeZone} instead of
* {@link ValueTimestamp}
* @return parsed timestamp
*/
public
static
Value
parseTimestamp
(
String
s
,
Mode
mode
,
boolean
withTimeZone
)
{
int
dateEnd
=
s
.
indexOf
(
' '
);
if
(
dateEnd
<
0
)
{
// ISO 8601 compatibility
dateEnd
=
s
.
indexOf
(
'T'
);
if
(
dateEnd
<
0
&&
mode
!=
null
&&
mode
.
allowDB2TimestampFormat
)
{
// DB2 also allows dash between date and time
dateEnd
=
findNthIndexOf
(
s
,
'-'
,
3
);
}
}
int
timeStart
;
if
(
dateEnd
<
0
)
{
dateEnd
=
s
.
length
();
timeStart
=
-
1
;
}
else
{
timeStart
=
dateEnd
+
1
;
}
long
dateValue
=
parseDateValue
(
s
,
0
,
dateEnd
);
long
nanos
;
short
tzMinutes
=
0
;
if
(
timeStart
<
0
)
{
nanos
=
0
;
}
else
{
int
timeEnd
=
s
.
length
();
TimeZone
tz
=
null
;
if
(
s
.
endsWith
(
"Z"
))
{
tz
=
UTC
;
timeEnd
--;
}
else
{
int
timeZoneStart
=
s
.
indexOf
(
'+'
,
dateEnd
+
1
);
if
(
timeZoneStart
<
0
)
{
timeZoneStart
=
s
.
indexOf
(
'-'
,
dateEnd
+
1
);
}
if
(
timeZoneStart
>=
0
)
{
String
tzName
=
"GMT"
+
s
.
substring
(
timeZoneStart
);
tz
=
TimeZone
.
getTimeZone
(
tzName
);
if
(!
tz
.
getID
().
startsWith
(
tzName
))
{
throw
new
IllegalArgumentException
(
tzName
+
" ("
+
tz
.
getID
()
+
"?)"
);
}
timeEnd
=
timeZoneStart
;
}
else
{
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
;
}
}
}
nanos
=
parseTimeNanos
(
s
,
dateEnd
+
1
,
timeEnd
,
true
);
if
(
tz
!=
null
)
{
if
(
withTimeZone
)
{
if
(
tz
!=
UTC
)
{
long
millis
=
convertDateTimeValueToMillis
(
tz
,
dateValue
,
nanos
/
1000000
);
tzMinutes
=
(
short
)
(
tz
.
getOffset
(
millis
)
/
1000
/
60
);
}
}
else
{
long
ms
=
nanos
/
1000000
;
nanos
-=
ms
*
1000000
;
long
millis
=
convertDateTimeValueToMillis
(
tz
,
dateValue
,
ms
);
ms
=
convertToLocal
(
new
Date
(
millis
),
createGregorianCalendar
(
UTC
));
long
md
=
MILLIS_PER_DAY
;
long
absoluteDay
=
(
ms
>=
0
?
ms
:
ms
-
md
+
1
)
/
md
;
dateValue
=
dateValueFromAbsoluteDay
(
absoluteDay
);
ms
-=
absoluteDay
*
md
;
nanos
+=
ms
*
1000000
;
}
}
}
if
(
withTimeZone
)
{
return
ValueTimestampTimeZone
.
fromDateValueAndNanos
(
dateValue
,
nanos
,
tzMinutes
);
}
return
ValueTimestamp
.
fromDateValueAndNanos
(
dateValue
,
nanos
);
}
/**
/**
* Calculate the milliseconds since 1970-01-01 (UTC) for the given date and
* Calculate the milliseconds since 1970-01-01 (UTC) for the given date and
* time (in the specified timezone).
* time (in the specified timezone).
...
@@ -750,6 +853,25 @@ public class DateTimeUtils {
...
@@ -750,6 +853,25 @@ public class DateTimeUtils {
0
,
0
,
0
);
0
,
0
,
0
);
}
}
/**
* Convert an encoded date-time value to millis, using the supplied timezone.
*
* @param tz the timezone
* @param dateValue the date value
* @param ms milliseconds of day
* @return the date
*/
public
static
long
convertDateTimeValueToMillis
(
TimeZone
tz
,
long
dateValue
,
long
ms
)
{
long
second
=
ms
/
1000
;
ms
-=
second
*
1000
;
int
minute
=
(
int
)
(
second
/
60
);
second
-=
minute
*
60
;
int
hour
=
minute
/
60
;
minute
-=
hour
*
60
;
return
getMillis
(
tz
,
yearFromDateValue
(
dateValue
),
monthFromDateValue
(
dateValue
),
dayFromDateValue
(
dateValue
),
hour
,
minute
,
(
int
)
second
,
(
int
)
ms
);
}
/**
/**
* Convert an encoded date value / time value to a timestamp, using the
* Convert an encoded date value / time value to a timestamp, using the
* default timezone.
* default timezone.
...
@@ -760,19 +882,9 @@ public class DateTimeUtils {
...
@@ -760,19 +882,9 @@ public class DateTimeUtils {
*/
*/
public
static
Timestamp
convertDateValueToTimestamp
(
long
dateValue
,
public
static
Timestamp
convertDateValueToTimestamp
(
long
dateValue
,
long
timeNanos
)
{
long
timeNanos
)
{
long
millis
=
timeNanos
/
1000000
;
Timestamp
ts
=
new
Timestamp
(
convertDateTimeValueToMillis
(
null
,
dateValue
,
timeNanos
/
1000000
));
timeNanos
-=
millis
*
1000000
;
// This method expects the complete nanoseconds value including milliseconds
long
s
=
millis
/
1000
;
ts
.
setNanos
((
int
)
(
timeNanos
%
1000000000
));
millis
-=
s
*
1000
;
long
m
=
s
/
60
;
s
-=
m
*
60
;
long
h
=
m
/
60
;
m
-=
h
*
60
;
long
ms
=
getMillis
(
null
,
yearFromDateValue
(
dateValue
),
monthFromDateValue
(
dateValue
),
dayFromDateValue
(
dateValue
),
(
int
)
h
,
(
int
)
m
,
(
int
)
s
,
0
);
Timestamp
ts
=
new
Timestamp
(
ms
);
ts
.
setNanos
((
int
)
(
timeNanos
+
millis
*
1000000
));
return
ts
;
return
ts
;
}
}
...
@@ -999,4 +1111,113 @@ public class DateTimeUtils {
...
@@ -999,4 +1111,113 @@ public class DateTimeUtils {
return
resultDate
;
return
resultDate
;
}
}
/**
* Append a date to the string builder.
*
* @param buff the target string builder
* @param dateValue the date value
*/
public
static
void
appendDate
(
StringBuilder
buff
,
long
dateValue
)
{
int
y
=
yearFromDateValue
(
dateValue
);
int
m
=
monthFromDateValue
(
dateValue
);
int
d
=
dayFromDateValue
(
dateValue
);
if
(
y
>
0
&&
y
<
10000
)
{
StringUtils
.
appendZeroPadded
(
buff
,
4
,
y
);
}
else
{
buff
.
append
(
y
);
}
buff
.
append
(
'-'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
m
);
buff
.
append
(
'-'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
d
);
}
/**
* Append a time to the string builder.
*
* @param buff the target string builder
* @param nanos the time in nanoseconds
* @param alwaysAddMillis whether to always add at least ".0"
*/
public
static
void
appendTime
(
StringBuilder
buff
,
long
nanos
,
boolean
alwaysAddMillis
)
{
if
(
nanos
<
0
)
{
buff
.
append
(
'-'
);
nanos
=
-
nanos
;
}
/*
* nanos now either in range from 0 to Long.MAX_VALUE or equals to
* Long.MIN_VALUE. We need to divide nanos by 1000000 with unsigned division to
* get correct result. The simplest way to do this with such constraints is to
* divide -nanos by -1000000.
*/
long
ms
=
-
nanos
/
-
1000000
;
nanos
-=
ms
*
1000000
;
long
s
=
ms
/
1000
;
ms
-=
s
*
1000
;
long
m
=
s
/
60
;
s
-=
m
*
60
;
long
h
=
m
/
60
;
m
-=
h
*
60
;
StringUtils
.
appendZeroPadded
(
buff
,
2
,
h
);
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
m
);
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
s
);
if
(
alwaysAddMillis
||
ms
>
0
||
nanos
>
0
)
{
buff
.
append
(
'.'
);
int
start
=
buff
.
length
();
StringUtils
.
appendZeroPadded
(
buff
,
3
,
ms
);
if
(
nanos
>
0
)
{
StringUtils
.
appendZeroPadded
(
buff
,
6
,
nanos
);
}
for
(
int
i
=
buff
.
length
()
-
1
;
i
>
start
;
i
--)
{
if
(
buff
.
charAt
(
i
)
!=
'0'
)
{
break
;
}
buff
.
deleteCharAt
(
i
);
}
}
}
/**
* Append a time zone to the string builder.
*
* @param buff the target string builder
* @param tz the time zone in minutes
*/
public
static
void
appendTimeZone
(
StringBuilder
buff
,
short
tz
)
{
if
(
tz
<
0
)
{
buff
.
append
(
'-'
);
tz
=
(
short
)
-
tz
;
}
else
{
buff
.
append
(
'+'
);
}
int
hours
=
tz
/
60
;
tz
-=
hours
*
60
;
int
mins
=
tz
;
StringUtils
.
appendZeroPadded
(
buff
,
2
,
hours
);
if
(
mins
!=
0
)
{
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
mins
);
}
}
/**
* Formats timestamp with time zone as string.
*
* @param dateValue the year-month-day bit field
* @param timeNanos nanoseconds since midnight
* @param timeZoneOffsetMins the time zone offset in minutes
* @return formatted string
*/
public
static
String
timestampTimeZoneToString
(
long
dateValue
,
long
timeNanos
,
short
timeZoneOffsetMins
)
{
StringBuilder
buff
=
new
StringBuilder
(
ValueTimestampTimeZone
.
DISPLAY_SIZE
);
appendDate
(
buff
,
dateValue
);
buff
.
append
(
' '
);
appendTime
(
buff
,
timeNanos
,
true
);
appendTimeZone
(
buff
,
timeZoneOffsetMins
);
return
buff
.
toString
();
}
}
}
h2/src/main/org/h2/value/ValueDate.java
浏览文件 @
73ac0e4d
...
@@ -12,7 +12,6 @@ import java.sql.SQLException;
...
@@ -12,7 +12,6 @@ import java.sql.SQLException;
import
org.h2.api.ErrorCode
;
import
org.h2.api.ErrorCode
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.StringUtils
;
/**
/**
* Implementation of the DATE data type.
* Implementation of the DATE data type.
...
@@ -99,7 +98,7 @@ public class ValueDate extends Value {
...
@@ -99,7 +98,7 @@ public class ValueDate extends Value {
@Override
@Override
public
String
getString
()
{
public
String
getString
()
{
StringBuilder
buff
=
new
StringBuilder
(
DISPLAY_SIZE
);
StringBuilder
buff
=
new
StringBuilder
(
DISPLAY_SIZE
);
appendDate
(
buff
,
dateValue
);
DateTimeUtils
.
appendDate
(
buff
,
dateValue
);
return
buff
.
toString
();
return
buff
.
toString
();
}
}
...
@@ -148,25 +147,4 @@ public class ValueDate extends Value {
...
@@ -148,25 +147,4 @@ public class ValueDate extends Value {
prep
.
setDate
(
parameterIndex
,
getDate
());
prep
.
setDate
(
parameterIndex
,
getDate
());
}
}
/**
* Append a date to the string builder.
*
* @param buff the target string builder
* @param dateValue the date value
*/
static
void
appendDate
(
StringBuilder
buff
,
long
dateValue
)
{
int
y
=
DateTimeUtils
.
yearFromDateValue
(
dateValue
);
int
m
=
DateTimeUtils
.
monthFromDateValue
(
dateValue
);
int
d
=
DateTimeUtils
.
dayFromDateValue
(
dateValue
);
if
(
y
>
0
&&
y
<
10000
)
{
StringUtils
.
appendZeroPadded
(
buff
,
4
,
y
);
}
else
{
buff
.
append
(
y
);
}
buff
.
append
(
'-'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
m
);
buff
.
append
(
'-'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
d
);
}
}
}
h2/src/main/org/h2/value/ValueTime.java
浏览文件 @
73ac0e4d
...
@@ -12,7 +12,6 @@ import org.h2.api.ErrorCode;
...
@@ -12,7 +12,6 @@ import org.h2.api.ErrorCode;
import
org.h2.engine.SysProperties
;
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
;
import
org.h2.util.StringUtils
;
/**
/**
* Implementation of the TIME data type.
* Implementation of the TIME data type.
...
@@ -52,7 +51,7 @@ public class ValueTime extends Value {
...
@@ -52,7 +51,7 @@ public class ValueTime extends Value {
if
(!
SysProperties
.
UNLIMITED_TIME_RANGE
)
{
if
(!
SysProperties
.
UNLIMITED_TIME_RANGE
)
{
if
(
nanos
<
0L
||
nanos
>=
86400000000000L
)
{
if
(
nanos
<
0L
||
nanos
>=
86400000000000L
)
{
StringBuilder
builder
=
new
StringBuilder
();
StringBuilder
builder
=
new
StringBuilder
();
appendTime
(
builder
,
nanos
,
false
);
DateTimeUtils
.
appendTime
(
builder
,
nanos
,
false
);
throw
DbException
.
get
(
ErrorCode
.
INVALID_DATETIME_CONSTANT_2
,
throw
DbException
.
get
(
ErrorCode
.
INVALID_DATETIME_CONSTANT_2
,
"TIME"
,
builder
.
toString
());
"TIME"
,
builder
.
toString
());
}
}
...
@@ -116,7 +115,7 @@ public class ValueTime extends Value {
...
@@ -116,7 +115,7 @@ public class ValueTime extends Value {
@Override
@Override
public
String
getString
()
{
public
String
getString
()
{
StringBuilder
buff
=
new
StringBuilder
(
DISPLAY_SIZE
);
StringBuilder
buff
=
new
StringBuilder
(
DISPLAY_SIZE
);
appendTime
(
buff
,
nanos
,
false
);
DateTimeUtils
.
appendTime
(
buff
,
nanos
,
false
);
return
buff
.
toString
();
return
buff
.
toString
();
}
}
...
@@ -196,52 +195,4 @@ public class ValueTime extends Value {
...
@@ -196,52 +195,4 @@ public class ValueTime extends Value {
return
ValueTime
.
fromNanos
(-
nanos
);
return
ValueTime
.
fromNanos
(-
nanos
);
}
}
/**
* Append a time to the string builder.
*
* @param buff the target string builder
* @param nanos the time in nanoseconds
* @param alwaysAddMillis whether to always add at least ".0"
*/
static
void
appendTime
(
StringBuilder
buff
,
long
nanos
,
boolean
alwaysAddMillis
)
{
if
(
nanos
<
0
)
{
buff
.
append
(
'-'
);
nanos
=
-
nanos
;
}
/*
* nanos now either in range from 0 to Long.MAX_VALUE or equals to
* Long.MIN_VALUE. We need to divide nanos by 1000000 with unsigned division to
* get correct result. The simplest way to do this with such constraints is to
* divide -nanos by -1000000.
*/
long
ms
=
-
nanos
/
-
1000000
;
nanos
-=
ms
*
1000000
;
long
s
=
ms
/
1000
;
ms
-=
s
*
1000
;
long
m
=
s
/
60
;
s
-=
m
*
60
;
long
h
=
m
/
60
;
m
-=
h
*
60
;
StringUtils
.
appendZeroPadded
(
buff
,
2
,
h
);
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
m
);
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
s
);
if
(
alwaysAddMillis
||
ms
>
0
||
nanos
>
0
)
{
buff
.
append
(
'.'
);
int
start
=
buff
.
length
();
StringUtils
.
appendZeroPadded
(
buff
,
3
,
ms
);
if
(
nanos
>
0
)
{
StringUtils
.
appendZeroPadded
(
buff
,
6
,
nanos
);
}
for
(
int
i
=
buff
.
length
()
-
1
;
i
>
start
;
i
--)
{
if
(
buff
.
charAt
(
i
)
!=
'0'
)
{
break
;
}
buff
.
deleteCharAt
(
i
);
}
}
}
}
}
h2/src/main/org/h2/value/ValueTimestamp.java
浏览文件 @
73ac0e4d
...
@@ -6,11 +6,9 @@
...
@@ -6,11 +6,9 @@
package
org
.
h2
.
value
;
package
org
.
h2
.
value
;
import
java.math.BigDecimal
;
import
java.math.BigDecimal
;
import
java.sql.Date
;
import
java.sql.PreparedStatement
;
import
java.sql.PreparedStatement
;
import
java.sql.SQLException
;
import
java.sql.SQLException
;
import
java.sql.Timestamp
;
import
java.sql.Timestamp
;
import
java.util.TimeZone
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.ErrorCode
;
import
org.h2.engine.Mode
;
import
org.h2.engine.Mode
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
...
@@ -129,104 +127,13 @@ public class ValueTimestamp extends Value {
...
@@ -129,104 +127,13 @@ public class ValueTimestamp extends Value {
*/
*/
public
static
ValueTimestamp
parse
(
String
s
,
Mode
mode
)
{
public
static
ValueTimestamp
parse
(
String
s
,
Mode
mode
)
{
try
{
try
{
return
parseTry
(
s
,
mod
e
);
return
(
ValueTimestamp
)
DateTimeUtils
.
parseTimestamp
(
s
,
mode
,
fals
e
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_DATETIME_CONSTANT_2
,
throw
DbException
.
get
(
ErrorCode
.
INVALID_DATETIME_CONSTANT_2
,
e
,
"TIMESTAMP"
,
s
);
e
,
"TIMESTAMP"
,
s
);
}
}
}
}
/**
* See:
* https://stackoverflow.com/questions/3976616/how-to-find-nth-occurrence-of-character-in-a-string#answer-3976656
*/
private
static
int
findNthIndexOf
(
String
str
,
char
chr
,
int
n
)
{
int
pos
=
str
.
indexOf
(
chr
);
while
(--
n
>
0
&&
pos
!=
-
1
)
pos
=
str
.
indexOf
(
chr
,
pos
+
1
);
return
pos
;
}
private
static
ValueTimestamp
parseTry
(
String
s
,
Mode
mode
)
{
int
dateEnd
=
s
.
indexOf
(
' '
);
if
(
dateEnd
<
0
)
{
// ISO 8601 compatibility
dateEnd
=
s
.
indexOf
(
'T'
);
if
(
dateEnd
<
0
&&
mode
!=
null
&&
mode
.
allowDB2TimestampFormat
)
{
// DB2 also allows dash between date and time
dateEnd
=
findNthIndexOf
(
s
,
'-'
,
3
);
}
}
int
timeStart
;
if
(
dateEnd
<
0
)
{
dateEnd
=
s
.
length
();
timeStart
=
-
1
;
}
else
{
timeStart
=
dateEnd
+
1
;
}
long
dateValue
=
DateTimeUtils
.
parseDateValue
(
s
,
0
,
dateEnd
);
long
nanos
;
if
(
timeStart
<
0
)
{
nanos
=
0
;
}
else
{
int
timeEnd
=
s
.
length
();
TimeZone
tz
=
null
;
if
(
s
.
endsWith
(
"Z"
))
{
tz
=
DateTimeUtils
.
UTC
;
timeEnd
--;
}
else
{
int
timeZoneStart
=
s
.
indexOf
(
'+'
,
dateEnd
+
1
);
if
(
timeZoneStart
<
0
)
{
timeZoneStart
=
s
.
indexOf
(
'-'
,
dateEnd
+
1
);
}
if
(
timeZoneStart
>=
0
)
{
String
tzName
=
"GMT"
+
s
.
substring
(
timeZoneStart
);
tz
=
TimeZone
.
getTimeZone
(
tzName
);
if
(!
tz
.
getID
().
startsWith
(
tzName
))
{
throw
new
IllegalArgumentException
(
tzName
+
" ("
+
tz
.
getID
()
+
"?)"
);
}
timeEnd
=
timeZoneStart
;
}
else
{
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
;
}
}
}
nanos
=
DateTimeUtils
.
parseTimeNanos
(
s
,
dateEnd
+
1
,
timeEnd
,
true
);
if
(
tz
!=
null
)
{
int
year
=
DateTimeUtils
.
yearFromDateValue
(
dateValue
);
int
month
=
DateTimeUtils
.
monthFromDateValue
(
dateValue
);
int
day
=
DateTimeUtils
.
dayFromDateValue
(
dateValue
);
long
ms
=
nanos
/
1000000
;
nanos
-=
ms
*
1000000
;
long
second
=
ms
/
1000
;
ms
-=
second
*
1000
;
int
minute
=
(
int
)
(
second
/
60
);
second
-=
minute
*
60
;
int
hour
=
minute
/
60
;
minute
-=
hour
*
60
;
long
millis
=
DateTimeUtils
.
getMillis
(
tz
,
year
,
month
,
day
,
hour
,
minute
,
(
int
)
second
,
(
int
)
ms
);
ms
=
DateTimeUtils
.
convertToLocal
(
new
Date
(
millis
),
DateTimeUtils
.
createGregorianCalendar
(
DateTimeUtils
.
UTC
));
long
md
=
DateTimeUtils
.
MILLIS_PER_DAY
;
long
absoluteDay
=
(
ms
>=
0
?
ms
:
ms
-
md
+
1
)
/
md
;
dateValue
=
DateTimeUtils
.
dateValueFromAbsoluteDay
(
absoluteDay
);
ms
-=
absoluteDay
*
md
;
nanos
+=
ms
*
1000000
;
}
}
return
ValueTimestamp
.
fromDateValueAndNanos
(
dateValue
,
nanos
);
}
/**
/**
* A bit field with bits for the year, month, and day (see DateTimeUtils for
* A bit field with bits for the year, month, and day (see DateTimeUtils for
* encoding).
* encoding).
...
@@ -259,9 +166,9 @@ public class ValueTimestamp extends Value {
...
@@ -259,9 +166,9 @@ public class ValueTimestamp extends Value {
@Override
@Override
public
String
getString
()
{
public
String
getString
()
{
StringBuilder
buff
=
new
StringBuilder
(
DISPLAY_SIZE
);
StringBuilder
buff
=
new
StringBuilder
(
DISPLAY_SIZE
);
ValueDate
.
appendDate
(
buff
,
dateValue
);
DateTimeUtils
.
appendDate
(
buff
,
dateValue
);
buff
.
append
(
' '
);
buff
.
append
(
' '
);
ValueTime
.
appendTime
(
buff
,
timeNanos
,
true
);
DateTimeUtils
.
appendTime
(
buff
,
timeNanos
,
true
);
return
buff
.
toString
();
return
buff
.
toString
();
}
}
...
...
h2/src/main/org/h2/value/ValueTimestampTimeZone.java
浏览文件 @
73ac0e4d
...
@@ -15,7 +15,6 @@ import org.h2.api.ErrorCode;
...
@@ -15,7 +15,6 @@ import org.h2.api.ErrorCode;
import
org.h2.api.TimestampWithTimeZone
;
import
org.h2.api.TimestampWithTimeZone
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.StringUtils
;
/**
/**
* Implementation of the TIMESTAMP WITH TIME ZONE data type.
* Implementation of the TIMESTAMP WITH TIME ZONE data type.
...
@@ -34,7 +33,7 @@ public class ValueTimestampTimeZone extends Value {
...
@@ -34,7 +33,7 @@ public class ValueTimestampTimeZone extends Value {
* The display size of the textual representation of a timestamp. Example:
* The display size of the textual representation of a timestamp. Example:
* 2001-01-01 23:59:59.000 +10:00
* 2001-01-01 23:59:59.000 +10:00
*/
*/
static
final
int
DISPLAY_SIZE
=
30
;
public
static
final
int
DISPLAY_SIZE
=
30
;
/**
/**
* The default scale for timestamps.
* The default scale for timestamps.
...
@@ -114,72 +113,13 @@ public class ValueTimestampTimeZone extends Value {
...
@@ -114,72 +113,13 @@ public class ValueTimestampTimeZone extends Value {
*/
*/
public
static
ValueTimestampTimeZone
parse
(
String
s
)
{
public
static
ValueTimestampTimeZone
parse
(
String
s
)
{
try
{
try
{
return
parseTry
(
s
);
return
(
ValueTimestampTimeZone
)
DateTimeUtils
.
parseTimestamp
(
s
,
null
,
true
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
throw
DbException
.
get
(
ErrorCode
.
INVALID_DATETIME_CONSTANT_2
,
e
,
throw
DbException
.
get
(
ErrorCode
.
INVALID_DATETIME_CONSTANT_2
,
e
,
"TIMESTAMP WITH TIME ZONE"
,
s
);
"TIMESTAMP WITH TIME ZONE"
,
s
);
}
}
}
}
private
static
ValueTimestampTimeZone
parseTry
(
String
s
)
{
int
dateEnd
=
s
.
indexOf
(
' '
);
if
(
dateEnd
<
0
)
{
// ISO 8601 compatibility
dateEnd
=
s
.
indexOf
(
'T'
);
}
int
timeStart
;
if
(
dateEnd
<
0
)
{
dateEnd
=
s
.
length
();
timeStart
=
-
1
;
}
else
{
timeStart
=
dateEnd
+
1
;
}
long
dateValue
=
DateTimeUtils
.
parseDateValue
(
s
,
0
,
dateEnd
);
long
nanos
;
short
tzMinutes
=
0
;
if
(
timeStart
<
0
)
{
nanos
=
0
;
}
else
{
int
timeEnd
=
s
.
length
();
if
(
s
.
endsWith
(
"Z"
))
{
timeEnd
--;
}
else
{
int
timeZoneStart
=
s
.
indexOf
(
'+'
,
dateEnd
);
if
(
timeZoneStart
<
0
)
{
timeZoneStart
=
s
.
indexOf
(
'-'
,
dateEnd
);
}
TimeZone
tz
=
null
;
if
(
timeZoneStart
>=
0
)
{
String
tzName
=
"GMT"
+
s
.
substring
(
timeZoneStart
);
tz
=
TimeZone
.
getTimeZone
(
tzName
);
if
(!
tz
.
getID
().
startsWith
(
tzName
))
{
throw
new
IllegalArgumentException
(
tzName
+
" ("
+
tz
.
getID
()
+
"?)"
);
}
timeEnd
=
timeZoneStart
;
}
else
{
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
;
}
}
if
(
tz
!=
null
)
{
long
millis
=
DateTimeUtils
.
convertDateValueToMillis
(
DateTimeUtils
.
UTC
,
dateValue
);
tzMinutes
=
(
short
)
(
tz
.
getOffset
(
millis
)
/
1000
/
60
);
}
}
nanos
=
DateTimeUtils
.
parseTimeNanos
(
s
,
dateEnd
+
1
,
timeEnd
,
true
);
}
return
ValueTimestampTimeZone
.
fromDateValueAndNanos
(
dateValue
,
nanos
,
tzMinutes
);
}
/**
/**
* A bit field with bits for the year, month, and day (see DateTimeUtils for
* A bit field with bits for the year, month, and day (see DateTimeUtils for
* encoding).
* encoding).
...
@@ -233,35 +173,7 @@ public class ValueTimestampTimeZone extends Value {
...
@@ -233,35 +173,7 @@ public class ValueTimestampTimeZone extends Value {
@Override
@Override
public
String
getString
()
{
public
String
getString
()
{
StringBuilder
buff
=
new
StringBuilder
(
DISPLAY_SIZE
);
return
DateTimeUtils
.
timestampTimeZoneToString
(
dateValue
,
timeNanos
,
timeZoneOffsetMins
);
ValueDate
.
appendDate
(
buff
,
dateValue
);
buff
.
append
(
' '
);
ValueTime
.
appendTime
(
buff
,
timeNanos
,
true
);
appendTimeZone
(
buff
,
timeZoneOffsetMins
);
return
buff
.
toString
();
}
/**
* Append a time zone to the string builder.
*
* @param buff the target string builder
* @param tz the time zone in minutes
*/
private
static
void
appendTimeZone
(
StringBuilder
buff
,
short
tz
)
{
if
(
tz
<
0
)
{
buff
.
append
(
'-'
);
tz
=
(
short
)
-
tz
;
}
else
{
buff
.
append
(
'+'
);
}
int
hours
=
tz
/
60
;
tz
-=
hours
*
60
;
int
mins
=
tz
;
StringUtils
.
appendZeroPadded
(
buff
,
2
,
hours
);
if
(
mins
!=
0
)
{
buff
.
append
(
':'
);
StringUtils
.
appendZeroPadded
(
buff
,
2
,
mins
);
}
}
}
@Override
@Override
...
...
h2/src/test/org/h2/test/scripts/datatypes/timestamp-with-timezone.sql
浏览文件 @
73ac0e4d
...
@@ -3,7 +3,6 @@
...
@@ -3,7 +3,6 @@
-- Initial Developer: H2 Group
-- Initial Developer: H2 Group
--
--
CREATE
TABLE
tab_with_timezone
(
x
TIMESTAMP
WITH
TIME
ZONE
);
CREATE
TABLE
tab_with_timezone
(
x
TIMESTAMP
WITH
TIME
ZONE
);
>
ok
>
ok
...
@@ -14,3 +13,16 @@ SELECT "Query".* FROM (select * from tab_with_timezone where x > '2016-01-01') A
...
@@ -14,3 +13,16 @@ SELECT "Query".* FROM (select * from tab_with_timezone where x > '2016-01-01') A
>
X
>
X
>
------------------------
>
------------------------
>
2017
-
01
-
01
00
:
00
:
00
.
0
+
00
>
2017
-
01
-
01
00
:
00
:
00
.
0
+
00
DELETE
FROM
tab_with_timezone
;
>
update
count
:
1
INSERT
INTO
tab_with_timezone
VALUES
(
'2018-03-25 01:59:00 Europe/Berlin'
),
(
'2018-03-25 03:00:00 Europe/Berlin'
);
>
update
count
:
2
SELECT
*
FROM
tab_with_timezone
ORDER
BY
X
;
>
X
>
------------------------
>
2018
-
03
-
25
01
:
59
:
00
.
0
+
01
>
2018
-
03
-
25
03
:
00
:
00
.
0
+
02
>
rows
(
ordered
):
2
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论