Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
778748d1
提交
778748d1
authored
2月 15, 2018
作者:
Evgenij Ryazanov
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Reimplement TO_DATE without a Calendar and fix a lot of bugs an incompatibilities
上级
aac17564
显示空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
360 行增加
和
210 行删除
+360
-210
Function.java
h2/src/main/org/h2/expression/Function.java
+11
-5
ToChar.java
h2/src/main/org/h2/util/ToChar.java
+3
-3
ToDateParser.java
h2/src/main/org/h2/util/ToDateParser.java
+202
-40
ToDateTokenizer.java
h2/src/main/org/h2/util/ToDateTokenizer.java
+77
-103
TestFunctions.java
h2/src/test/org/h2/test/db/TestFunctions.java
+67
-59
没有找到文件。
h2/src/main/org/h2/expression/Function.java
浏览文件 @
778748d1
...
...
@@ -98,7 +98,7 @@ public class Function extends Expression implements FunctionCall {
XMLATTR
=
83
,
XMLNODE
=
84
,
XMLCOMMENT
=
85
,
XMLCDATA
=
86
,
XMLSTARTDOC
=
87
,
XMLTEXT
=
88
,
REGEXP_REPLACE
=
89
,
RPAD
=
90
,
LPAD
=
91
,
CONCAT_WS
=
92
,
TO_CHAR
=
93
,
TRANSLATE
=
94
,
ORA_HASH
=
95
,
TO_DATE
=
96
,
TO_TIMESTAMP
=
97
,
ADD_MONTHS
=
98
;
TO_DATE
=
96
,
TO_TIMESTAMP
=
97
,
ADD_MONTHS
=
98
,
TO_TIMESTAMP_TZ
=
99
;
public
static
final
int
CURDATE
=
100
,
CURTIME
=
101
,
DATE_ADD
=
102
,
DATE_DIFF
=
103
,
DAY_NAME
=
104
,
DAY_OF_MONTH
=
105
,
...
...
@@ -335,6 +335,7 @@ public class Function extends Expression implements FunctionCall {
addFunction
(
"TO_DATE"
,
TO_DATE
,
VAR_ARGS
,
Value
.
TIMESTAMP
);
addFunction
(
"TO_TIMESTAMP"
,
TO_TIMESTAMP
,
VAR_ARGS
,
Value
.
TIMESTAMP
);
addFunction
(
"ADD_MONTHS"
,
ADD_MONTHS
,
2
,
Value
.
TIMESTAMP
);
addFunction
(
"TO_TIMESTAMP_TZ"
,
TO_TIMESTAMP_TZ
,
VAR_ARGS
,
Value
.
TIMESTAMP_TZ
);
// alias for MSSQLServer
addFunctionNotDeterministic
(
"GETDATE"
,
CURDATE
,
0
,
Value
.
DATE
);
...
...
@@ -1455,16 +1456,20 @@ public class Function extends Expression implements FunctionCall {
}
break
;
case
TO_DATE:
result
=
ValueTimestamp
.
get
(
ToDateParser
.
toDate
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
())
)
;
result
=
ToDateParser
.
toDate
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
());
break
;
case
TO_TIMESTAMP:
result
=
ValueTimestamp
.
get
(
ToDateParser
.
toTimestamp
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
())
)
;
result
=
ToDateParser
.
toTimestamp
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
());
break
;
case
ADD_MONTHS:
result
=
dateadd
(
"MONTH"
,
v1
.
getInt
(),
v0
);
break
;
case
TO_TIMESTAMP_TZ:
result
=
ToDateParser
.
toTimestampTz
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
());
break
;
case
TRANSLATE:
{
String
matching
=
v1
.
getString
();
String
replacement
=
v2
.
getString
();
...
...
@@ -2307,6 +2312,7 @@ public class Function extends Expression implements FunctionCall {
case
XMLTEXT:
case
TRUNCATE:
case
TO_TIMESTAMP:
case
TO_TIMESTAMP_TZ:
min
=
1
;
max
=
2
;
break
;
...
...
h2/src/main/org/h2/util/ToChar.java
浏览文件 @
778748d1
...
...
@@ -28,7 +28,7 @@ public class ToChar {
/**
* The beginning of the Julian calendar.
*/
private
static
final
int
JULIAN_EPOCH
=
-
2_440_588
;
static
final
int
JULIAN_EPOCH
=
-
2_440_588
;
private
static
final
int
[]
ROMAN_VALUES
=
{
1000
,
900
,
500
,
400
,
100
,
90
,
50
,
40
,
10
,
9
,
5
,
4
,
1
};
...
...
@@ -36,7 +36,7 @@ public class ToChar {
private
static
final
String
[]
ROMAN_NUMERALS
=
{
"M"
,
"CM"
,
"D"
,
"CD"
,
"C"
,
"XC"
,
"L"
,
"XL"
,
"X"
,
"IX"
,
"V"
,
"IV"
,
"I"
};
private
static
final
int
MONTHS
=
0
,
SHORT_MONTHS
=
1
,
WEEKDAYS
=
2
,
SHORT_WEEKDAYS
=
3
,
AM_PM
=
4
;
static
final
int
MONTHS
=
0
,
SHORT_MONTHS
=
1
,
WEEKDAYS
=
2
,
SHORT_WEEKDAYS
=
3
,
AM_PM
=
4
;
private
static
volatile
String
[][]
NAMES
;
...
...
@@ -454,7 +454,7 @@ public class ToChar {
return
hex
;
}
private
static
String
[]
getNames
(
int
names
)
{
static
String
[]
getNames
(
int
names
)
{
String
[][]
result
=
NAMES
;
if
(
result
==
null
)
{
result
=
new
String
[
5
][];
...
...
h2/src/main/org/h2/util/ToDateParser.java
浏览文件 @
778748d1
...
...
@@ -7,9 +7,13 @@ package org.h2.util;
import
static
java
.
lang
.
String
.
format
;
import
java.sql.Timestamp
;
import
java.util.Calendar
;
import
java.util.GregorianCalendar
;
import
java.util.List
;
import
java.util.TimeZone
;
import
org.h2.value.ValueTimestamp
;
import
org.h2.value.ValueTimestampTimeZone
;
/**
* Emulates Oracle's TO_DATE function.<br>
...
...
@@ -21,8 +25,29 @@ public class ToDateParser {
private
final
ConfigParam
functionName
;
private
String
inputStr
;
private
String
formatStr
;
private
final
Calendar
resultCalendar
=
DateTimeUtils
.
createGregorianCalendar
();
private
Integer
nanos
;
private
boolean
doyValid
=
false
,
absoluteDayValid
=
false
,
hour12Valid
=
false
,
timeZoneHMValid
=
false
;
private
boolean
bc
;
private
long
absoluteDay
;
private
int
year
,
month
,
day
=
1
;
private
int
dayOfYear
;
private
int
hour
,
minute
,
second
,
nanos
;
private
int
hour12
;
boolean
isAM
=
true
;
private
TimeZone
timeZone
;
private
int
timeZoneHour
,
timeZoneMinute
;
private
int
currentYear
,
currentMonth
;
/**
* @param input the input date with the date-time info
...
...
@@ -32,18 +57,6 @@ public class ToDateParser {
*/
private
ToDateParser
(
ConfigParam
functionName
,
String
input
,
String
format
)
{
// reset calendar - default oracle behaviour
resultCalendar
.
set
(
Calendar
.
YEAR
,
1970
);
resultCalendar
.
set
(
Calendar
.
MONTH
,
DateTimeUtils
.
createGregorianCalendar
().
get
(
Calendar
.
MONTH
));
resultCalendar
.
clear
(
Calendar
.
DAY_OF_YEAR
);
resultCalendar
.
clear
(
Calendar
.
DAY_OF_WEEK
);
resultCalendar
.
clear
(
Calendar
.
DAY_OF_WEEK_IN_MONTH
);
resultCalendar
.
set
(
Calendar
.
DAY_OF_MONTH
,
1
);
resultCalendar
.
set
(
Calendar
.
HOUR
,
0
);
resultCalendar
.
set
(
Calendar
.
HOUR_OF_DAY
,
0
);
resultCalendar
.
set
(
Calendar
.
MINUTE
,
0
);
resultCalendar
.
set
(
Calendar
.
SECOND
,
0
);
resultCalendar
.
set
(
Calendar
.
MILLISECOND
,
0
);
resultCalendar
.
set
(
Calendar
.
AM_PM
,
Calendar
.
AM
);
this
.
functionName
=
functionName
;
inputStr
=
input
.
trim
();
...
...
@@ -59,30 +72,65 @@ public class ToDateParser {
unmodifiedFormatStr
=
formatStr
;
}
private
static
ToDateParser
get
DateParser
(
String
input
,
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_DATE
,
input
,
format
);
private
static
ToDateParser
get
TimestampParser
(
ConfigParam
param
,
String
input
,
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
param
,
input
,
format
);
parse
(
result
);
return
result
;
}
private
static
ToDateParser
getTimestampParser
(
String
input
,
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_TIMESTAMP
,
input
,
format
);
parse
(
result
);
return
result
;
private
ValueTimestamp
getResultingValue
()
{
long
dateValue
;
if
(
absoluteDayValid
)
{
dateValue
=
DateTimeUtils
.
dateValueFromAbsoluteDay
(
absoluteDay
);
}
else
{
int
year
=
this
.
year
;
if
(
year
==
0
)
{
year
=
getCurrentYear
();
}
if
(
bc
)
{
year
=
1
-
year
;
}
if
(
doyValid
)
{
dateValue
=
DateTimeUtils
.
dateValueFromAbsoluteDay
(
DateTimeUtils
.
absoluteDayFromDateValue
(
DateTimeUtils
.
dateValue
(
year
,
1
,
1
))
+
dayOfYear
-
1
);
}
else
{
int
month
=
this
.
month
;
if
(
month
==
0
)
{
// Oracle uses current month as default
month
=
getCurrentMonth
();
}
dateValue
=
DateTimeUtils
.
dateValue
(
year
,
month
,
day
);
}
private
Timestamp
getResultingTimestamp
()
{
Calendar
cal
=
(
Calendar
)
getResultCalendar
().
clone
();
int
nanosToSet
=
nanos
==
null
?
cal
.
get
(
Calendar
.
MILLISECOND
)
*
1000000
:
nanos
.
intValue
();
cal
.
set
(
Calendar
.
MILLISECOND
,
0
);
Timestamp
ts
=
new
Timestamp
(
cal
.
getTimeInMillis
());
ts
.
setNanos
(
nanosToSet
);
return
ts
;
}
int
hour
;
if
(
hour12Valid
)
{
hour
=
hour12
%
12
;
if
(!
isAM
)
{
hour
+=
12
;
}
}
else
{
hour
=
this
.
hour
;
}
long
timeNanos
=
((((
hour
*
60
)
+
minute
)
*
60
)
+
second
)
*
1_000_000_000L
+
nanos
;
return
ValueTimestamp
.
fromDateValueAndNanos
(
dateValue
,
timeNanos
);
}
Calendar
getResultCalendar
()
{
return
resultCalendar
;
private
ValueTimestampTimeZone
getResultingValueWithTimeZone
()
{
ValueTimestamp
ts
=
getResultingValue
();
long
dateValue
=
ts
.
getDateValue
();
short
offset
;
if
(
timeZoneHMValid
)
{
offset
=
(
short
)
(
timeZoneHour
*
60
+
((
timeZoneHour
>=
0
)
?
timeZoneMinute
:
-
timeZoneMinute
));
}
else
{
TimeZone
timeZone
=
this
.
timeZone
;
if
(
timeZone
==
null
)
{
timeZone
=
TimeZone
.
getDefault
();
}
long
millis
=
DateTimeUtils
.
convertDateTimeValueToMillis
(
timeZone
,
dateValue
,
nanos
/
1000000
);
offset
=
(
short
)
(
timeZone
.
getOffset
(
millis
)
/
1000
/
60
);
}
return
ValueTimestampTimeZone
.
fromDateValueAndNanos
(
dateValue
,
ts
.
getTimeNanos
(),
offset
);
}
String
getInputStr
()
{
...
...
@@ -97,10 +145,111 @@ public class ToDateParser {
return
functionName
.
name
();
}
private
void
queryCurrentYearAndMonth
()
{
GregorianCalendar
gc
=
DateTimeUtils
.
getCalendar
();
gc
.
setTimeInMillis
(
System
.
currentTimeMillis
());
currentYear
=
gc
.
get
(
Calendar
.
YEAR
);
currentMonth
=
gc
.
get
(
Calendar
.
MONTH
)
+
1
;
}
int
getCurrentYear
()
{
if
(
currentYear
==
0
)
{
queryCurrentYearAndMonth
();
}
return
currentYear
;
}
int
getCurrentMonth
()
{
if
(
currentMonth
==
0
)
{
queryCurrentYearAndMonth
();
}
return
currentMonth
;
}
void
setAbsoluteDay
(
int
absoluteDay
)
{
doyValid
=
false
;
absoluteDayValid
=
true
;
this
.
absoluteDay
=
absoluteDay
;
}
void
setBC
(
boolean
bc
)
{
doyValid
=
false
;
absoluteDayValid
=
false
;
this
.
bc
=
bc
;
}
void
setYear
(
int
year
)
{
doyValid
=
false
;
absoluteDayValid
=
false
;
this
.
year
=
year
;
}
void
setMonth
(
int
month
)
{
doyValid
=
false
;
absoluteDayValid
=
false
;
this
.
month
=
month
;
if
(
year
==
0
)
{
year
=
1970
;
}
}
void
setDay
(
int
day
)
{
doyValid
=
false
;
absoluteDayValid
=
false
;
this
.
day
=
day
;
if
(
year
==
0
)
{
year
=
1970
;
}
}
void
setDayOfYear
(
int
dayOfYear
)
{
doyValid
=
true
;
absoluteDayValid
=
false
;
this
.
dayOfYear
=
dayOfYear
;
}
void
setHour
(
int
hour
)
{
hour12Valid
=
false
;
this
.
hour
=
hour
;
}
void
setMinute
(
int
minute
)
{
this
.
minute
=
minute
;
}
void
setSecord
(
int
second
)
{
this
.
second
=
second
;
}
void
setNanos
(
int
nanos
)
{
this
.
nanos
=
nanos
;
}
void
setAmPm
(
boolean
isAM
)
{
hour12Valid
=
true
;
this
.
isAM
=
isAM
;
}
void
setHour12
(
int
hour12
)
{
hour12Valid
=
true
;
this
.
hour12
=
hour12
;
}
void
setTimeZone
(
TimeZone
timeZone
)
{
timeZoneHMValid
=
false
;
this
.
timeZone
=
timeZone
;
}
void
setTimeZoneHour
(
int
timeZoneHour
)
{
timeZoneHMValid
=
true
;
this
.
timeZoneHour
=
timeZoneHour
;
}
void
setTimeZoneMinute
(
int
timeZoneMinute
)
{
timeZoneHMValid
=
true
;
this
.
timeZoneMinute
=
timeZoneMinute
;
}
private
boolean
hasToParseData
()
{
return
formatStr
.
length
()
>
0
;
}
...
...
@@ -180,9 +329,21 @@ public class ToDateParser {
* @param format the format
* @return the timestamp
*/
public
static
Timestamp
toTimestamp
(
String
input
,
String
format
)
{
ToDateParser
parser
=
getTimestampParser
(
input
,
format
);
return
parser
.
getResultingTimestamp
();
public
static
ValueTimestamp
toTimestamp
(
String
input
,
String
format
)
{
ToDateParser
parser
=
getTimestampParser
(
ConfigParam
.
TO_TIMESTAMP
,
input
,
format
);
return
parser
.
getResultingValue
();
}
/**
* Parse a string as a timestamp with the given format.
*
* @param input the input
* @param format the format
* @return the timestamp
*/
public
static
ValueTimestampTimeZone
toTimestampTz
(
String
input
,
String
format
)
{
ToDateParser
parser
=
getTimestampParser
(
ConfigParam
.
TO_TIMESTAMP_TZ
,
input
,
format
);
return
parser
.
getResultingValueWithTimeZone
();
}
/**
...
...
@@ -192,9 +353,9 @@ public class ToDateParser {
* @param format the format
* @return the date as a timestamp
*/
public
static
Timestamp
toDate
(
String
input
,
String
format
)
{
ToDateParser
parser
=
get
DateParser
(
input
,
format
);
return
parser
.
getResulting
Timestamp
();
public
static
Value
Timestamp
toDate
(
String
input
,
String
format
)
{
ToDateParser
parser
=
get
TimestampParser
(
ConfigParam
.
TO_DATE
,
input
,
format
);
return
parser
.
getResulting
Value
();
}
/**
...
...
@@ -202,7 +363,8 @@ public class ToDateParser {
*/
private
enum
ConfigParam
{
TO_DATE
(
"DD MON YYYY"
),
TO_TIMESTAMP
(
"DD MON YYYY HH:MI:SS"
);
TO_TIMESTAMP
(
"DD MON YYYY HH:MI:SS"
),
TO_TIMESTAMP_TZ
(
"DD MON YYYY HH:MI:SS TZR"
);
private
final
String
defaultFormatStr
;
ConfigParam
(
String
defaultFormatStr
)
{
...
...
h2/src/main/org/h2/util/ToDateTokenizer.java
浏览文件 @
778748d1
...
...
@@ -6,17 +6,12 @@
package
org
.
h2
.
util
;
import
static
java
.
lang
.
String
.
format
;
import
java.text.ParseException
;
import
java.text.SimpleDateFormat
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Calendar
;
import
java.util.Collections
;
import
java.util.Date
;
import
java.util.GregorianCalendar
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Locale
;
import
java.util.Map
;
import
java.util.TimeZone
;
import
java.util.regex.Matcher
;
...
...
@@ -144,10 +139,10 @@ class ToDateTokenizer {
* Parslet responsible for parsing year parameter
*/
static
class
YearParslet
implements
ToDateParslet
{
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
...
...
@@ -156,26 +151,26 @@ class ToDateTokenizer {
case
IYYY:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_FOUR_DIGITS
,
params
,
formatTokenEnum
);
// only necessary for Java1.6
if
(
inputFragmentStr
.
startsWith
(
"+"
))
{
inputFragmentStr
=
inputFragmentStr
.
substring
(
1
);
}
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
if
(
dateNr
==
0
)
{
throwException
(
params
,
"Year may not be zero"
);
}
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
params
.
setYear
(
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
case
YYY:
case
IYY:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_THREE_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
if
(
dateNr
>
999
)
{
throwException
(
params
,
"Year may have only three digits with specified format"
);
}
dateNr
+=
(
params
.
getCurrentYear
()
/
1_000
)
*
1_000
;
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
params
.
setYear
(
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
case
RRRR:
inputFragmentStr
=
matchStringOrThrow
(
...
...
@@ -191,15 +186,14 @@ class ToDateTokenizer {
if
(
dateNr
==
0
)
{
throwException
(
params
,
"Year may not be zero"
);
}
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
params
.
setYear
(
dateNr
);
break
;
case
RR:
Calendar
calendar
=
DateTimeUtils
.
createGregorianCalendar
();
int
cc
=
calendar
.
get
(
Calendar
.
YEAR
)
/
100
;
int
cc
=
params
.
getCurrentYear
()
/
100
;
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
)
+
cc
*
100
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
params
.
setYear
(
dateNr
);
break
;
case
EE
/* NOT supported yet */
:
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
...
...
@@ -214,34 +208,38 @@ class ToDateTokenizer {
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
if
(
dateNr
>
99
)
{
throwException
(
params
,
"Year may have only two digits with specified format"
);
}
dateNr
+=
(
params
.
getCurrentYear
()
/
100
)
*
100
;
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
params
.
setYear
(
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
case
SCC:
case
CC:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
)
*
100
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
params
.
setYear
(
dateNr
);
break
;
case
Y:
case
I:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
if
(
dateNr
>
9
)
{
throwException
(
params
,
"Year may have only two digits with specified format"
);
}
dateNr
+=
(
params
.
getCurrentYear
()
/
10
)
*
10
;
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
params
.
setYear
(
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
case
BC_AD:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_BC_AD
,
params
,
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"B"
))
{
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
BC
);
}
else
{
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
AD
);
}
params
.
setBC
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"B"
));
break
;
default
:
throw
new
IllegalArgumentException
(
format
(
...
...
@@ -262,29 +260,26 @@ class ToDateTokenizer {
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
s
=
params
.
getInputStr
();
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
case
MONTH:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
Calendar
.
LONG
);
inputFragmentStr
=
setByName
(
params
,
ToChar
.
MONTHS
);
break
;
case
Q
/* NOT supported yet */
:
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
break
;
case
MON:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
Calendar
.
SHORT
);
inputFragmentStr
=
setByName
(
params
,
ToChar
.
SHORT_MONTHS
);
break
;
case
MM:
// Note: In Calendar Month go from 0 - 11
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
MONTH
,
dateNr
-
1
);
params
.
setMonth
(
dateNr
);
break
;
case
RM:
dateNr
=
0
;
...
...
@@ -293,7 +288,7 @@ class ToDateTokenizer {
int
len
=
monthName
.
length
();
if
(
s
.
length
()
>=
len
&&
monthName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
)))
{
result
.
set
(
Calendar
.
MONTH
,
dateNr
);
params
.
setMonth
(
dateNr
+
1
);
inputFragmentStr
=
monthName
;
break
;
}
...
...
@@ -322,7 +317,6 @@ class ToDateTokenizer {
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
...
...
@@ -330,40 +324,31 @@ class ToDateTokenizer {
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_YEAR
,
dateNr
);
params
.
setDayOfYear
(
dateNr
);
break
;
case
DD:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
params
.
setDay
(
dateNr
);
break
;
case
D:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
params
.
setDay
(
dateNr
);
break
;
case
DAY:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
DAY_OF_WEEK
,
Calendar
.
LONG
);
inputFragmentStr
=
setByName
(
params
,
ToChar
.
WEEKDAYS
);
break
;
case
DY:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
DAY_OF_WEEK
,
Calendar
.
SHORT
);
inputFragmentStr
=
setByName
(
params
,
ToChar
.
SHORT_WEEKDAYS
);
break
;
case
J:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
try
{
Date
date
=
new
SimpleDateFormat
(
"Myydd"
)
.
parse
(
inputFragmentStr
);
result
.
setTime
(
date
);
}
catch
(
ParseException
e
)
{
throwException
(
params
,
format
(
"Failed to parse Julian date: %s"
,
inputFragmentStr
));
}
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
params
.
setAbsoluteDay
(
dateNr
+
ToChar
.
JULIAN_EPOCH
);
break
;
default
:
throw
new
IllegalArgumentException
(
format
(
...
...
@@ -382,7 +367,6 @@ class ToDateTokenizer {
@Override
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
)
{
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
...
...
@@ -390,97 +374,76 @@ class ToDateTokenizer {
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
dateNr
);
params
.
setHour
(
dateNr
);
break
;
case
HH12:
case
HH:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR
,
dateNr
);
params
.
setHour12
(
dateNr
);
break
;
case
MI:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
MINUTE
,
dateNr
);
params
.
setMinute
(
dateNr
);
break
;
case
SS:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
params
.
setSecord
(
dateNr
);
break
;
case
SSSSS:
case
SSSSS:
{
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
0
);
result
.
set
(
Calendar
.
MINUTE
,
0
);
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
int
second
=
dateNr
%
60
;
dateNr
/=
60
;
int
minute
=
dateNr
%
60
;
dateNr
/=
60
;
int
hour
=
dateNr
%
24
;
params
.
setHour
(
hour
);
params
.
setMinute
(
minute
);
params
.
setSecord
(
second
);
break
;
}
case
FF:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
String
paddedRightNrStr
=
format
(
"%-9s"
,
inputFragmentStr
)
.
replace
(
' '
,
'0'
);
paddedRightNrStr
=
paddedRightNrStr
.
substring
(
0
,
9
);
Double
nineDigits
=
Double
.
parseDouble
(
paddedRightNrStr
);
params
.
setNanos
(
nineDigits
.
intValue
());
dateNr
=
(
int
)
Math
.
round
(
nineDigits
/
1000000.0
);
result
.
set
(
Calendar
.
MILLISECOND
,
dateNr
);
double
nineDigits
=
Double
.
parseDouble
(
paddedRightNrStr
);
params
.
setNanos
((
int
)
nineDigits
);
break
;
case
AM_PM:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_AM_PM
,
params
,
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"A"
))
{
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
AM
);
params
.
setAmPm
(
true
);
}
else
{
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
PM
);
params
.
setAmPm
(
false
);
}
break
;
case
TZH:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
TimeZone
tz
=
result
.
getTimeZone
();
int
offsetMillis
=
tz
.
getRawOffset
();
// purge min and sec
offsetMillis
=
(
offsetMillis
/
MILLIS_IN_HOUR
)
*
MILLIS_IN_HOUR
;
tz
.
setRawOffset
(
offsetMillis
+
dateNr
);
result
.
setTimeZone
(
tz
);
params
.
setTimeZoneHour
(
dateNr
);
break
;
case
TZM:
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
Integer
.
parseInt
(
inputFragmentStr
);
tz
=
result
.
getTimeZone
();
offsetMillis
=
tz
.
getRawOffset
();
// purge hour
offsetMillis
=
offsetMillis
%
MILLIS_IN_HOUR
;
tz
.
setRawOffset
(
dateNr
*
MILLIS_IN_HOUR
+
offsetMillis
);
result
.
setTimeZone
(
tz
);
params
.
setTimeZoneMinute
(
dateNr
);
break
;
case
TZR:
// Example: US/Pacific
String
s
=
params
.
getInputStr
();
tz
=
result
.
getTimeZone
();
for
(
String
tzName
:
TimeZone
.
getAvailableIDs
())
{
int
length
=
tzName
.
length
();
if
(
s
.
length
()
>=
length
&&
tzName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
length
)))
{
tz
.
setID
(
tzName
);
result
.
setTimeZone
(
tz
);
inputFragmentStr
=
tzName
;
break
;
}
}
break
;
case
TZD:
// Must correspond with TZR region. Example: PST (for US/Pacific
// standard time)
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
String
tzName
=
params
.
getInputStr
();
params
.
setTimeZone
(
TimeZone
.
getTimeZone
(
tzName
));
inputFragmentStr
=
tzName
;
break
;
default
:
throw
new
IllegalArgumentException
(
format
(
...
...
@@ -535,22 +498,33 @@ class ToDateTokenizer {
/**
* Set the given field in the calendar.
*
* @param c the calendar
* @param params the parameters with the input string
* @param field the field to set
* @param style the data type
* @return the matched value
*/
static
String
setByName
(
Calendar
c
,
ToDateParser
params
,
int
field
,
int
style
)
{
static
String
setByName
(
ToDateParser
params
,
int
field
)
{
String
inputFragmentStr
=
null
;
String
s
=
params
.
getInputStr
();
Map
<
String
,
Integer
>
timeStringMap
=
c
.
getDisplayNames
(
field
,
style
,
Locale
.
getDefault
());
for
(
String
dayName
:
timeStringMap
.
keySet
())
{
String
[]
values
=
ToChar
.
getNames
(
field
);
for
(
int
i
=
0
;
i
<
values
.
length
;
i
++)
{
String
dayName
=
values
[
i
];
if
(
dayName
==
null
)
{
continue
;
}
int
len
=
dayName
.
length
();
if
(
dayName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
)))
{
c
.
set
(
field
,
timeStringMap
.
get
(
dayName
));
switch
(
field
)
{
case
ToChar
.
MONTHS
:
case
ToChar
.
SHORT_MONTHS
:
params
.
setMonth
(
i
+
1
);
break
;
case
ToChar
.
WEEKDAYS
:
case
ToChar
.
SHORT_WEEKDAYS
:
// TODO
break
;
default
:
throw
new
IllegalArgumentException
();
}
inputFragmentStr
=
dayName
;
break
;
}
...
...
@@ -558,7 +532,7 @@ class ToDateTokenizer {
if
(
inputFragmentStr
==
null
||
inputFragmentStr
.
isEmpty
())
{
throwException
(
params
,
format
(
"Tried to parse one of '%s' but failed (may be an internal error?)"
,
timeStringMap
.
keySet
(
)));
Arrays
.
toString
(
values
)));
}
return
inputFragmentStr
;
}
...
...
h2/src/test/org/h2/test/db/TestFunctions.java
浏览文件 @
778748d1
...
...
@@ -34,6 +34,7 @@ import java.util.ArrayList;
import
java.util.Calendar
;
import
java.util.Currency
;
import
java.util.Date
;
import
java.util.GregorianCalendar
;
import
java.util.HashMap
;
import
java.util.Locale
;
import
java.util.Properties
;
...
...
@@ -56,6 +57,8 @@ import org.h2.util.StringUtils;
import
org.h2.util.ToChar.Capitalization
;
import
org.h2.util.ToDateParser
;
import
org.h2.value.Value
;
import
org.h2.value.ValueTimestamp
;
import
org.h2.value.ValueTimestampTimeZone
;
/**
* Tests for user defined functions and aggregates.
...
...
@@ -1296,10 +1299,13 @@ public class TestFunctions extends TestBase implements AggregateFunction {
}
private
void
testToDate
()
throws
ParseException
{
final
int
month
=
DateTimeUtils
.
createGregorianCalendar
().
get
(
Calendar
.
MONTH
);
Date
date
=
null
;
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1979-11-12"
);
GregorianCalendar
calendar
=
DateTimeUtils
.
createGregorianCalendar
();
int
year
=
calendar
.
get
(
Calendar
.
YEAR
);
int
month
=
calendar
.
get
(
Calendar
.
MONTH
)
+
1
;
// Default date in Oracle is the first day of the current month
String
defDate
=
year
+
"-"
+
month
+
"-1 "
;
ValueTimestamp
date
=
null
;
date
=
ValueTimestamp
.
parse
(
"1979-11-12"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979-11-12T00:00:00Z"
,
"YYYY-MM-DD\"T\"HH24:MI:SS\"Z\""
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979*foo*1112"
,
"YYYY\"*foo*\"MM\"\"DD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979-11-12"
,
"YYYY-MM-DD"
));
...
...
@@ -1309,8 +1315,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979;11;12"
,
"YYYY;MM;DD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979:11:12"
,
"YYYY:MM:DD"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"1979"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
"1979-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979"
,
"YYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979 AD"
,
"YYYY AD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1979 A.D."
,
"YYYY A.D."
));
...
...
@@ -1319,116 +1324,119 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertEquals
(
date
,
ToDateParser
.
toDate
(
"+1979"
,
"SYYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"79"
,
"RRRR"
));
date
=
new
SimpleDateFormat
(
"yyyy-mm"
).
parse
(
"1970-12"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"00:12:00"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"12"
,
"MI"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM"
).
parse
(
"1970-1
1"
);
date
=
ValueTimestamp
.
parse
(
"1970-11-0
1"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"MM"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"Mm"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"mM"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"11"
,
"mm"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"XI"
,
"RM"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"9"
)
;
setMonth
(
date
,
month
);
int
y
=
(
year
/
10
)
*
10
+
9
;
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"9"
,
"Y"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"9"
,
"I"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"79"
)
;
setMonth
(
date
,
month
);
y
=
(
year
/
100
)
*
100
+
79
;
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"79"
,
"YY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"79"
,
"IY"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"979"
);
setMonth
(
date
,
month
);
y
=
(
year
/
1_000
)
*
1_000
+
979
;
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"979"
,
"YYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"979"
,
"IYY"
));
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
date
=
new
SimpleDateFormat
(
"yyy"
).
parse
(
"-99"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
"-99-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"0100 BC"
,
"YYYY BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"0100 B.C."
,
"YYYY B.C."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"100 BC"
,
"YYY BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"-0100"
,
"SYYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"-0100"
,
"YYYY"
));
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
date
=
new
SimpleDateFormat
(
"y"
).
parse
(
"0"
);
setMonth
(
date
,
month
);
y
=
-((
year
/
1_000
)
*
1_000
+
99
);
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"100 BC"
,
"YYY BC"
));
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
y
=
-((
year
/
100
)
*
100
);
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"01 BC"
,
"YY BC"
));
y
=
-((
year
/
10
)
*
10
);
date
=
ValueTimestamp
.
parse
(
y
+
"-"
+
month
+
"-01"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"1 BC"
,
"Y BC"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:00"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12 AM"
,
"HH:MI AM"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12 A.M."
,
"HH:MI A.M."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12"
,
"HH24:MI"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:00"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12"
,
"HH:MI"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12"
,
"HH12:MI"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:34"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:34"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34"
,
"HH:MI:SS"
));
date
=
new
SimpleDateFormat
(
"ss"
).
parse
(
"34"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"12:00:00"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"12:00:00 PM"
,
"HH12:MI:SS AM"
));
date
=
ValueTimestamp
.
parse
(
defDate
+
"00:00:00"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"12:00:00 AM"
,
"HH12:MI:SS AM"
));
date
=
ValueTimestamp
.
parse
(
defDate
+
"00:00:34"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"34"
,
"SS"
));
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss"
).
parse
(
"1970 08:12:34"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:34"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"29554"
,
"SSSSS"
));
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss SSS"
).
parse
(
"1970 08:12:34 550"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"08:12:34.550"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34 550"
,
"HH:MI:SS FF"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"08:12:34 55"
,
"HH:MI:SS FF2"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"14:04:00"
);
setMonth
(
date
,
month
);
date
=
ValueTimestamp
.
parse
(
defDate
+
"14:04:00"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"02:04 P.M."
,
"HH:MI p.M."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"02:04 PM"
,
"HH:MI PM"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1970-12-12"
);
// does not work in all timezones
// assertEquals(date, ToDateParser.toDate("12", "DD"));
date
=
ValueTimestamp
.
parse
(
"1970-"
+
month
+
"-12"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"12"
,
"DD"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1970-11-12"
);
date
=
ValueTimestamp
.
parse
(
year
+
(
calendar
.
isLeapYear
(
year
)
?
"11-11"
:
"-11-12"
)
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"DDD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"DdD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"dDD"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"316"
,
"ddd"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
)
.
parse
(
"2013-01-29"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"
113029
"
,
"J"
));
date
=
ValueTimestamp
.
parse
(
"2013-01-29"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"
2456322
"
,
"J"
));
if
(
Locale
.
getDefault
()
==
Locale
.
ENGLISH
)
{
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd'T'HH:mm:ss"
).
parse
(
"9999-12-31T
23:59:59"
);
if
(
Locale
.
getDefault
()
.
getLanguage
().
equals
(
"en"
)
)
{
date
=
ValueTimestamp
.
parse
(
"9999-12-31
23:59:59"
);
assertEquals
(
date
,
ToDateParser
.
toDate
(
"31-DEC-9999 23:59:59"
,
"DD-MON-YYYY HH24:MI:SS"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"31-DEC-9999 23:59:59"
,
"DD-MON-RRRR HH24:MI:SS"
));
SimpleDateFormat
ymd
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
);
assertEquals
(
ymd
.
parse
(
"0001-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-0001"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"9999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-9999"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"2000-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-000"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"1999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-099"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"0100-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-100"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"2000-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-00"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"2049-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-49"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"1950-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-50"
,
"DD-MON-RRRR"
));
assertEquals
(
ymd
.
parse
(
"1999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-99"
,
"DD-MON-RRRR"
));
}
}
private
static
void
setMonth
(
Date
date
,
int
month
)
{
Calendar
c
=
DateTimeUtils
.
createGregorianCalendar
();
c
.
setTime
(
date
);
c
.
set
(
Calendar
.
MONTH
,
month
);
date
.
setTime
(
c
.
getTimeInMillis
());
assertEquals
(
ValueTimestamp
.
parse
(
"0001-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-0001"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"9999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-9999"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"2000-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-000"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"1999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-099"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"0100-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-100"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"2000-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-00"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"2049-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-49"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"1950-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-50"
,
"DD-MON-RRRR"
));
assertEquals
(
ValueTimestamp
.
parse
(
"1999-03-01"
),
ToDateParser
.
toDate
(
"1-MAR-99"
,
"DD-MON-RRRR"
));
}
assertEquals
(
ValueTimestampTimeZone
.
parse
(
"2000-05-10 10:11:12-08:15"
),
ToDateParser
.
toTimestampTz
(
"2000-05-10 10:11:12 -8:15"
,
"YYYY-MM-DD HH24:MI:SS TZH:TZM"
));
assertEquals
(
ValueTimestampTimeZone
.
parse
(
"2000-05-10 10:11:12-08:15"
),
ToDateParser
.
toTimestampTz
(
"2000-05-10 10:11:12 GMT-08:15"
,
"YYYY-MM-DD HH24:MI:SS TZR"
));
assertEquals
(
ValueTimestampTimeZone
.
parse
(
"2000-02-10 10:11:12-08"
),
ToDateParser
.
toTimestampTz
(
"2000-02-10 10:11:12 US/Pacific"
,
"YYYY-MM-DD HH24:MI:SS TZR"
));
assertEquals
(
ValueTimestampTimeZone
.
parse
(
"2000-02-10 10:11:12-08"
),
ToDateParser
.
toTimestampTz
(
"2000-02-10 10:11:12 PST"
,
"YYYY-MM-DD HH24:MI:SS TZD"
));
}
private
void
testToCharFromDateTime
()
throws
SQLException
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论