Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
19556a3e
提交
19556a3e
authored
1月 13, 2016
作者:
Erwan Bocher
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'master' of
https://github.com/h2database/h2database
into updateJTS
上级
2ff8f838
00a1b0e2
显示空白字符变更
内嵌
并排
正在显示
16 个修改的文件
包含
583 行增加
和
449 行删除
+583
-449
Function.java
h2/src/main/org/h2/expression/Function.java
+13
-3
JoinBatch.java
h2/src/main/org/h2/table/JoinBatch.java
+3
-3
DateTimeUtils.java
h2/src/main/org/h2/util/DateTimeUtils.java
+4
-1
ToDate.java
h2/src/main/org/h2/util/ToDate.java
+0
-19
ToDateParser.java
h2/src/main/org/h2/util/ToDateParser.java
+79
-61
ToDateTokenizer.java
h2/src/main/org/h2/util/ToDateTokenizer.java
+336
-229
Value.java
h2/src/main/org/h2/value/Value.java
+1
-1
ValueTimestampUtc.java
h2/src/main/org/h2/value/ValueTimestampUtc.java
+3
-3
ToDate.java
h2/src/test/org/h2/samples/ToDate.java
+16
-10
TestFunctions.java
h2/src/test/org/h2/test/db/TestFunctions.java
+82
-72
TestOptimizations.java
h2/src/test/org/h2/test/db/TestOptimizations.java
+15
-15
TestTableEngines.java
h2/src/test/org/h2/test/db/TestTableEngines.java
+18
-18
TestDate.java
h2/src/test/org/h2/test/unit/TestDate.java
+2
-1
TestTimeStampUtc.java
h2/src/test/org/h2/test/unit/TestTimeStampUtc.java
+3
-3
BuildBase.java
h2/src/tools/org/h2/build/BuildBase.java
+3
-3
dictionary.txt
h2/src/tools/org/h2/build/doc/dictionary.txt
+5
-7
没有找到文件。
h2/src/main/org/h2/expression/Function.java
浏览文件 @
19556a3e
...
@@ -44,7 +44,17 @@ import org.h2.table.Table;
...
@@ -44,7 +44,17 @@ import org.h2.table.Table;
import
org.h2.table.TableFilter
;
import
org.h2.table.TableFilter
;
import
org.h2.tools.CompressTool
;
import
org.h2.tools.CompressTool
;
import
org.h2.tools.Csv
;
import
org.h2.tools.Csv
;
import
org.h2.util.*
;
import
org.h2.util.AutoCloseInputStream
;
import
org.h2.util.DateTimeUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.JdbcUtils
;
import
org.h2.util.MathUtils
;
import
org.h2.util.New
;
import
org.h2.util.StatementBuilder
;
import
org.h2.util.StringUtils
;
import
org.h2.util.ToChar
;
import
org.h2.util.ToDateParser
;
import
org.h2.util.Utils
;
import
org.h2.value.DataType
;
import
org.h2.value.DataType
;
import
org.h2.value.Value
;
import
org.h2.value.Value
;
import
org.h2.value.ValueArray
;
import
org.h2.value.ValueArray
;
...
@@ -1424,11 +1434,11 @@ public class Function extends Expression implements FunctionCall {
...
@@ -1424,11 +1434,11 @@ public class Function extends Expression implements FunctionCall {
}
}
break
;
break
;
case
TO_DATE:
case
TO_DATE:
result
=
ValueTimestamp
.
get
(
ToDate
.
TO_DATE
(
v0
.
getString
(),
result
=
ValueTimestamp
.
get
(
ToDate
Parser
.
toDate
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
()));
v1
==
null
?
null
:
v1
.
getString
()));
break
;
break
;
case
TO_TIMESTAMP:
case
TO_TIMESTAMP:
result
=
ValueTimestamp
.
get
(
ToDate
.
TO_TIMESTAMP
(
v0
.
getString
(),
result
=
ValueTimestamp
.
get
(
ToDate
Parser
.
toTimestamp
(
v0
.
getString
(),
v1
==
null
?
null
:
v1
.
getString
()));
v1
==
null
?
null
:
v1
.
getString
()));
break
;
break
;
case
TRANSLATE:
{
case
TRANSLATE:
{
...
...
h2/src/main/org/h2/table/JoinBatch.java
浏览文件 @
19556a3e
...
@@ -410,9 +410,9 @@ public final class JoinBatch {
...
@@ -410,9 +410,9 @@ public final class JoinBatch {
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
"JoinBatch->\nprev->"
+
(
current
==
null
?
null
:
current
.
prev
)
+
return
"JoinBatch->\n
"
+
"
prev->"
+
(
current
==
null
?
null
:
current
.
prev
)
+
"\ncurr->"
+
current
+
"\n
"
+
"
curr->"
+
current
+
"\nnext->"
+
(
current
==
null
?
null
:
current
.
next
);
"\n
"
+
"
next->"
+
(
current
==
null
?
null
:
current
.
next
);
}
}
/**
/**
...
...
h2/src/main/org/h2/util/DateTimeUtils.java
浏览文件 @
19556a3e
...
@@ -11,7 +11,10 @@ import java.sql.Date;
...
@@ -11,7 +11,10 @@ import java.sql.Date;
import
java.sql.Time
;
import
java.sql.Time
;
import
java.sql.Timestamp
;
import
java.sql.Timestamp
;
import
java.text.SimpleDateFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.*
;
import
java.util.Calendar
;
import
java.util.GregorianCalendar
;
import
java.util.Locale
;
import
java.util.TimeZone
;
import
org.h2.api.ErrorCode
;
import
org.h2.api.ErrorCode
;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
...
...
h2/src/main/org/h2/util/ToDate.java
deleted
100644 → 0
浏览文件 @
2ff8f838
package
org
.
h2
.
util
;
import
java.sql.Timestamp
;
import
java.util.Date
;
/**
* Emulates Oracle's TO_DATE function.<br>
* Main class
*/
public
class
ToDate
{
public
static
Timestamp
TO_DATE
(
final
String
input
,
final
String
format
)
{
ToDateParser
parser
=
ToDateParser
.
toDate
(
input
,
format
);
return
parser
.
getResultingTimestamp
();
}
public
static
Timestamp
TO_TIMESTAMP
(
final
String
input
,
final
String
format
)
{
ToDateParser
parser
=
ToDateParser
.
toTimestamp
(
input
,
format
);
return
parser
.
getResultingTimestamp
();
}
}
\ No newline at end of file
h2/src/main/org/h2/util/ToDateParser.java
浏览文件 @
19556a3e
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: Daniel Gredler
*/
package
org
.
h2
.
util
;
package
org
.
h2
.
util
;
import
static
java
.
lang
.
String
.
format
;
import
static
java
.
lang
.
String
.
format
;
import
java.sql.Timestamp
;
import
java.sql.Timestamp
;
import
java.util.Calendar
;
import
java.util.Calendar
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.List
;
/**
/**
* Emulates Oracle's TO_DATE function.<br>
* Emulates Oracle's TO_DATE function.<br>
* This class holds and handles the input data form the TO_DATE-method
* This class holds and handles the input data form the TO_DATE-method
*/
*/
class
ToDateParser
{
public
class
ToDateParser
{
private
final
String
unmodifiedInputStr
;
private
final
String
unmodifiedInputStr
;
private
final
String
unmodifiedFormatStr
;
private
final
String
unmodifiedFormatStr
;
private
final
ConfigParam
functionName
;
private
final
ConfigParam
functionName
;
private
String
inputStr
;
private
String
inputStr
;
private
String
formatStr
;
private
String
formatStr
;
private
final
Calendar
resultCalendar
=
(
Calendar
)
Calendar
.
getInstance
().
clone
();
private
final
Calendar
resultCalendar
=
(
Calendar
)
Calendar
.
getInstance
().
clone
();
private
Integer
nanos
=
null
;
private
Integer
nanos
;
private
enum
ConfigParam
{
TO_DATE
(
"DD MON YYYY"
),
TO_TIMESTAMP
(
"DD MON YYYY HH:MI:SS"
);
private
final
String
defaultFormatStr
;
ConfigParam
(
final
String
defaultFormatStr
)
{
this
.
defaultFormatStr
=
defaultFormatStr
;
}
String
getDefaultFormatStr
()
{
return
defaultFormatStr
;
}
}
static
ToDateParser
toDate
(
final
String
input
,
final
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_DATE
,
input
,
format
);
parse
(
result
);
return
result
;
}
static
ToDateParser
toTimestamp
(
final
String
input
,
final
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_TIMESTAMP
,
input
,
format
);
parse
(
result
);
return
result
;
}
/**
/**
* @param input the input date with the date-time info
* @param input the input date with the date-time info
* @param format the format of date-time info
* @param format the format of date-time info
* @param functionName one of [TO_DATE, TO_TIMESTAMP] (both share the same code)
* @param functionName one of [TO_DATE, TO_TIMESTAMP] (both share the same
* code)
*/
*/
ToDateParser
(
final
ConfigParam
functionName
,
final
String
input
,
final
String
format
)
{
private
ToDateParser
(
ConfigParam
functionName
,
String
input
,
String
format
)
{
// reset calendar - default oracle behaviour
// reset calendar - default oracle behaviour
resultCalendar
.
set
(
Calendar
.
YEAR
,
1970
);
resultCalendar
.
set
(
Calendar
.
YEAR
,
1970
);
resultCalendar
.
set
(
Calendar
.
MONTH
,
Calendar
.
getInstance
().
get
(
Calendar
.
MONTH
));
resultCalendar
.
set
(
Calendar
.
MONTH
,
Calendar
.
getInstance
().
get
(
Calendar
.
MONTH
));
...
@@ -65,18 +47,34 @@ class ToDateParser {
...
@@ -65,18 +47,34 @@ class ToDateParser {
this
.
functionName
=
functionName
;
this
.
functionName
=
functionName
;
inputStr
=
input
.
trim
();
inputStr
=
input
.
trim
();
unmodifiedInputStr
=
inputStr
;
// Keep a copy
// Keep a copy
unmodifiedInputStr
=
inputStr
;
if
(
format
==
null
||
format
.
isEmpty
())
{
if
(
format
==
null
||
format
.
isEmpty
())
{
formatStr
=
functionName
.
getDefaultFormatStr
();
// default Oracle format.
// default Oracle format.
formatStr
=
functionName
.
getDefaultFormatStr
();
}
else
{
}
else
{
formatStr
=
format
.
trim
();
formatStr
=
format
.
trim
();
}
}
unmodifiedFormatStr
=
formatStr
;
// Keep a copy
// Keep a copy
unmodifiedFormatStr
=
formatStr
;
}
private
static
ToDateParser
getDateParser
(
String
input
,
String
format
)
{
ToDateParser
result
=
new
ToDateParser
(
ConfigParam
.
TO_DATE
,
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
;
}
}
Timestamp
getResultingTimestamp
()
{
private
Timestamp
getResultingTimestamp
()
{
Calendar
cal
=
(
Calendar
)
getResultCalendar
().
clone
();
Calendar
cal
=
(
Calendar
)
getResultCalendar
().
clone
();
int
nanosToSet
=
nanos
==
null
?
cal
.
get
(
Calendar
.
MILLISECOND
)
*
1000000
:
nanos
.
intValue
();
int
nanosToSet
=
nanos
==
null
?
cal
.
get
(
Calendar
.
MILLISECOND
)
*
1000000
:
nanos
.
intValue
();
cal
.
set
(
Calendar
.
MILLISECOND
,
0
);
cal
.
set
(
Calendar
.
MILLISECOND
,
0
);
Timestamp
ts
=
new
Timestamp
(
cal
.
getTimeInMillis
());
Timestamp
ts
=
new
Timestamp
(
cal
.
getTimeInMillis
());
ts
.
setNanos
(
nanosToSet
);
ts
.
setNanos
(
nanosToSet
);
...
@@ -99,15 +97,15 @@ class ToDateParser {
...
@@ -99,15 +97,15 @@ class ToDateParser {
return
functionName
.
name
();
return
functionName
.
name
();
}
}
void
setNanos
(
final
int
nanos
)
{
void
setNanos
(
int
nanos
)
{
this
.
nanos
=
nanos
;
this
.
nanos
=
nanos
;
}
}
boolean
hasToParseData
()
{
private
boolean
hasToParseData
()
{
return
formatStr
.
length
()
>
0
;
return
formatStr
.
length
()
>
0
;
}
}
void
removeFirstChar
()
{
private
void
removeFirstChar
()
{
if
(!
formatStr
.
isEmpty
())
{
if
(!
formatStr
.
isEmpty
())
{
formatStr
=
formatStr
.
substring
(
1
);
formatStr
=
formatStr
.
substring
(
1
);
}
}
...
@@ -116,9 +114,10 @@ class ToDateParser {
...
@@ -116,9 +114,10 @@ class ToDateParser {
}
}
}
}
private
static
ToDateParser
parse
(
final
ToDateParser
p
)
{
private
static
ToDateParser
parse
(
ToDateParser
p
)
{
while
(
p
.
hasToParseData
())
{
while
(
p
.
hasToParseData
())
{
List
<
ToDateTokenizer
.
FormatTokenEnum
>
tokenList
=
ToDateTokenizer
.
FormatTokenEnum
.
getTokensInQuestion
(
p
.
getFormatStr
());
List
<
ToDateTokenizer
.
FormatTokenEnum
>
tokenList
=
ToDateTokenizer
.
FormatTokenEnum
.
getTokensInQuestion
(
p
.
getFormatStr
());
if
(
tokenList
.
isEmpty
())
{
if
(
tokenList
.
isEmpty
())
{
p
.
removeFirstChar
();
p
.
removeFirstChar
();
continue
;
continue
;
...
@@ -138,19 +137,9 @@ class ToDateParser {
...
@@ -138,19 +137,9 @@ class ToDateParser {
return
p
;
return
p
;
}
}
void
remove
(
final
String
toIgnore
)
{
void
remove
(
String
inputFragmentStr
,
String
formatFragment
)
{
if
(
toIgnore
!=
null
)
{
if
(
inputFragmentStr
!=
null
&&
inputStr
.
length
()
>=
inputFragmentStr
.
length
())
{
int
trimLeng
=
toIgnore
.
length
();
inputStr
=
inputStr
.
substring
(
inputFragmentStr
.
length
());
formatStr
=
formatStr
.
substring
(
trimLeng
);
if
(
inputStr
.
length
()
>=
trimLeng
)
{
inputStr
=
inputStr
.
substring
(
trimLeng
);
}
}
}
void
remove
(
final
String
intputFragmentStr
,
final
String
formatFragment
)
{
if
(
intputFragmentStr
!=
null
&&
inputStr
.
length
()
>=
intputFragmentStr
.
length
())
{
inputStr
=
inputStr
.
substring
(
intputFragmentStr
.
length
());
}
}
if
(
formatFragment
!=
null
&&
formatStr
.
length
()
>=
formatFragment
.
length
())
{
if
(
formatFragment
!=
null
&&
formatStr
.
length
()
>=
formatFragment
.
length
())
{
formatStr
=
formatStr
.
substring
(
formatFragment
.
length
());
formatStr
=
formatStr
.
substring
(
formatFragment
.
length
());
...
@@ -159,21 +148,50 @@ class ToDateParser {
...
@@ -159,21 +148,50 @@ class ToDateParser {
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
int
inputStrLen
g
=
inputStr
.
length
();
int
inputStrLen
=
inputStr
.
length
();
int
orgInputLen
g
=
unmodifiedInputStr
.
length
();
int
orgInputLen
=
unmodifiedInputStr
.
length
();
int
currentInputPos
=
orgInputLen
g
-
inputStrLeng
;
int
currentInputPos
=
orgInputLen
-
inputStrLen
;
int
restInputLen
g
=
inputStrLeng
<=
0
?
inputStrLeng
:
inputStrLeng
-
1
;
int
restInputLen
=
inputStrLen
<=
0
?
inputStrLen
:
inputStrLen
-
1
;
int
orgFormatLen
g
=
unmodifiedFormatStr
.
length
();
int
orgFormatLen
=
unmodifiedFormatStr
.
length
();
int
currentFormatPos
=
orgFormatLen
g
-
formatStr
.
length
();
int
currentFormatPos
=
orgFormatLen
-
formatStr
.
length
();
StringBuilder
sb
=
new
StringBuilder
();
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
format
(
"\n %s('%s', '%s')"
,
functionName
,
unmodifiedInputStr
,
unmodifiedFormatStr
));
sb
.
append
(
format
(
"\n %s('%s', '%s')"
,
functionName
,
sb
.
append
(
format
(
"\n %s^%s , %s^ <-- Parsing failed at this point"
,
//
unmodifiedInputStr
,
unmodifiedFormatStr
));
sb
.
append
(
format
(
"\n %s^%s , %s^ <-- Parsing failed at this point"
,
format
(
"%"
+
(
functionName
.
name
().
length
()
+
currentInputPos
)
+
"s"
,
""
),
format
(
"%"
+
(
functionName
.
name
().
length
()
+
currentInputPos
)
+
"s"
,
""
),
restInputLen
g
<=
0
?
""
:
format
(
"%"
+
restInputLeng
+
"s"
,
""
),
restInputLen
<=
0
?
""
:
format
(
"%"
+
restInputLen
+
"s"
,
""
),
currentFormatPos
<=
0
?
""
:
format
(
"%"
+
currentFormatPos
+
"s"
,
""
)));
currentFormatPos
<=
0
?
""
:
format
(
"%"
+
currentFormatPos
+
"s"
,
""
)));
return
sb
.
toString
();
return
sb
.
toString
();
}
}
public
static
Timestamp
toTimestamp
(
String
input
,
String
format
)
{
ToDateParser
parser
=
getTimestampParser
(
input
,
format
);
return
parser
.
getResultingTimestamp
();
}
public
static
Timestamp
toDate
(
String
input
,
String
format
)
{
ToDateParser
parser
=
getDateParser
(
input
,
format
);
return
parser
.
getResultingTimestamp
();
}
/**
* The configuration of the date parser.
*/
private
enum
ConfigParam
{
TO_DATE
(
"DD MON YYYY"
),
TO_TIMESTAMP
(
"DD MON YYYY HH:MI:SS"
);
private
final
String
defaultFormatStr
;
ConfigParam
(
String
defaultFormatStr
)
{
this
.
defaultFormatStr
=
defaultFormatStr
;
}
String
getDefaultFormatStr
()
{
return
defaultFormatStr
;
}
}
}
}
\ No newline at end of file
h2/src/main/org/h2/util/ToDateTokenizer.java
浏览文件 @
19556a3e
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: Daniel Gredler
*/
package
org
.
h2
.
util
;
package
org
.
h2
.
util
;
import
static
java
.
lang
.
String
.
format
;
import
static
java
.
lang
.
String
.
format
;
import
java.text.ParseException
;
import
java.text.ParseException
;
import
java.text.SimpleDateFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.*
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Calendar
;
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
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
java.util.regex.Pattern
;
...
@@ -12,227 +26,129 @@ import org.h2.api.ErrorCode;
...
@@ -12,227 +26,129 @@ import org.h2.api.ErrorCode;
import
org.h2.message.DbException
;
import
org.h2.message.DbException
;
/**
/**
* Emulates Oracle's TO_DATE function.
<br>
* Emulates Oracle's TO_DATE function.
This class knows all about the
* T
his class knows all about the TO_DATE-format conventions and how to parse the corresponding data
* T
O_DATE-format conventions and how to parse the corresponding data.
*/
*/
class
ToDateTokenizer
{
class
ToDateTokenizer
{
private
static
final
Pattern
PATTERN_NUMBER
=
Pattern
.
compile
(
"^([+-]?[0-9]+)"
);
static
final
Pattern
PATTERN_NUMBER
=
Pattern
.
compile
(
"^([+-]?[0-9]+)"
);
private
static
final
Pattern
PATTERN_FOUR_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{4})"
);
static
final
Pattern
PATTERN_FOUR_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{4})"
);
private
static
final
Pattern
PATTERN_THREE_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{3})"
);
static
final
Pattern
PATTERN_THREE_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{3})"
);
private
static
final
Pattern
PATTERN_TWO_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{2})"
);
static
final
Pattern
PATTERN_TWO_DIGITS
=
Pattern
.
compile
(
"^([+-]?[0-9]{2})"
);
private
static
final
Pattern
PATTERN_TWO_DIGITS_OR_LESS
=
Pattern
.
compile
(
"^([+-]?[0-9][0-9]?)"
);
static
final
Pattern
PATTERN_TWO_DIGITS_OR_LESS
=
private
static
final
Pattern
PATTERN_ONE_DIGIT
=
Pattern
.
compile
(
"^([+-]?[0-9])"
);
Pattern
.
compile
(
"^([+-]?[0-9][0-9]?)"
);
private
static
final
Pattern
PATTERN_FF
=
Pattern
.
compile
(
"^(FF[0-9]?)"
,
Pattern
.
CASE_INSENSITIVE
);
static
final
Pattern
PATTERN_ONE_DIGIT
=
private
static
final
Pattern
PATTERN_AM_PM
=
Pattern
.
compile
(
"^(AM|A\\.M\\.|PM|P\\.M\\.)"
,
Pattern
.
CASE_INSENSITIVE
);
Pattern
.
compile
(
"^([+-]?[0-9])"
);
private
static
final
Pattern
PATTERN_BC_AD
=
Pattern
.
compile
(
"^(BC|B\\.C\\.|AD|A\\.D\\.)"
,
Pattern
.
CASE_INSENSITIVE
);
static
final
Pattern
PATTERN_FF
=
private
static
final
YearParslet
PARSLET_YEAR
=
new
YearParslet
();
Pattern
.
compile
(
"^(FF[0-9]?)"
,
Pattern
.
CASE_INSENSITIVE
);
private
static
final
MonthParslet
PARSLET_MONTH
=
new
MonthParslet
();
static
final
Pattern
PATTERN_AM_PM
=
private
static
final
DayParslet
PARSLET_DAY
=
new
DayParslet
();
Pattern
.
compile
(
"^(AM|A\\.M\\.|PM|P\\.M\\.)"
,
Pattern
.
CASE_INSENSITIVE
);
private
static
final
TimeParslet
PARSLET_TIME
=
new
TimeParslet
();
static
final
Pattern
PATTERN_BC_AD
=
Pattern
.
compile
(
"^(BC|B\\.C\\.|AD|A\\.D\\.)"
,
Pattern
.
CASE_INSENSITIVE
);
static
enum
FormatTokenEnum
{
static
final
YearParslet
PARSLET_YEAR
=
new
YearParslet
();
YYYY
(
PARSLET_YEAR
)
// 4-digit year
static
final
MonthParslet
PARSLET_MONTH
=
new
MonthParslet
();
,
SYYYY
(
PARSLET_YEAR
)
// 4-digit year with sign (- = B.C.)
static
final
DayParslet
PARSLET_DAY
=
new
DayParslet
();
,
IYYY
(
PARSLET_YEAR
)
// 4-digit year based on the ISO standard (?)
static
final
TimeParslet
PARSLET_TIME
=
new
TimeParslet
();
,
YYY
(
PARSLET_YEAR
)
//
static
final
int
MILLIS_IN_HOUR
=
60
*
60
*
1000
;
,
IYY
(
PARSLET_YEAR
)
//
,
YY
(
PARSLET_YEAR
)
//
,
IY
(
PARSLET_YEAR
)
//
,
SCC
(
PARSLET_YEAR
)
// Two-digit century with with sign (- = B.C.)
,
CC
(
PARSLET_YEAR
)
// Two-digit century.
,
RRRR
(
PARSLET_YEAR
)
// 2-digit -> 4-digit year 0-49 -> 20xx , 50-99 -> 19xx
,
RR
(
PARSLET_YEAR
)
// last 2-digit of the year using "current" century value.
,
BC_AD
(
PARSLET_YEAR
,
PATTERN_BC_AD
)
// Meridian indicator
,
MONTH
(
PARSLET_MONTH
)
// Full Name of month
,
MON
(
PARSLET_MONTH
)
// Abbreviated name of month.
,
MM
(
PARSLET_MONTH
)
// Month (01-12; JAN = 01).
,
RM
(
PARSLET_MONTH
)
// Roman numeral month (I-XII; JAN = I).
,
DDD
(
PARSLET_DAY
)
// Day of year (1-366).
,
DAY
(
PARSLET_DAY
)
// Name of day.
,
DD
(
PARSLET_DAY
)
// Day of month (1-31).
,
DY
(
PARSLET_DAY
)
// Abbreviated name of day.
,
HH24
(
PARSLET_TIME
)
//
,
HH12
(
PARSLET_TIME
)
//
,
HH
(
PARSLET_TIME
)
// Hour of day (1-12).
,
MI
(
PARSLET_TIME
)
// Min
,
SSSSS
(
PARSLET_TIME
)
// Seconds past midnight (0-86399)
,
SS
(
PARSLET_TIME
)
//
,
FF
(
PARSLET_TIME
,
PATTERN_FF
)
// Fractional seconds
,
TZH
(
PARSLET_TIME
)
// Time zone hour.
,
TZM
(
PARSLET_TIME
)
// Time zone minute.
,
TZR
(
PARSLET_TIME
)
// Time zone region ID
,
TZD
(
PARSLET_TIME
)
// Daylight savings information. Example: PST (for US/Pacific standard time);
,
AM_PM
(
PARSLET_TIME
,
PATTERN_AM_PM
)
// Meridian indicator
,
EE
(
PARSLET_YEAR
)
// NOT supported yet - Full era name (Japanese Imperial, ROC Official, and Thai Buddha calendars).
,
E
(
PARSLET_YEAR
)
// NOT supported yet - Abbreviated era name (Japanese Imperial, ROC Official, and Thai Buddha calendars).
,
Y
(
PARSLET_YEAR
)
//
,
I
(
PARSLET_YEAR
)
//
,
Q
(
PARSLET_MONTH
)
// Quarter of year (1, 2, 3, 4; JAN-MAR = 1).
,
D
(
PARSLET_DAY
)
// Day of week (1-7).
,
J
(
PARSLET_DAY
);
// NOT supported yet - Julian day; the number of days since Jan 1, 4712 BC.
private
final
static
Map
<
Character
,
List
<
FormatTokenEnum
>>
cache
=
new
HashMap
<
Character
,
List
<
FormatTokenEnum
>>(
FormatTokenEnum
.
values
().
length
);
private
final
ToDateParslet
toDateParslet
;
private
final
Pattern
patternToUse
;
FormatTokenEnum
(
final
ToDateParslet
toDateParslet
,
final
Pattern
patternToUse
)
{
this
.
toDateParslet
=
toDateParslet
;
this
.
patternToUse
=
patternToUse
;
}
FormatTokenEnum
(
final
ToDateParslet
toDateParslet
)
{
this
.
toDateParslet
=
toDateParslet
;
patternToUse
=
Pattern
.
compile
(
format
(
"^(%s)"
,
name
()),
Pattern
.
CASE_INSENSITIVE
);
}
private
static
List
<
FormatTokenEnum
>
EMPTY_LIST
=
new
ArrayList
<
FormatTokenEnum
>(
0
);
/**
/**
* OPTIMISATION: Only return a list of {@link FormatTokenEnum} that share the same 1st char
* Interface of the classes that can parse a specialized small bit of the
* using the 1st char of the 'to parse' formatStr. Or return empty list if no match.
* TO_DATE format-string
*/
static
List
<
FormatTokenEnum
>
getTokensInQuestion
(
String
formatStr
)
{
List
<
FormatTokenEnum
>
result
=
EMPTY_LIST
;
if
(
cache
.
size
()
<=
0
)
{
initCache
();
}
if
(
formatStr
!=
null
&&
formatStr
.
length
()
>
0
)
{
Character
key
=
Character
.
toUpperCase
(
formatStr
.
charAt
(
0
));
result
=
cache
.
get
(
key
);
}
if
(
result
==
null
)
{
result
=
EMPTY_LIST
;
}
return
result
;
}
private
static
synchronized
void
initCache
()
{
if
(
cache
.
size
()
<=
0
)
{
for
(
FormatTokenEnum
token
:
FormatTokenEnum
.
values
())
{
List
<
Character
>
tokenKeys
=
new
ArrayList
<
Character
>();
if
(
token
.
name
().
contains
(
"_"
))
{
String
[]
tokens
=
token
.
name
().
split
(
"_"
);
for
(
String
tokenLets
:
tokens
)
{
tokenKeys
.
add
(
tokenLets
.
toUpperCase
().
charAt
(
0
));
}
}
else
{
tokenKeys
.
add
(
token
.
name
().
toUpperCase
().
charAt
(
0
));
}
for
(
Character
tokenKey
:
tokenKeys
)
{
List
<
FormatTokenEnum
>
l
=
cache
.
get
(
tokenKey
);
if
(
l
==
null
)
{
l
=
new
ArrayList
<
FormatTokenEnum
>(
1
);
cache
.
put
(
tokenKey
,
l
);
}
l
.
add
(
token
);
}
}
}
}
/**
* Parse the format-string with passed token of {@link FormatTokenEnum}}.<br>
* If token matches return true, otherwise false.
*/
boolean
parseFormatStrWithToken
(
final
ToDateParser
params
)
{
Matcher
matcher
=
patternToUse
.
matcher
(
params
.
getFormatStr
());
boolean
foundToken
=
matcher
.
find
();
if
(
foundToken
)
{
String
formatTokenStr
=
matcher
.
group
(
1
);
toDateParslet
.
parse
(
params
,
this
,
formatTokenStr
);
}
return
foundToken
;
}
}
/**
* Interface of the classes that can parse a specialized small bit of the TO_DATE format-string
*/
*/
interface
ToDateParslet
{
interface
ToDateParslet
{
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
);
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
String
formatTokenStr
);
}
}
/**
/**
* Parslet responsible for parsing year parameter
* Parslet responsible for parsing year parameter
*/
*/
private
static
final
class
YearParslet
implements
ToDateParslet
{
static
class
YearParslet
implements
ToDateParslet
{
@Override
@Override
public
void
parse
(
final
ToDateParser
params
,
final
FormatTokenEnum
formatTokenEnum
,
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
final
String
formatTokenStr
)
{
String
formatTokenStr
)
{
final
Calendar
result
=
params
.
getResultCalendar
();
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
switch
(
formatTokenEnum
)
{
case
SYYYY:
case
SYYYY:
case
YYYY:
case
YYYY:
case
IYYY:
case
IYYY:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_FOUR_DIGITS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_FOUR_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// 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
);
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
break
;
case
YYY:
case
YYY:
case
IYY:
case
IYY:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_THREE_DIGITS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_THREE_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// 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
);
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
break
;
case
RRRR:
case
RRRR:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
+=
dateNr
<
50
?
2000
:
1900
;
dateNr
+=
dateNr
<
50
?
2000
:
1900
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
break
;
break
;
case
RR:
case
RR:
Calendar
calendar
=
Calendar
.
getInstance
();
Calendar
calendar
=
Calendar
.
getInstance
();
int
cc
=
(
calendar
.
get
(
Calendar
.
YEAR
)
/
100
);
int
cc
=
calendar
.
get
(
Calendar
.
YEAR
)
/
100
;
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
)
+
cc
*
100
;
dateNr
=
parseInt
(
inputFragmentStr
)
+
cc
*
100
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
break
;
break
;
case
EE
/*NOT supported yet*/
:
case
EE
/*NOT supported yet*/
:
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
break
;
break
;
case
E
/*NOT supported yet*/
:
case
E
/*NOT supported yet*/
:
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
break
;
break
;
case
YY:
case
YY:
case
IY:
case
IY:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// 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
);
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
break
;
case
SCC:
case
SCC:
case
CC:
case
CC:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
)
*
100
;
dateNr
=
parseInt
(
inputFragmentStr
)
*
100
;
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
result
.
set
(
Calendar
.
YEAR
,
dateNr
);
break
;
break
;
case
Y:
case
Y:
case
I:
case
I:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// 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
);
result
.
set
(
Calendar
.
YEAR
,
dateNr
>=
0
?
dateNr
:
dateNr
+
1
);
break
;
break
;
case
BC_AD:
case
BC_AD:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_BC_AD
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"B"
))
{
PATTERN_BC_AD
,
params
,
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"B"
))
{
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
BC
);
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
BC
);
}
}
else
{
else
{
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
AD
);
result
.
set
(
Calendar
.
ERA
,
GregorianCalendar
.
AD
);
}
}
break
;
break
;
default
:
default
:
throw
new
IllegalArgumentException
(
format
(
"%s: Internal Error. Unhandled case: %s"
,
this
.
getClass
()
throw
new
IllegalArgumentException
(
format
(
"%s: Internal Error. Unhandled case: %s"
,
this
.
getClass
()
.
getSimpleName
(),
formatTokenEnum
));
.
getSimpleName
(),
formatTokenEnum
));
}
}
params
.
remove
(
inputFragmentStr
,
formatTokenStr
);
params
.
remove
(
inputFragmentStr
,
formatTokenStr
);
...
@@ -242,39 +158,44 @@ class ToDateTokenizer {
...
@@ -242,39 +158,44 @@ class ToDateTokenizer {
/**
/**
* Parslet responsible for parsing month parameter
* Parslet responsible for parsing month parameter
*/
*/
private
static
final
class
MonthParslet
implements
ToDateParslet
{
static
class
MonthParslet
implements
ToDateParslet
{
private
static
final
String
[]
ROMAN_M
onth
=
{
"I"
,
"II"
,
"III"
,
"IV"
,
"V"
,
"VI"
,
"VII"
,
"VIII"
,
"IX"
,
"X
"
,
private
static
final
String
[]
ROMAN_M
ONTH
=
{
"I"
,
"II"
,
"III"
,
"IV
"
,
"XI"
,
"XII"
};
"
V"
,
"VI"
,
"VII"
,
"VIII"
,
"IX"
,
"X"
,
"
XI"
,
"XII"
};
@Override
@Override
public
void
parse
(
final
ToDateParser
params
,
final
FormatTokenEnum
formatTokenEnum
,
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
final
String
formatTokenStr
)
{
String
formatTokenStr
)
{
final
Calendar
result
=
params
.
getResultCalendar
();
Calendar
result
=
params
.
getResultCalendar
();
final
String
s
=
params
.
getInputStr
();
String
s
=
params
.
getInputStr
();
String
inputFragmentStr
=
null
;
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
switch
(
formatTokenEnum
)
{
case
MONTH:
case
MONTH:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
Calendar
.
LONG
);
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
Calendar
.
LONG
);
break
;
break
;
case
Q
/*NOT supported yet*/
:
case
Q
/*NOT supported yet*/
:
throwException
(
params
,
format
(
"token '%s' not supported jet."
,
formatTokenEnum
.
name
()));
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
break
;
break
;
case
MON:
case
MON:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
Calendar
.
SHORT
);
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
MONTH
,
Calendar
.
SHORT
);
break
;
break
;
case
MM:
case
MM:
// Note: In Calendar Month go from 0 - 11
// Note: In Calendar Month go from 0 - 11
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
MONTH
,
dateNr
-
1
);
result
.
set
(
Calendar
.
MONTH
,
dateNr
-
1
);
break
;
break
;
case
RM:
case
RM:
dateNr
=
0
;
dateNr
=
0
;
for
(
String
monthName
:
ROMAN_M
onth
)
{
for
(
String
monthName
:
ROMAN_M
ONTH
)
{
dateNr
++;
dateNr
++;
int
leng
=
monthName
.
length
();
int
len
=
monthName
.
length
();
if
(
s
.
length
()
>=
leng
&&
monthName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
leng
)))
{
if
(
s
.
length
()
>=
len
&&
monthName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
)))
{
result
.
set
(
Calendar
.
MONTH
,
dateNr
);
result
.
set
(
Calendar
.
MONTH
,
dateNr
);
inputFragmentStr
=
monthName
;
inputFragmentStr
=
monthName
;
break
;
break
;
...
@@ -282,12 +203,14 @@ class ToDateTokenizer {
...
@@ -282,12 +203,14 @@ class ToDateTokenizer {
}
}
if
(
inputFragmentStr
==
null
||
inputFragmentStr
.
isEmpty
())
{
if
(
inputFragmentStr
==
null
||
inputFragmentStr
.
isEmpty
())
{
throwException
(
params
,
throwException
(
params
,
format
(
"Issue happened when parsing token '%s'. Expected one of: %s"
,
format
(
"Issue happened when parsing token '%s'. "
+
formatTokenEnum
.
name
(),
Arrays
.
toString
(
ROMAN_Month
)));
"Expected one of: %s"
,
formatTokenEnum
.
name
(),
Arrays
.
toString
(
ROMAN_MONTH
)));
}
}
break
;
break
;
default
:
default
:
throw
new
IllegalArgumentException
(
format
(
"%s: Internal Error. Unhandled case: %s"
,
this
.
getClass
()
throw
new
IllegalArgumentException
(
format
(
"%s: Internal Error. Unhandled case: %s"
,
this
.
getClass
()
.
getSimpleName
(),
formatTokenEnum
));
.
getSimpleName
(),
formatTokenEnum
));
}
}
params
.
remove
(
inputFragmentStr
,
formatTokenStr
);
params
.
remove
(
inputFragmentStr
,
formatTokenStr
);
...
@@ -297,96 +220,108 @@ class ToDateTokenizer {
...
@@ -297,96 +220,108 @@ class ToDateTokenizer {
/**
/**
* Parslet responsible for parsing day parameter
* Parslet responsible for parsing day parameter
*/
*/
private
static
final
class
DayParslet
implements
ToDateParslet
{
static
class
DayParslet
implements
ToDateParslet
{
@Override
@Override
public
void
parse
(
final
ToDateParser
params
,
final
FormatTokenEnum
formatTokenEnum
,
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
final
String
formatTokenStr
)
{
String
formatTokenStr
)
{
final
Calendar
result
=
params
.
getResultCalendar
();
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
switch
(
formatTokenEnum
)
{
case
DDD:
case
DDD:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_YEAR
,
dateNr
);
result
.
set
(
Calendar
.
DAY_OF_YEAR
,
dateNr
);
break
;
break
;
case
DD:
case
DD:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
break
;
break
;
case
D:
case
D:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_ONE_DIGIT
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
result
.
set
(
Calendar
.
DAY_OF_MONTH
,
dateNr
);
break
;
break
;
case
DAY:
case
DAY:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
DAY_OF_WEEK
,
Calendar
.
LONG
);
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
DAY_OF_WEEK
,
Calendar
.
LONG
);
break
;
break
;
case
DY:
case
DY:
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
DAY_OF_WEEK
,
Calendar
.
SHORT
);
inputFragmentStr
=
setByName
(
result
,
params
,
Calendar
.
DAY_OF_WEEK
,
Calendar
.
SHORT
);
break
;
break
;
case
J:
case
J:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
try
{
try
{
Date
date
=
new
SimpleDateFormat
(
"Myydd"
).
parse
(
inputFragmentStr
);
Date
date
=
new
SimpleDateFormat
(
"Myydd"
).
parse
(
inputFragmentStr
);
result
.
setTime
(
date
);
result
.
setTime
(
date
);
}
catch
(
ParseException
e
)
{
}
catch
(
ParseException
e
)
{
throwException
(
params
,
format
(
"Failed to parse Julian date: %s"
,
inputFragmentStr
));
throwException
(
params
,
format
(
"Failed to parse Julian date: %s"
,
inputFragmentStr
));
}
}
break
;
break
;
default
:
default
:
throw
new
IllegalArgumentException
(
format
(
"%s: Internal Error. Unhandled case: %s"
,
this
.
getClass
()
throw
new
IllegalArgumentException
(
format
(
"%s: Internal Error. Unhandled case: %s"
,
this
.
getClass
()
.
getSimpleName
(),
formatTokenEnum
));
.
getSimpleName
(),
formatTokenEnum
));
}
}
params
.
remove
(
inputFragmentStr
,
formatTokenStr
);
params
.
remove
(
inputFragmentStr
,
formatTokenStr
);
}
}
}
}
private
static
int
MILLIS_in_hour
=
60
*
60
*
1000
;
/**
/**
* Parslet responsible for parsing time parameter
* Parslet responsible for parsing time parameter
*/
*/
private
static
final
class
TimeParslet
implements
ToDateParslet
{
static
class
TimeParslet
implements
ToDateParslet
{
@Override
@Override
public
void
parse
(
final
ToDateParser
params
,
final
FormatTokenEnum
formatTokenEnum
,
public
void
parse
(
ToDateParser
params
,
FormatTokenEnum
formatTokenEnum
,
final
String
formatTokenStr
)
{
String
formatTokenStr
)
{
final
Calendar
result
=
params
.
getResultCalendar
();
Calendar
result
=
params
.
getResultCalendar
();
String
inputFragmentStr
=
null
;
String
inputFragmentStr
=
null
;
int
dateNr
=
0
;
int
dateNr
=
0
;
switch
(
formatTokenEnum
)
{
switch
(
formatTokenEnum
)
{
case
HH24:
case
HH24:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
dateNr
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
dateNr
);
break
;
break
;
case
HH12:
case
HH12:
case
HH:
case
HH:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR
,
dateNr
);
result
.
set
(
Calendar
.
HOUR
,
dateNr
);
break
;
break
;
case
MI:
case
MI:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
MINUTE
,
dateNr
);
result
.
set
(
Calendar
.
MINUTE
,
dateNr
);
break
;
break
;
case
SS:
case
SS:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
break
;
break
;
case
SSSSS:
case
SSSSS:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
0
);
result
.
set
(
Calendar
.
HOUR_OF_DAY
,
0
);
result
.
set
(
Calendar
.
MINUTE
,
0
);
result
.
set
(
Calendar
.
MINUTE
,
0
);
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
result
.
set
(
Calendar
.
SECOND
,
dateNr
);
break
;
break
;
case
FF:
//
case
FF:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_NUMBER
,
params
,
formatTokenEnum
);
String
paddedRightNrStr
=
format
(
"%-9s"
,
inputFragmentStr
).
replace
(
' '
,
'0'
);
String
paddedRightNrStr
=
format
(
"%-9s"
,
inputFragmentStr
).
replace
(
' '
,
'0'
);
paddedRightNrStr
=
paddedRightNrStr
.
substring
(
0
,
9
);
paddedRightNrStr
=
paddedRightNrStr
.
substring
(
0
,
9
);
Double
nineDigits
=
Double
.
parseDouble
(
paddedRightNrStr
);
Double
nineDigits
=
Double
.
parseDouble
(
paddedRightNrStr
);
...
@@ -395,39 +330,44 @@ class ToDateTokenizer {
...
@@ -395,39 +330,44 @@ class ToDateTokenizer {
result
.
set
(
Calendar
.
MILLISECOND
,
dateNr
);
result
.
set
(
Calendar
.
MILLISECOND
,
dateNr
);
break
;
break
;
case
AM_PM:
case
AM_PM:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_AM_PM
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"A"
))
{
PATTERN_AM_PM
,
params
,
formatTokenEnum
);
if
(
inputFragmentStr
.
toUpperCase
().
startsWith
(
"A"
))
{
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
AM
);
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
AM
);
}
}
else
{
else
{
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
PM
);
result
.
set
(
Calendar
.
AM_PM
,
Calendar
.
PM
);
}
}
break
;
break
;
case
TZH:
case
TZH:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
TimeZone
tz
=
result
.
getTimeZone
();
TimeZone
tz
=
result
.
getTimeZone
();
int
offsetMillis
=
tz
.
getRawOffset
();
int
offsetMillis
=
tz
.
getRawOffset
();
offsetMillis
=
(
offsetMillis
/
MILLIS_in_hour
)
*
MILLIS_in_hour
;
// purge min and sec
// purge min and sec
offsetMillis
=
(
offsetMillis
/
MILLIS_IN_HOUR
)
*
MILLIS_IN_HOUR
;
tz
.
setRawOffset
(
offsetMillis
+
dateNr
);
tz
.
setRawOffset
(
offsetMillis
+
dateNr
);
result
.
setTimeZone
(
tz
);
result
.
setTimeZone
(
tz
);
break
;
break
;
case
TZM:
case
TZM:
inputFragmentStr
=
matchStringOrDie
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
inputFragmentStr
=
matchStringOrThrow
(
PATTERN_TWO_DIGITS_OR_LESS
,
params
,
formatTokenEnum
);
dateNr
=
parseInt
(
inputFragmentStr
);
dateNr
=
parseInt
(
inputFragmentStr
);
tz
=
result
.
getTimeZone
();
tz
=
result
.
getTimeZone
();
offsetMillis
=
tz
.
getRawOffset
();
offsetMillis
=
tz
.
getRawOffset
();
offsetMillis
=
offsetMillis
%
MILLIS_in_hour
;
// purge hour
// purge hour
tz
.
setRawOffset
(
dateNr
*
MILLIS_in_hour
+
offsetMillis
);
offsetMillis
=
offsetMillis
%
MILLIS_IN_HOUR
;
tz
.
setRawOffset
(
dateNr
*
MILLIS_IN_HOUR
+
offsetMillis
);
result
.
setTimeZone
(
tz
);
result
.
setTimeZone
(
tz
);
break
;
break
;
case
TZR:
// Example: US/Pacific
case
TZR:
final
String
s
=
params
.
getInputStr
();
// Example: US/Pacific
String
s
=
params
.
getInputStr
();
tz
=
result
.
getTimeZone
();
tz
=
result
.
getTimeZone
();
for
(
String
tzName
:
TimeZone
.
getAvailableIDs
())
{
for
(
String
tzName
:
TimeZone
.
getAvailableIDs
())
{
int
length
=
tzName
.
length
();
int
length
=
tzName
.
length
();
if
(
s
.
length
()
>=
length
&&
tzName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
length
)))
{
if
(
s
.
length
()
>=
length
&&
tzName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
length
)))
{
tz
.
setID
(
tzName
);
tz
.
setID
(
tzName
);
result
.
setTimeZone
(
tz
);
result
.
setTimeZone
(
tz
);
inputFragmentStr
=
tzName
;
inputFragmentStr
=
tzName
;
...
@@ -435,18 +375,22 @@ class ToDateTokenizer {
...
@@ -435,18 +375,22 @@ class ToDateTokenizer {
}
}
}
}
break
;
break
;
case
TZD:
// Must correspond with TZR region. Example: PST (for US/Pacific standard time)
case
TZD:
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
// Must correspond with TZR region. Example: PST (for US/Pacific
// standard time)
throwException
(
params
,
format
(
"token '%s' not supported yet."
,
formatTokenEnum
.
name
()));
break
;
break
;
default
:
default
:
throw
new
IllegalArgumentException
(
format
(
"%s: Internal Error. Unhandled case: %s"
,
this
.
getClass
()
throw
new
IllegalArgumentException
(
format
(
"%s: Internal Error. Unhandled case: %s"
,
this
.
getClass
()
.
getSimpleName
(),
formatTokenEnum
));
.
getSimpleName
(),
formatTokenEnum
));
}
}
params
.
remove
(
inputFragmentStr
,
formatTokenStr
);
params
.
remove
(
inputFragmentStr
,
formatTokenStr
);
}
}
}
}
private
static
int
parseInt
(
final
String
s
)
{
static
int
parseInt
(
String
s
)
{
int
result
=
0
;
int
result
=
0
;
if
(
s
.
length
()
>
0
&&
s
.
charAt
(
0
)
==
'+'
)
{
if
(
s
.
length
()
>
0
&&
s
.
charAt
(
0
)
==
'+'
)
{
result
=
Integer
.
parseInt
(
s
.
substring
(
1
));
result
=
Integer
.
parseInt
(
s
.
substring
(
1
));
...
@@ -456,39 +400,202 @@ class ToDateTokenizer {
...
@@ -456,39 +400,202 @@ class ToDateTokenizer {
return
result
;
return
result
;
}
}
private
static
String
matchStringOrDie
(
final
Pattern
p
,
final
ToDateParser
params
,
final
Enum
<?>
aEnum
)
{
static
String
matchStringOrThrow
(
Pattern
p
,
ToDateParser
params
,
Enum
<?>
aEnum
)
{
final
String
s
=
params
.
getInputStr
();
String
s
=
params
.
getInputStr
();
Matcher
matcher
=
p
.
matcher
(
s
);
Matcher
matcher
=
p
.
matcher
(
s
);
if
(!
matcher
.
find
())
{
if
(!
matcher
.
find
())
{
throwException
(
params
,
format
(
"Issue happend when parsing token '%s'"
,
aEnum
.
name
()));
throwException
(
params
,
format
(
"Issue happen
e
d when parsing token '%s'"
,
aEnum
.
name
()));
}
}
return
matcher
.
group
(
1
);
return
matcher
.
group
(
1
);
}
}
private
static
String
setByName
(
final
Calendar
c
,
final
ToDateParser
params
,
final
int
field
,
final
int
style
)
{
static
String
setByName
(
Calendar
c
,
ToDateParser
params
,
int
field
,
int
style
)
{
String
inputFragmentStr
=
null
;
String
inputFragmentStr
=
null
;
String
s
=
params
.
getInputStr
();
String
s
=
params
.
getInputStr
();
Map
<
String
,
Integer
>
timeStringMap
=
c
.
getDisplayNames
(
field
,
style
,
Locale
.
getDefault
());
Map
<
String
,
Integer
>
timeStringMap
=
c
.
getDisplayNames
(
field
,
style
,
Locale
.
getDefault
());
for
(
String
dayName
:
timeStringMap
.
keySet
())
{
for
(
String
dayName
:
timeStringMap
.
keySet
())
{
int
len
g
=
dayName
.
length
();
int
len
=
dayName
.
length
();
if
(
dayName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
g
)))
{
if
(
dayName
.
equalsIgnoreCase
(
s
.
substring
(
0
,
len
)))
{
c
.
set
(
field
,
timeStringMap
.
get
(
dayName
));
c
.
set
(
field
,
timeStringMap
.
get
(
dayName
));
inputFragmentStr
=
dayName
;
inputFragmentStr
=
dayName
;
break
;
break
;
}
}
}
}
if
(
inputFragmentStr
==
null
||
inputFragmentStr
.
isEmpty
())
{
if
(
inputFragmentStr
==
null
||
inputFragmentStr
.
isEmpty
())
{
throwException
(
params
,
format
(
"Tried to parse one of '%s' but failed (may be an internal error?)"
,
throwException
(
params
,
format
(
"Tried to parse one of '%s' but failed (may be an internal error?)"
,
timeStringMap
.
keySet
()));
timeStringMap
.
keySet
()));
}
}
return
inputFragmentStr
;
return
inputFragmentStr
;
}
}
private
static
void
throwException
(
final
ToDateParser
params
,
final
String
errorStr
)
{
static
void
throwException
(
ToDateParser
params
,
String
errorStr
)
{
throw
DbException
.
get
(
throw
DbException
.
get
(
ErrorCode
.
INVALID_TO_DATE_FORMAT
,
ErrorCode
.
INVALID_TO_DATE_FORMAT
,
params
.
getFunctionName
(),
params
.
getFunctionName
(),
format
(
" %s. Details: %s"
,
errorStr
,
params
));
format
(
" %s. Details: %s"
,
errorStr
,
params
));
}
}
/**
* The format tokens.
*/
static
enum
FormatTokenEnum
{
// 4-digit year
YYYY
(
PARSLET_YEAR
),
// 4-digit year with sign (- = B.C.)
SYYYY
(
PARSLET_YEAR
),
// 4-digit year based on the ISO standard (?)
IYYY
(
PARSLET_YEAR
),
YYY
(
PARSLET_YEAR
),
IYY
(
PARSLET_YEAR
),
YY
(
PARSLET_YEAR
),
IY
(
PARSLET_YEAR
),
// Two-digit century with with sign (- = B.C.)
SCC
(
PARSLET_YEAR
),
// Two-digit century.
CC
(
PARSLET_YEAR
),
// 2-digit -> 4-digit year 0-49 -> 20xx , 50-99 -> 19xx
RRRR
(
PARSLET_YEAR
),
// last 2-digit of the year using "current" century value.
RR
(
PARSLET_YEAR
),
// Meridian indicator
BC_AD
(
PARSLET_YEAR
,
PATTERN_BC_AD
),
// Full Name of month
MONTH
(
PARSLET_MONTH
),
// Abbreviated name of month.
MON
(
PARSLET_MONTH
),
// Month (01-12; JAN = 01).
MM
(
PARSLET_MONTH
),
// Roman numeral month (I-XII; JAN = I).
RM
(
PARSLET_MONTH
),
// Day of year (1-366).
DDD
(
PARSLET_DAY
),
// Name of day.
DAY
(
PARSLET_DAY
),
// Day of month (1-31).
DD
(
PARSLET_DAY
),
// Abbreviated name of day.
DY
(
PARSLET_DAY
),
HH24
(
PARSLET_TIME
),
HH12
(
PARSLET_TIME
),
// Hour of day (1-12).
HH
(
PARSLET_TIME
),
// Min
MI
(
PARSLET_TIME
),
// Seconds past midnight (0-86399)
SSSSS
(
PARSLET_TIME
),
SS
(
PARSLET_TIME
),
// Fractional seconds
FF
(
PARSLET_TIME
,
PATTERN_FF
),
// Time zone hour.
TZH
(
PARSLET_TIME
),
// Time zone minute.
TZM
(
PARSLET_TIME
),
// Time zone region ID
TZR
(
PARSLET_TIME
),
// Daylight savings information. Example:
// PST (for US/Pacific standard time);
TZD
(
PARSLET_TIME
),
// Meridian indicator
AM_PM
(
PARSLET_TIME
,
PATTERN_AM_PM
),
// NOT supported yet -
// Full era name (Japanese Imperial, ROC Official,
// and Thai Buddha calendars).
EE
(
PARSLET_YEAR
),
// NOT supported yet -
// Abbreviated era name (Japanese Imperial,
// ROC Official, and Thai Buddha calendars).
E
(
PARSLET_YEAR
),
Y
(
PARSLET_YEAR
),
I
(
PARSLET_YEAR
),
// Quarter of year (1, 2, 3, 4; JAN-MAR = 1).
Q
(
PARSLET_MONTH
),
// Day of week (1-7).
D
(
PARSLET_DAY
),
// NOT supported yet -
// Julian day; the number of days since Jan 1, 4712 BC.
J
(
PARSLET_DAY
);
private
static
final
List
<
FormatTokenEnum
>
EMPTY_LIST
=
new
ArrayList
<
FormatTokenEnum
>(
0
);
private
static
final
Map
<
Character
,
List
<
FormatTokenEnum
>>
CACHE
=
new
HashMap
<
Character
,
List
<
FormatTokenEnum
>>(
FormatTokenEnum
.
values
().
length
);
private
final
ToDateParslet
toDateParslet
;
private
final
Pattern
patternToUse
;
FormatTokenEnum
(
ToDateParslet
toDateParslet
,
Pattern
patternToUse
)
{
this
.
toDateParslet
=
toDateParslet
;
this
.
patternToUse
=
patternToUse
;
}
FormatTokenEnum
(
ToDateParslet
toDateParslet
)
{
this
.
toDateParslet
=
toDateParslet
;
patternToUse
=
Pattern
.
compile
(
format
(
"^(%s)"
,
name
()),
Pattern
.
CASE_INSENSITIVE
);
}
/**
* Optimization: Only return a list of {@link FormatTokenEnum} that
* share the same 1st char using the 1st char of the 'to parse'
* formatStr. Or return empty list if no match.
*/
static
List
<
FormatTokenEnum
>
getTokensInQuestion
(
String
formatStr
)
{
List
<
FormatTokenEnum
>
result
=
EMPTY_LIST
;
if
(
CACHE
.
size
()
<=
0
)
{
initCache
();
}
if
(
formatStr
!=
null
&&
formatStr
.
length
()
>
0
)
{
Character
key
=
Character
.
toUpperCase
(
formatStr
.
charAt
(
0
));
result
=
CACHE
.
get
(
key
);
}
if
(
result
==
null
)
{
result
=
EMPTY_LIST
;
}
return
result
;
}
private
static
synchronized
void
initCache
()
{
if
(
CACHE
.
size
()
<=
0
)
{
for
(
FormatTokenEnum
token
:
FormatTokenEnum
.
values
())
{
List
<
Character
>
tokenKeys
=
new
ArrayList
<
Character
>();
if
(
token
.
name
().
contains
(
"_"
))
{
String
[]
tokens
=
token
.
name
().
split
(
"_"
);
for
(
String
tokenLets
:
tokens
)
{
tokenKeys
.
add
(
tokenLets
.
toUpperCase
().
charAt
(
0
));
}
}
else
{
tokenKeys
.
add
(
token
.
name
().
toUpperCase
().
charAt
(
0
));
}
for
(
Character
tokenKey
:
tokenKeys
)
{
List
<
FormatTokenEnum
>
l
=
CACHE
.
get
(
tokenKey
);
if
(
l
==
null
)
{
l
=
new
ArrayList
<
FormatTokenEnum
>(
1
);
CACHE
.
put
(
tokenKey
,
l
);
}
l
.
add
(
token
);
}
}
}
}
/**
* Parse the format-string with passed token of {@link FormatTokenEnum}.
* If token matches return true, otherwise false.
*/
boolean
parseFormatStrWithToken
(
ToDateParser
params
)
{
Matcher
matcher
=
patternToUse
.
matcher
(
params
.
getFormatStr
());
boolean
foundToken
=
matcher
.
find
();
if
(
foundToken
)
{
String
formatTokenStr
=
matcher
.
group
(
1
);
toDateParslet
.
parse
(
params
,
this
,
formatTokenStr
);
}
return
foundToken
;
}
}
}
}
\ No newline at end of file
h2/src/main/org/h2/value/Value.java
浏览文件 @
19556a3e
...
@@ -767,7 +767,7 @@ public abstract class Value {
...
@@ -767,7 +767,7 @@ public abstract class Value {
case
TIMESTAMP_UTC:
case
TIMESTAMP_UTC:
return
ValueTimestamp
.
fromMillisNanos
(
return
ValueTimestamp
.
fromMillisNanos
(
((
ValueTimestampUtc
)
this
).
getUtcDateTimeMillis
(),
((
ValueTimestampUtc
)
this
).
getUtcDateTimeMillis
(),
((
ValueTimestampUtc
)
this
).
getNanosSinceLastMilli
());
((
ValueTimestampUtc
)
this
).
getNanosSinceLastMilli
s
());
}
}
break
;
break
;
}
}
...
...
h2/src/main/org/h2/value/ValueTimestampUtc.java
浏览文件 @
19556a3e
...
@@ -110,14 +110,14 @@ public final class ValueTimestampUtc extends Value {
...
@@ -110,14 +110,14 @@ public final class ValueTimestampUtc extends Value {
return
utcDateTimeNanos
/
1000
/
1000
;
return
utcDateTimeNanos
/
1000
/
1000
;
}
}
public
int
getNanosSinceLastMilli
()
{
int
getNanosSinceLastMillis
()
{
return
(
int
)
(
utcDateTimeNanos
%
(
1000
*
1000
));
return
(
int
)
(
utcDateTimeNanos
%
(
1000
*
1000
));
}
}
@Override
@Override
public
java
.
sql
.
Timestamp
getTimestamp
()
{
public
java
.
sql
.
Timestamp
getTimestamp
()
{
java
.
sql
.
Timestamp
ts
=
new
java
.
sql
.
Timestamp
(
getUtcDateTimeMillis
());
java
.
sql
.
Timestamp
ts
=
new
java
.
sql
.
Timestamp
(
getUtcDateTimeMillis
());
ts
.
setNanos
(
getNanosSinceLastMilli
());
ts
.
setNanos
(
getNanosSinceLastMilli
s
());
return
ts
;
return
ts
;
}
}
...
@@ -157,7 +157,7 @@ public final class ValueTimestampUtc extends Value {
...
@@ -157,7 +157,7 @@ public final class ValueTimestampUtc extends Value {
timeNanos
*=
60
;
timeNanos
*=
60
;
timeNanos
+=
cal
.
get
(
Calendar
.
MILLISECOND
);
timeNanos
+=
cal
.
get
(
Calendar
.
MILLISECOND
);
timeNanos
*=
1000
*
1000
;
timeNanos
*=
1000
*
1000
;
timeNanos
+=
getNanosSinceLastMilli
();
timeNanos
+=
getNanosSinceLastMilli
s
();
ValueTime
.
appendTime
(
buff
,
timeNanos
,
true
);
ValueTime
.
appendTime
(
buff
,
timeNanos
,
true
);
buff
.
append
(
" UTC"
);
buff
.
append
(
" UTC"
);
return
buff
.
toString
();
return
buff
.
toString
();
...
...
h2/src/test/org/h2/samples/ToDate.java
浏览文件 @
19556a3e
...
@@ -5,17 +5,14 @@
...
@@ -5,17 +5,14 @@
*/
*/
package
org
.
h2
.
samples
;
package
org
.
h2
.
samples
;
import
org.h2.tools.DeleteDbFiles
;
import
java.sql.Connection
;
import
java.sql.Connection
;
import
java.sql.DriverManager
;
import
java.sql.DriverManager
;
import
java.sql.ResultSet
;
import
java.sql.ResultSet
;
import
java.sql.Statement
;
import
java.sql.Statement
;
import
java.text.DateFormat
;
import
java.text.SimpleDateFormat
;
import
java.text.SimpleDateFormat
;
import
java.util.Date
;
import
java.util.Date
;
import
java.util.Locale
;
import
java.util.TimeZone
;
import
org.h2.tools.DeleteDbFiles
;
/**
/**
* A very simple class that shows how to load the driver, create a database,
* A very simple class that shows how to load the driver, create a database,
...
@@ -37,11 +34,20 @@ public class ToDate {
...
@@ -37,11 +34,20 @@ public class ToDate {
Connection
conn
=
DriverManager
.
getConnection
(
"jdbc:h2:~/test"
);
Connection
conn
=
DriverManager
.
getConnection
(
"jdbc:h2:~/test"
);
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"create table ToDateTest(id int primary key, start_date datetime, end_date datetime)"
);
stat
.
execute
(
"create table ToDateTest(id int primary key, "
+
stat
.
execute
(
"insert into ToDateTest values(1, TO_DATE('2015-11-13', 'yyyy-MM-DD'), TO_DATE('2015-12-15', 'YYYY-MM-DD'))"
);
"start_date datetime, end_date datetime)"
);
stat
.
execute
(
"insert into ToDateTest values(2, TO_DATE('2015-12-12 00:00:00', 'yyyy-MM-DD HH24:MI:ss'), TO_DATE('2015-12-16 15:00:00', 'YYYY-MM-DD HH24:MI:ss'))"
);
stat
.
execute
(
"insert into ToDateTest values(1, "
+
stat
.
execute
(
"insert into ToDateTest values(3, TO_DATE('2015-12-12 08:00 A.M.', 'yyyy-MM-DD HH:MI AM'), TO_DATE('2015-12-17 08:00 P.M.', 'YYYY-MM-DD HH:MI AM'))"
);
"TO_DATE('2015-11-13', 'yyyy-MM-DD'), "
+
stat
.
execute
(
"insert into ToDateTest values(4, TO_DATE(substr('2015-12-12 08:00 A.M.', 1, 10), 'yyyy-MM-DD'), TO_DATE('2015-12-17 08:00 P.M.', 'YYYY-MM-DD HH:MI AM'))"
);
"TO_DATE('2015-12-15', 'YYYY-MM-DD'))"
);
stat
.
execute
(
"insert into ToDateTest values(2, "
+
"TO_DATE('2015-12-12 00:00:00', 'yyyy-MM-DD HH24:MI:ss'), "
+
"TO_DATE('2015-12-16 15:00:00', 'YYYY-MM-DD HH24:MI:ss'))"
);
stat
.
execute
(
"insert into ToDateTest values(3, "
+
"TO_DATE('2015-12-12 08:00 A.M.', 'yyyy-MM-DD HH:MI AM'), "
+
"TO_DATE('2015-12-17 08:00 P.M.', 'YYYY-MM-DD HH:MI AM'))"
);
stat
.
execute
(
"insert into ToDateTest values(4, "
+
"TO_DATE(substr('2015-12-12 08:00 A.M.', 1, 10), 'yyyy-MM-DD'), "
+
"TO_DATE('2015-12-17 08:00 P.M.', 'YYYY-MM-DD HH:MI AM'))"
);
ResultSet
rs
=
stat
.
executeQuery
(
"select * from ToDateTest"
);
ResultSet
rs
=
stat
.
executeQuery
(
"select * from ToDateTest"
);
while
(
rs
.
next
())
{
while
(
rs
.
next
())
{
...
...
h2/src/test/org/h2/test/db/TestFunctions.java
浏览文件 @
19556a3e
...
@@ -52,7 +52,7 @@ import org.h2.tools.SimpleResultSet;
...
@@ -52,7 +52,7 @@ import org.h2.tools.SimpleResultSet;
import
org.h2.util.IOUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.New
;
import
org.h2.util.New
;
import
org.h2.util.StringUtils
;
import
org.h2.util.StringUtils
;
import
org.h2.util.ToDate
;
import
org.h2.util.ToDate
Parser
;
import
org.h2.value.Value
;
import
org.h2.value.Value
;
/**
/**
...
@@ -1283,119 +1283,129 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -1283,119 +1283,129 @@ public class TestFunctions extends TestBase implements AggregateFunction {
private
void
testToDateException
()
{
private
void
testToDateException
()
{
try
{
try
{
ToDate
.
TO_DATE
(
"1979-ThisWillFail-12"
,
"YYYY-MM-DD"
);
ToDate
Parser
.
toDate
(
"1979-ThisWillFail-12"
,
"YYYY-MM-DD"
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
assertEquals
(
DbException
.
class
.
getSimpleName
(),
e
.
getClass
().
getSimpleName
());
assertEquals
(
DbException
.
class
.
getSimpleName
(),
e
.
getClass
().
getSimpleName
());
}
}
}
}
private
void
testToDate
()
throws
SQLException
,
ParseException
{
private
void
testToDate
()
throws
ParseException
{
final
int
curM
onth
=
Calendar
.
getInstance
().
get
(
Calendar
.
MONTH
);
final
int
m
onth
=
Calendar
.
getInstance
().
get
(
Calendar
.
MONTH
);
Date
date
=
null
;
Date
date
=
null
;
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1979-11-12"
);
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1979-11-12"
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979-11-12"
,
"YYYY-MM-DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979-11-12"
,
"YYYY-MM-DD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979/11/12"
,
"YYYY/MM/DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979/11/12"
,
"YYYY/MM/DD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979,11,12"
,
"YYYY,MM,DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979,11,12"
,
"YYYY,MM,DD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979.11.12"
,
"YYYY.MM.DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979.11.12"
,
"YYYY.MM.DD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979;11;12"
,
"YYYY;MM;DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979;11;12"
,
"YYYY;MM;DD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979:11:12"
,
"YYYY:MM:DD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979:11:12"
,
"YYYY:MM:DD"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"1979"
);
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"1979"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979"
,
"YYYY"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979"
,
"YYYY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979 AD"
,
"YYYY AD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979 AD"
,
"YYYY AD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979 A.D."
,
"YYYY A.D."
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979 A.D."
,
"YYYY A.D."
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979 A.D."
,
"YYYY BC"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979 A.D."
,
"YYYY BC"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1979"
,
"IYYY"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1979"
,
"IYYY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"+1979"
,
"SYYYY"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"+1979"
,
"SYYYY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"79"
,
"RRRR"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"79"
,
"RRRR"
));
date
=
new
SimpleDateFormat
(
"yyyy-mm"
).
parse
(
"1970-12"
);
date
=
new
SimpleDateFormat
(
"yyyy-mm"
).
parse
(
"1970-12"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"12"
,
"MI"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"12"
,
"MI"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM"
).
parse
(
"1970-11"
);
date
=
new
SimpleDateFormat
(
"yyyy-MM"
).
parse
(
"1970-11"
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"11"
,
"MM"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"11"
,
"MM"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"11"
,
"Mm"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"11"
,
"Mm"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"11"
,
"mM"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"11"
,
"mM"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"11"
,
"mm"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"11"
,
"mm"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"XI"
,
"RM"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"XI"
,
"RM"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"9"
);
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"9"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"9"
,
"Y"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"9"
,
"Y"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"9"
,
"I"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"9"
,
"I"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"79"
);
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"79"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"79"
,
"YY"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"79"
,
"YY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"79"
,
"IY"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"79"
,
"IY"
));
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"979"
);
date
=
new
SimpleDateFormat
(
"yyyy"
).
parse
(
"979"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"979"
,
"YYY"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"979"
,
"YYY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"979"
,
"IYY"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"979"
,
"IYY"
));
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
date
=
new
SimpleDateFormat
(
"yyy"
).
parse
(
"-99"
);
date
=
new
SimpleDateFormat
(
"yyy"
).
parse
(
"-99"
);
date
.
setMonth
(
curMonth
);
setMonth
(
date
,
month
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"0100 BC"
,
"YYYY BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"0100 BC"
,
"YYYY BC"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"0100 B.C."
,
"YYYY B.C."
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"0100 B.C."
,
"YYYY B.C."
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"100 BC"
,
"YYY BC"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"100 BC"
,
"YYY BC"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"-0100"
,
"SYYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"-0100"
,
"SYYYY"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"-0100"
,
"YYYY"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"-0100"
,
"YYYY"
));
// Gregorian calendar does not have a year 0. 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
// Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
date
=
new
SimpleDateFormat
(
"y"
).
parse
(
"0"
);
date
=
new
SimpleDateFormat
(
"y"
).
parse
(
"0"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"01 BC"
,
"YY BC"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"01 BC"
,
"YY BC"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"1 BC"
,
"Y BC"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"1 BC"
,
"Y BC"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12 AM"
,
"HH:MI AM"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12 AM"
,
"HH:MI AM"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12 A.M."
,
"HH:MI A.M."
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12 A.M."
,
"HH:MI A.M."
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12"
,
"HH24:MI"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12"
,
"HH24:MI"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:00"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12"
,
"HH:MI"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12"
,
"HH:MI"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12"
,
"HH12:MI"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12"
,
"HH12:MI"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:34"
);
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"08:12:34"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12:34"
,
"HH:MI:SS"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12:34"
,
"HH:MI:SS"
));
date
=
new
SimpleDateFormat
(
"ss"
).
parse
(
"34"
);
date
=
new
SimpleDateFormat
(
"ss"
).
parse
(
"34"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"34"
,
"SS"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"34"
,
"SS"
));
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss"
).
parse
(
"1970 08:12:34"
);
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss"
).
parse
(
"1970 08:12:34"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"29554"
,
"SSSSS"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"29554"
,
"SSSSS"
));
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss SSS"
).
parse
(
"1970 08:12:34 550"
);
date
=
new
SimpleDateFormat
(
"yyyy hh:mm:ss SSS"
).
parse
(
"1970 08:12:34 550"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12:34 550"
,
"HH:MI:SS FF"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12:34 550"
,
"HH:MI:SS FF"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"08:12:34 55"
,
"HH:MI:SS FF2"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"08:12:34 55"
,
"HH:MI:SS FF2"
));
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"14:04:00"
);
date
=
new
SimpleDateFormat
(
"hh:mm:ss"
).
parse
(
"14:04:00"
);
date
.
setMonth
(
curM
onth
);
setMonth
(
date
,
m
onth
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"02:04 P.M."
,
"HH:MI p.M."
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"02:04 P.M."
,
"HH:MI p.M."
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"02:04 PM"
,
"HH:MI PM"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"02:04 PM"
,
"HH:MI PM"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1970-12-12"
);
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1970-12-12"
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"12"
,
"DD"
));
// does not work in all timezones
// assertEquals(date, ToDateParser.toDate("12", "DD"));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1970-11-12"
);
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"1970-11-12"
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"316"
,
"DDD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"316"
,
"DDD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"316"
,
"DdD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"316"
,
"DdD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"316"
,
"dDD"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"316"
,
"dDD"
));
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"316"
,
"ddd"
));
assertEquals
(
date
,
ToDate
Parser
.
toDate
(
"316"
,
"ddd"
));
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"2013-01-29"
);
date
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
).
parse
(
"2013-01-29"
);
assertEquals
(
date
,
ToDate
.
TO_DATE
(
"113029"
,
"J"
));
assertEquals
(
date
,
ToDateParser
.
toDate
(
"113029"
,
"J"
));
}
private
static
void
setMonth
(
Date
date
,
int
month
)
{
Calendar
c
=
Calendar
.
getInstance
();
c
.
setTime
(
date
);
c
.
set
(
Calendar
.
MONTH
,
month
);
date
.
setTime
(
c
.
getTimeInMillis
());
}
}
private
void
testToCharFromDateTime
()
throws
SQLException
{
private
void
testToCharFromDateTime
()
throws
SQLException
{
...
@@ -1907,7 +1917,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
...
@@ -1907,7 +1917,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
private
void
testAnnotationProcessorsOutput
()
throws
SQLException
{
private
void
testAnnotationProcessorsOutput
()
throws
SQLException
{
try
{
try
{
System
.
setProperty
(
TestAnnotationProcessor
.
MESSAGES_KEY
,
"WARNING,foo1|ERROR,foo2"
);
System
.
setProperty
(
TestAnnotationProcessor
.
MESSAGES_KEY
,
"WARNING,foo1|ERROR,foo2"
);
callCompiledFunction
(
"test_a
tp
_warn_and_error"
);
callCompiledFunction
(
"test_a
nnotation_processor
_warn_and_error"
);
fail
();
fail
();
}
catch
(
JdbcSQLException
e
)
{
}
catch
(
JdbcSQLException
e
)
{
assertEquals
(
ErrorCode
.
SYNTAX_ERROR_1
,
e
.
getErrorCode
());
assertEquals
(
ErrorCode
.
SYNTAX_ERROR_1
,
e
.
getErrorCode
());
...
...
h2/src/test/org/h2/test/db/TestOptimizations.java
浏览文件 @
19556a3e
...
@@ -1033,32 +1033,32 @@ public class TestOptimizations extends TestBase {
...
@@ -1033,32 +1033,32 @@ public class TestOptimizations extends TestBase {
deleteDb
(
"optimizations"
);
deleteDb
(
"optimizations"
);
Connection
conn
=
getConnection
(
"optimizations"
);
Connection
conn
=
getConnection
(
"optimizations"
);
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"CREATE TABLE T
BL
_A(id IDENTITY PRIMARY KEY NOT NULL, "
+
stat
.
execute
(
"CREATE TABLE T
ABLE
_A(id IDENTITY PRIMARY KEY NOT NULL, "
+
"name VARCHAR NOT NULL, active BOOLEAN DEFAULT TRUE, "
+
"name VARCHAR NOT NULL, active BOOLEAN DEFAULT TRUE, "
+
"UNIQUE KEY T
BL
_A_UK (name) )"
);
"UNIQUE KEY T
ABLE
_A_UK (name) )"
);
stat
.
execute
(
"CREATE TABLE T
BL
_B(id IDENTITY PRIMARY KEY NOT NULL, "
+
stat
.
execute
(
"CREATE TABLE T
ABLE
_B(id IDENTITY PRIMARY KEY NOT NULL, "
+
"
tbl
_a_id BIGINT NOT NULL, createDate TIMESTAMP DEFAULT NOW(), "
+
"
TABLE
_a_id BIGINT NOT NULL, createDate TIMESTAMP DEFAULT NOW(), "
+
"UNIQUE KEY T
BL_B_UK (tbl
_a_id, createDate), "
+
"UNIQUE KEY T
ABLE_B_UK (table
_a_id, createDate), "
+
"FOREIGN KEY (t
bl_a_id) REFERENCES TBL
_A(id) )"
);
"FOREIGN KEY (t
able_a_id) REFERENCES TABLE
_A(id) )"
);
stat
.
execute
(
"INSERT INTO T
BL
_A (name) SELECT 'package_' || CAST(X as VARCHAR) "
+
stat
.
execute
(
"INSERT INTO T
ABLE
_A (name) SELECT 'package_' || CAST(X as VARCHAR) "
+
"FROM SYSTEM_RANGE(1, 100) WHERE X <= 100"
);
"FROM SYSTEM_RANGE(1, 100) WHERE X <= 100"
);
stat
.
execute
(
"INSERT INTO T
BL_B (tbl
_a_id, createDate) SELECT "
+
stat
.
execute
(
"INSERT INTO T
ABLE_B (table
_a_id, createDate) SELECT "
+
"CASE WHEN t
bl_a_id = 0 THEN 1 ELSE tbl
_a_id END, createDate "
+
"CASE WHEN t
able_a_id = 0 THEN 1 ELSE table
_a_id END, createDate "
+
"FROM ( SELECT ROUND((RAND() * 100)) AS t
bl
_a_id, "
+
"FROM ( SELECT ROUND((RAND() * 100)) AS t
able
_a_id, "
+
"DATEADD('SECOND', X, NOW()) as createDate FROM SYSTEM_RANGE(1, 50000) "
+
"DATEADD('SECOND', X, NOW()) as createDate FROM SYSTEM_RANGE(1, 50000) "
+
"WHERE X < 50000 )"
);
"WHERE X < 50000 )"
);
stat
.
execute
(
"CREATE INDEX t
bl_b_idx ON tbl_b(tbl
_a_id, id)"
);
stat
.
execute
(
"CREATE INDEX t
able_b_idx ON table_b(table
_a_id, id)"
);
stat
.
execute
(
"ANALYZE"
);
stat
.
execute
(
"ANALYZE"
);
ResultSet
rs
=
stat
.
executeQuery
(
"EXPLAIN ANALYZE SELECT MAX(b.id) as id "
+
ResultSet
rs
=
stat
.
executeQuery
(
"EXPLAIN ANALYZE SELECT MAX(b.id) as id "
+
"FROM t
bl_b b JOIN tbl_a a ON b.tbl_a_id = a.id GROUP BY b.tbl
_a_id "
+
"FROM t
able_b b JOIN table_a a ON b.table_a_id = a.id GROUP BY b.table
_a_id "
+
"HAVING A.ACTIVE = TRUE"
);
"HAVING A.ACTIVE = TRUE"
);
rs
.
next
();
rs
.
next
();
assertContains
(
rs
.
getString
(
1
),
"/* PUBLIC.T
BL_B_IDX: TBL
_A_ID = A.ID */"
);
assertContains
(
rs
.
getString
(
1
),
"/* PUBLIC.T
ABLE_B_IDX: TABLE
_A_ID = A.ID */"
);
rs
=
stat
.
executeQuery
(
"EXPLAIN ANALYZE SELECT MAX(id) FROM t
bl_b GROUP BY tbl
_a_id"
);
rs
=
stat
.
executeQuery
(
"EXPLAIN ANALYZE SELECT MAX(id) FROM t
able_b GROUP BY table
_a_id"
);
rs
.
next
();
rs
.
next
();
assertContains
(
rs
.
getString
(
1
),
"/* PUBLIC.T
BL
_B_IDX"
);
assertContains
(
rs
.
getString
(
1
),
"/* PUBLIC.T
ABLE
_B_IDX"
);
conn
.
close
();
conn
.
close
();
}
}
}
}
h2/src/test/org/h2/test/db/TestTableEngines.java
浏览文件 @
19556a3e
...
@@ -351,15 +351,15 @@ public class TestTableEngines extends TestBase {
...
@@ -351,15 +351,15 @@ public class TestTableEngines extends TestBase {
deleteDb
(
"testQueryExpressionFlag"
);
deleteDb
(
"testQueryExpressionFlag"
);
Connection
conn
=
getConnection
(
"testQueryExpressionFlag"
);
Connection
conn
=
getConnection
(
"testQueryExpressionFlag"
);
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"create table QRY_EXPR_TEST(id int) ENGINE \""
+
stat
.
execute
(
"create table Q
UE
RY_EXPR_TEST(id int) ENGINE \""
+
TreeSetIndexTableEngine
.
class
.
getName
()
+
"\""
);
TreeSetIndexTableEngine
.
class
.
getName
()
+
"\""
);
stat
.
execute
(
"create table QRY_EXPR_TEST_NO(id int) ENGINE \""
+
stat
.
execute
(
"create table Q
UE
RY_EXPR_TEST_NO(id int) ENGINE \""
+
TreeSetIndexTableEngine
.
class
.
getName
()
+
"\""
);
TreeSetIndexTableEngine
.
class
.
getName
()
+
"\""
);
stat
.
executeQuery
(
"select 1 + (select 1 from QRY_EXPR_TEST)"
).
next
();
stat
.
executeQuery
(
"select 1 + (select 1 from Q
UE
RY_EXPR_TEST)"
).
next
();
stat
.
executeQuery
(
"select 1 from QRY_EXPR_TEST_NO where id in "
stat
.
executeQuery
(
"select 1 from Q
UE
RY_EXPR_TEST_NO where id in "
+
"(select id from QRY_EXPR_TEST)"
);
+
"(select id from Q
UE
RY_EXPR_TEST)"
);
stat
.
executeQuery
(
"select 1 from QRY_EXPR_TEST_NO n "
stat
.
executeQuery
(
"select 1 from Q
UE
RY_EXPR_TEST_NO n "
+
"where exists(select 1 from QRY_EXPR_TEST y where y.id = n.id)"
);
+
"where exists(select 1 from Q
UE
RY_EXPR_TEST y where y.id = n.id)"
);
deleteDb
(
"testQueryExpressionFlag"
);
deleteDb
(
"testQueryExpressionFlag"
);
}
}
...
@@ -621,7 +621,7 @@ public class TestTableEngines extends TestBase {
...
@@ -621,7 +621,7 @@ public class TestTableEngines extends TestBase {
setBatchingEnabled
(
stat
,
true
);
setBatchingEnabled
(
stat
,
true
);
List
<
List
<
Object
>>
actual
=
query
(
stat
,
sql
);
List
<
List
<
Object
>>
actual
=
query
(
stat
,
sql
);
if
(!
expected
.
equals
(
actual
))
{
if
(!
expected
.
equals
(
actual
))
{
fail
(
"\n
expected: "
+
expected
+
"\n
actual: "
+
actual
);
fail
(
"\n
"
+
"expected: "
+
expected
+
"\n"
+
"
actual: "
+
actual
);
}
}
}
}
...
@@ -699,10 +699,10 @@ public class TestTableEngines extends TestBase {
...
@@ -699,10 +699,10 @@ public class TestTableEngines extends TestBase {
private
static
void
setBatchSize
(
TreeSetTable
t
,
int
batchSize
)
{
private
static
void
setBatchSize
(
TreeSetTable
t
,
int
batchSize
)
{
if
(
t
.
getIndexes
()
==
null
)
{
if
(
t
.
getIndexes
()
==
null
)
{
t
.
scan
.
preferedBatchSize
=
batchSize
;
t
.
scan
.
prefer
r
edBatchSize
=
batchSize
;
}
else
{
}
else
{
for
(
Index
idx
:
t
.
getIndexes
())
{
for
(
Index
idx
:
t
.
getIndexes
())
{
((
TreeSetIndex
)
idx
).
preferedBatchSize
=
batchSize
;
((
TreeSetIndex
)
idx
).
prefer
r
edBatchSize
=
batchSize
;
}
}
}
}
}
}
...
@@ -746,7 +746,7 @@ public class TestTableEngines extends TestBase {
...
@@ -746,7 +746,7 @@ public class TestTableEngines extends TestBase {
t
>>>=
4
;
t
>>>=
4
;
}
}
if
(
where
.
length
()
!=
0
)
{
if
(
where
.
length
()
!=
0
)
{
b
.
append
(
"\nwhere "
).
append
(
where
);
b
.
append
(
"\n
"
+
"
where "
).
append
(
where
);
}
}
return
b
.
toString
();
return
b
.
toString
();
...
@@ -1313,7 +1313,7 @@ public class TestTableEngines extends TestBase {
...
@@ -1313,7 +1313,7 @@ public class TestTableEngines extends TestBase {
static
AtomicInteger
lookupBatches
=
new
AtomicInteger
();
static
AtomicInteger
lookupBatches
=
new
AtomicInteger
();
int
preferedBatchSize
;
int
prefer
r
edBatchSize
;
final
TreeSet
<
SearchRow
>
set
=
new
TreeSet
<
SearchRow
>(
this
);
final
TreeSet
<
SearchRow
>
set
=
new
TreeSet
<
SearchRow
>(
this
);
...
@@ -1337,8 +1337,8 @@ public class TestTableEngines extends TestBase {
...
@@ -1337,8 +1337,8 @@ public class TestTableEngines extends TestBase {
@Override
@Override
public
IndexLookupBatch
createLookupBatch
(
final
TableFilter
filter
)
{
public
IndexLookupBatch
createLookupBatch
(
final
TableFilter
filter
)
{
assert0
(
filter
.
getMasks
()
!=
null
||
"scan"
.
equals
(
getName
()),
"masks"
);
assert0
(
filter
.
getMasks
()
!=
null
||
"scan"
.
equals
(
getName
()),
"masks"
);
final
int
prefer
edSize
=
prefe
redBatchSize
;
final
int
prefer
redSize
=
prefer
redBatchSize
;
if
(
preferedSize
==
0
)
{
if
(
prefer
r
edSize
==
0
)
{
return
null
;
return
null
;
}
}
lookupBatches
.
incrementAndGet
();
lookupBatches
.
incrementAndGet
();
...
@@ -1351,7 +1351,7 @@ public class TestTableEngines extends TestBase {
...
@@ -1351,7 +1351,7 @@ public class TestTableEngines extends TestBase {
}
}
@Override
public
boolean
isBatchFull
()
{
@Override
public
boolean
isBatchFull
()
{
return
searchRows
.
size
()
>=
preferedSize
*
2
;
return
searchRows
.
size
()
>=
prefer
r
edSize
*
2
;
}
}
@Override
@Override
...
@@ -1490,9 +1490,9 @@ public class TestTableEngines extends TestBase {
...
@@ -1490,9 +1490,9 @@ public class TestTableEngines extends TestBase {
String
alias
=
alias
(
session
.
getSubQueryInfo
());
String
alias
=
alias
(
session
.
getSubQueryInfo
());
assert0
(
alias
.
equals
(
"ZZ"
),
"select expression sub-query: "
+
alias
);
assert0
(
alias
.
equals
(
"ZZ"
),
"select expression sub-query: "
+
alias
);
assert0
(
session
.
getSubQueryInfo
().
getUpper
()
==
null
,
"upper"
);
assert0
(
session
.
getSubQueryInfo
().
getUpper
()
==
null
,
"upper"
);
}
else
if
(
getTable
().
getName
().
equals
(
"QRY_EXPR_TEST"
))
{
}
else
if
(
getTable
().
getName
().
equals
(
"Q
UE
RY_EXPR_TEST"
))
{
assert0
(
session
.
isPreparingQueryExpression
(),
"preparing query expression"
);
assert0
(
session
.
isPreparingQueryExpression
(),
"preparing query expression"
);
}
else
if
(
getTable
().
getName
().
equals
(
"QRY_EXPR_TEST_NO"
))
{
}
else
if
(
getTable
().
getName
().
equals
(
"Q
UE
RY_EXPR_TEST_NO"
))
{
assert0
(!
session
.
isPreparingQueryExpression
(),
"not preparing query expression"
);
assert0
(!
session
.
isPreparingQueryExpression
(),
"not preparing query expression"
);
}
}
}
}
...
@@ -1588,7 +1588,7 @@ public class TestTableEngines extends TestBase {
...
@@ -1588,7 +1588,7 @@ public class TestTableEngines extends TestBase {
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
"IterCursor->"
+
current
;
return
"Iter
ator
Cursor->"
+
current
;
}
}
}
}
...
...
h2/src/test/org/h2/test/unit/TestDate.java
浏览文件 @
19556a3e
...
@@ -474,7 +474,8 @@ public class TestDate extends TestBase {
...
@@ -474,7 +474,8 @@ public class TestDate extends TestBase {
assertEquals
(
"-999-08-07 13:14:15.16"
,
ts1a
.
getString
());
assertEquals
(
"-999-08-07 13:14:15.16"
,
ts1a
.
getString
());
assertEquals
(
"19999-08-07 13:14:15.16"
,
ts2a
.
getString
());
assertEquals
(
"19999-08-07 13:14:15.16"
,
ts2a
.
getString
());
// test for bug on Java 1.8.0_60 in "Europe/Moscow" timezone. Doesn't affect most other timezones
// test for bug on Java 1.8.0_60 in "Europe/Moscow" timezone.
// Doesn't affect most other timezones
long
millis
=
1407437460000L
;
long
millis
=
1407437460000L
;
long
result1
=
DateTimeUtils
.
nanosFromDate
(
DateTimeUtils
.
getTimeUTCWithoutDst
(
millis
));
long
result1
=
DateTimeUtils
.
nanosFromDate
(
DateTimeUtils
.
getTimeUTCWithoutDst
(
millis
));
long
result2
=
DateTimeUtils
.
nanosFromDate
(
DateTimeUtils
.
getTimeUTCWithoutDst
(
millis
));
long
result2
=
DateTimeUtils
.
nanosFromDate
(
DateTimeUtils
.
getTimeUTCWithoutDst
(
millis
));
...
...
h2/src/test/org/h2/test/unit/TestTimeStampUtc.java
浏览文件 @
19556a3e
...
@@ -26,13 +26,13 @@ public class TestTimeStampUtc extends TestBase {
...
@@ -26,13 +26,13 @@ public class TestTimeStampUtc extends TestBase {
@Override
@Override
public
void
test
()
throws
SQLException
{
public
void
test
()
throws
SQLException
{
deleteDb
(
"timestamputc"
);
deleteDb
(
"timestamp
_
utc"
);
test1
();
test1
();
deleteDb
(
"timestamputc"
);
deleteDb
(
"timestamp
_
utc"
);
}
}
private
void
test1
()
throws
SQLException
{
private
void
test1
()
throws
SQLException
{
Connection
conn
=
getConnection
(
"timestamputc"
);
Connection
conn
=
getConnection
(
"timestamp
_
utc"
);
Statement
stat
=
conn
.
createStatement
();
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"create table test(id identity, t1 timestamp_utc)"
);
stat
.
execute
(
"create table test(id identity, t1 timestamp_utc)"
);
stat
.
execute
(
"insert into test(t1) values(0)"
);
stat
.
execute
(
"insert into test(t1) values(0)"
);
...
...
h2/src/tools/org/h2/build/BuildBase.java
浏览文件 @
19556a3e
...
@@ -308,9 +308,9 @@ public class BuildBase {
...
@@ -308,9 +308,9 @@ public class BuildBase {
protected
int
execScript
(
String
script
,
StringList
args
)
{
protected
int
execScript
(
String
script
,
StringList
args
)
{
if
(
isWindows
())
{
if
(
isWindows
())
{
// Under windows, we use the "cmd" command interpreter since it will
// Under windows, we use the "cmd" command interpreter since it will
// search the path for us without us having to hard
code an extensio
n
// search the path for us without us having to hard
-code a
n
//
for the script we want. (Sometimes we don't know if the extension
//
extension for the script we want. (Sometimes we don't know if the
// will be .bat or .cmd)
//
extension
will be .bat or .cmd)
StringList
newArgs
=
new
StringList
();
StringList
newArgs
=
new
StringList
();
newArgs
.
add
(
"/C"
);
newArgs
.
add
(
"/C"
);
newArgs
.
add
(
script
);
newArgs
.
add
(
script
);
...
...
h2/src/tools/org/h2/build/doc/dictionary.txt
浏览文件 @
19556a3e
...
@@ -778,10 +778,8 @@ dance schedule hitting reverted youngest footers inliner deadlocked reorder nger
...
@@ -778,10 +778,8 @@ dance schedule hitting reverted youngest footers inliner deadlocked reorder nger
nullid syspublic sysibmts sysibminternal syscat sysfun sysstat systools sysibmadm
nullid syspublic sysibmts sysibminternal syscat sysfun sysstat systools sysibmadm
sysproc jcc expecting gpg showed unreferenced activating cvf stephane lacoin
sysproc jcc expecting gpg showed unreferenced activating cvf stephane lacoin
centrale umr ecole nantes sticc lab reordering preferable simultaneously
centrale umr ecole nantes sticc lab reordering preferable simultaneously
lazily satisfy participating eviction globally futures batches slot forced
--- todo
diagnostic filer stamp turn going cancellation fetched produced incurring
interpreter batching fewer runners imperial correspond nine purge meridian
timestamputc lazily satisfy nexpected messager participating eviction milli globally
calendars moscow messager lookups unhandled buddha parslet
futures atp lookups batches slot nnext forced tbl diagnostic filer stamp turn going
tzh roc xii tzm viii myydd mar vii
nwhere hardcode cancellation qry nprev fetched produced nactual incurring interpreter
batching ncurr prefered fewer runners iter
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论