Skip to content

Commit 8e0bc87

Browse files
authored
Merge pull request #4393 from evolvedbinary/feature/dateTimeStamp
Add xs:dateTimeStamp datatype
2 parents cf2e17a + 93d975e commit 8e0bc87

File tree

11 files changed

+273
-15
lines changed

11 files changed

+273
-15
lines changed

exist-core/src/main/java/org/exist/xquery/OpNumeric.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ public String toString() {
229229
new OpEntry(ArithmeticOperator.ADDITION, Type.YEAR_MONTH_DURATION, Type.DATE_TIME, Type.DATE_TIME),
230230
new OpEntry(ArithmeticOperator.ADDITION, Type.DATE_TIME, Type.DAY_TIME_DURATION, Type.DATE_TIME),
231231
new OpEntry(ArithmeticOperator.ADDITION, Type.DAY_TIME_DURATION, Type.DATE_TIME, Type.DATE_TIME),
232+
new OpEntry(ArithmeticOperator.ADDITION, Type.DATE_TIME_STAMP, Type.YEAR_MONTH_DURATION, Type.DATE_TIME_STAMP),
233+
new OpEntry(ArithmeticOperator.ADDITION, Type.YEAR_MONTH_DURATION, Type.DATE_TIME_STAMP, Type.DATE_TIME_STAMP),
234+
new OpEntry(ArithmeticOperator.ADDITION, Type.DATE_TIME_STAMP, Type.DAY_TIME_DURATION, Type.DATE_TIME_STAMP),
235+
new OpEntry(ArithmeticOperator.ADDITION, Type.DAY_TIME_DURATION, Type.DATE_TIME_STAMP, Type.DATE_TIME_STAMP),
232236
new OpEntry(ArithmeticOperator.ADDITION, Type.YEAR_MONTH_DURATION, Type.YEAR_MONTH_DURATION, Type.YEAR_MONTH_DURATION),
233237
new OpEntry(ArithmeticOperator.ADDITION, Type.DAY_TIME_DURATION, Type.DAY_TIME_DURATION, Type.DAY_TIME_DURATION),
234238
new OpEntry(ArithmeticOperator.SUBTRACTION, Type.NUMBER, Type.NUMBER, Type.NUMBER),
@@ -240,6 +244,9 @@ public String toString() {
240244
new OpEntry(ArithmeticOperator.SUBTRACTION, Type.DATE_TIME, Type.DATE_TIME, Type.DAY_TIME_DURATION),
241245
new OpEntry(ArithmeticOperator.SUBTRACTION, Type.DATE_TIME, Type.YEAR_MONTH_DURATION, Type.DATE_TIME),
242246
new OpEntry(ArithmeticOperator.SUBTRACTION, Type.DATE_TIME, Type.DAY_TIME_DURATION, Type.DATE_TIME),
247+
new OpEntry(ArithmeticOperator.SUBTRACTION, Type.DATE_TIME_STAMP, Type.DATE_TIME_STAMP, Type.DAY_TIME_DURATION),
248+
new OpEntry(ArithmeticOperator.SUBTRACTION, Type.DATE_TIME_STAMP, Type.YEAR_MONTH_DURATION, Type.DATE_TIME_STAMP),
249+
new OpEntry(ArithmeticOperator.SUBTRACTION, Type.DATE_TIME_STAMP, Type.DAY_TIME_DURATION, Type.DATE_TIME_STAMP),
243250
new OpEntry(ArithmeticOperator.SUBTRACTION, Type.YEAR_MONTH_DURATION, Type.YEAR_MONTH_DURATION, Type.YEAR_MONTH_DURATION),
244251
new OpEntry(ArithmeticOperator.SUBTRACTION, Type.DAY_TIME_DURATION, Type.DAY_TIME_DURATION, Type.DAY_TIME_DURATION),
245252
new OpEntry(ArithmeticOperator.MULTIPLICATION, Type.NUMBER, Type.NUMBER, Type.NUMBER),

exist-core/src/main/java/org/exist/xquery/functions/fn/FunCurrentDateTime.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import org.exist.xquery.Profiler;
3333
import org.exist.xquery.XPathException;
3434
import org.exist.xquery.XQueryContext;
35-
import org.exist.xquery.value.DateTimeValue;
35+
import org.exist.xquery.value.DateTimeStampValue;
3636
import org.exist.xquery.value.FunctionReturnSequenceType;
3737
import org.exist.xquery.value.Item;
3838
import org.exist.xquery.value.Sequence;
@@ -48,12 +48,11 @@ public class FunCurrentDateTime extends Function {
4848
public final static FunctionSignature fnCurrentDateTime =
4949
new FunctionSignature(
5050
new QName("current-dateTime", Function.BUILTIN_FUNCTION_NS),
51-
"Returns the xs:dateTime (with timezone) that is current at some time " +
51+
"Returns the xs:dateTimeStamp (with timezone) that is current at some time " +
5252
"during the evaluation of a query or transformation in which " +
5353
"fn:current-dateTime() is executed.",
5454
null,
55-
//should be xs:dateTimeStamp, need to add support for DATE_TIME_STAMP
56-
new FunctionReturnSequenceType(Type.DATE_TIME,
55+
new FunctionReturnSequenceType(Type.DATE_TIME_STAMP,
5756
Cardinality.EXACTLY_ONE, "the date-time current " +
5857
"within query execution time span"));
5958

@@ -95,7 +94,7 @@ public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathExc
9594
{context.getProfiler().message(this, Profiler.START_SEQUENCES,
9695
"CONTEXT ITEM", contextItem.toSequence());}
9796
}
98-
Sequence result = new DateTimeValue(context.getCalendar());
97+
Sequence result = new DateTimeStampValue(context.getCalendar());
9998
if (isCalledAs("current-dateTime")) {
10099
// do nothing, result already in right form
101100
} else if (isCalledAs("current-date")) {
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* eXist-db Open Source Native XML Database
3+
* Copyright (C) 2001 The eXist-db Authors
4+
*
5+
6+
* http://www.exist-db.org
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* This library is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with this library; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
package org.exist.xquery.value;
23+
24+
import org.exist.xquery.ErrorCodes;
25+
import org.exist.xquery.XPathException;
26+
27+
import javax.xml.XMLConstants;
28+
29+
import javax.xml.datatype.DatatypeConstants;
30+
import javax.xml.datatype.XMLGregorianCalendar;
31+
import javax.xml.namespace.QName;
32+
33+
public class DateTimeStampValue extends DateTimeValue {
34+
35+
private static final QName XML_SCHEMA_TYPE = new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "dateTimeStamp");
36+
37+
public DateTimeStampValue(final XMLGregorianCalendar calendar) throws XPathException {
38+
super(calendar);
39+
checkValidTimezone();
40+
}
41+
42+
public DateTimeStampValue(final String dateTime) throws XPathException {
43+
super(dateTime);
44+
checkValidTimezone();
45+
}
46+
47+
private void checkValidTimezone() throws XPathException {
48+
if(calendar.getTimezone() == DatatypeConstants.FIELD_UNDEFINED) {
49+
throw new XPathException(ErrorCodes.ERROR, "Unable to create xs:dateTimeStamp, timezone missing.");
50+
}
51+
}
52+
53+
@Override
54+
public AtomicValue convertTo(final int requiredType) throws XPathException {
55+
switch (requiredType) {
56+
case Type.DATE_TIME_STAMP:
57+
return this;
58+
case Type.DATE_TIME:
59+
return new DateTimeValue(calendar);
60+
default: return
61+
super.convertTo(requiredType);
62+
}
63+
}
64+
65+
@Override
66+
protected AbstractDateTimeValue createSameKind(final XMLGregorianCalendar cal) throws XPathException {
67+
return new DateTimeStampValue(cal);
68+
}
69+
70+
@Override
71+
public int getType() {
72+
return Type.DATE_TIME_STAMP;
73+
}
74+
75+
@Override
76+
protected QName getXMLSchemaType() {
77+
return XML_SCHEMA_TYPE;
78+
}
79+
}

exist-core/src/main/java/org/exist/xquery/value/DateTimeValue.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ public AtomicValue convertTo(int requiredType) throws XPathException {
115115
case Type.ATOMIC:
116116
case Type.ITEM:
117117
return this;
118+
case Type.DATE_TIME_STAMP:
119+
return new DateTimeStampValue(calendar);
118120
case Type.DATE:
119121
return new DateValue(calendar);
120122
case Type.TIME:

exist-core/src/main/java/org/exist/xquery/value/OrderedDurationValue.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ public ComputableValue plus(ComputableValue other) throws XPathException {
153153
}
154154
case Type.TIME:
155155
case Type.DATE_TIME:
156+
case Type.DATE_TIME_STAMP:
156157
case Type.DATE:
157158
final AbstractDateTimeValue date = (AbstractDateTimeValue) other;
158159
final XMLGregorianCalendar gc = (XMLGregorianCalendar) date.calendar.clone();

exist-core/src/main/java/org/exist/xquery/value/StringValue.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,8 @@ public AtomicValue convertTo(int requiredType) throws XPathException {
494494
return new TimeValue(value);
495495
case Type.DATE:
496496
return new DateValue(value);
497+
case Type.DATE_TIME_STAMP:
498+
return new DateTimeStampValue(value);
497499
case Type.DURATION:
498500
return new DurationValue(value);
499501
case Type.YEAR_MONTH_DURATION:

exist-core/src/main/java/org/exist/xquery/value/Type.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ public class Type {
9191
public final static int GDAY = 58;
9292
public final static int GYEARMONTH = 59;
9393
public final static int GMONTHDAY = 71;
94+
public final static int DATE_TIME_STAMP = 72;
9495
public final static int TOKEN = 60;
9596
public final static int NORMALIZED_STRING = 61;
9697
public final static int LANGUAGE = 62;
@@ -158,7 +159,7 @@ public class Type {
158159
defineSubType(ATOMIC, UNTYPED_ATOMIC);
159160

160161
// DATE_TIME sub-types
161-
//defineSubType(DATE_TIME, DATE_TIME_STAMP);
162+
defineSubType(DATE_TIME, DATE_TIME_STAMP);
162163

163164
// DURATION sub-types
164165
defineSubType(DURATION, DAY_TIME_DURATION);
@@ -285,8 +286,7 @@ public class Type {
285286
defineBuiltInType(HEX_BINARY, "xs:hexBinary");
286287
defineBuiltInType(NOTATION, "xs:NOTATION");
287288

288-
//TODO add handling for xs:dateTimeStamp
289-
//defineBuiltInType(DATE_TIME_STAMP, "xs:dateTimeStamp");
289+
defineBuiltInType(DATE_TIME_STAMP, "xs:dateTimeStamp");
290290
defineBuiltInType(DATE_TIME, "xs:dateTime");
291291
defineBuiltInType(DATE, "xs:date");
292292
defineBuiltInType(TIME, "xs:time");
@@ -355,7 +355,7 @@ public class Type {
355355
DAY_TIME_DURATION
356356
});
357357
definePrimitiveType(DATE_TIME, new int[] {
358-
//DATE_TIME_STAMP
358+
DATE_TIME_STAMP
359359
});
360360
definePrimitiveType(TIME);
361361
definePrimitiveType(DATE);

exist-core/src/main/java/org/exist/xquery/value/UntypedAtomicValue.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ TODO replace UntypedAtomicValue with something that can allow lazily reading tex
106106

107107
case Type.DATE_TIME:
108108
return new DateTimeValue(value);
109+
case Type.DATE_TIME_STAMP:
110+
return new DateTimeStampValue(value);
109111
case Type.TIME:
110112
return new TimeValue(value);
111113
case Type.DATE:
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* eXist-db Open Source Native XML Database
3+
* Copyright (C) 2001 The eXist-db Authors
4+
*
5+
6+
* http://www.exist-db.org
7+
*
8+
* This library is free software; you can redistribute it and/or
9+
* modify it under the terms of the GNU Lesser General Public
10+
* License as published by the Free Software Foundation; either
11+
* version 2.1 of the License, or (at your option) any later version.
12+
*
13+
* This library is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
* Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public
19+
* License along with this library; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
*/
22+
package org.exist.xquery.value;
23+
24+
import org.exist.xquery.XPathException;
25+
import org.junit.Test;
26+
27+
import static org.junit.Assert.assertEquals;
28+
29+
public class DateTimeStampTest extends AbstractTimeRelatedTestCase {
30+
31+
32+
@Test(expected = XPathException.class)
33+
public void constructWithoutTimeZone() throws XPathException {
34+
new DateTimeStampValue("2005-10-11T10:00:00");
35+
}
36+
37+
@Test
38+
public void convertDateTimeWithTimeZoneToDateTimeStamp() throws XPathException {
39+
final DateTimeValue dateTimeValue = new DateTimeValue("2005-10-11T10:00:00Z");
40+
final AtomicValue value = dateTimeValue.convertTo(Type.DATE_TIME_STAMP);
41+
assertEquals(DateTimeStampValue.class, value.getClass());
42+
}
43+
44+
@Test(expected = XPathException.class)
45+
public void convertDateTimeWithoutTimeZoneToDateTimeStamp() throws XPathException {
46+
final DateTimeValue dateTimeValue = new DateTimeValue("2005-10-11T10:00:00");
47+
final AtomicValue value = dateTimeValue.convertTo(Type.DATE_TIME_STAMP);
48+
assertEquals(DateTimeStampValue.class, value.getClass());
49+
}
50+
51+
@Test()
52+
public void getTimezone() throws XPathException {
53+
final DateTimeStampValue value = new DateTimeStampValue("2005-10-11T10:00:00+10:00");
54+
assertEquals(10 * 60, value.calendar.getTimezone());
55+
}
56+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
(:
2+
: eXist-db Open Source Native XML Database
3+
: Copyright (C) 2001 The eXist-db Authors
4+
:
5+
6+
: http://www.exist-db.org
7+
:
8+
: This library is free software; you can redistribute it and/or
9+
: modify it under the terms of the GNU Lesser General Public
10+
: License as published by the Free Software Foundation; either
11+
: version 2.1 of the License, or (at your option) any later version.
12+
:
13+
: This library is distributed in the hope that it will be useful,
14+
: but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
: Lesser General Public License for more details.
17+
:
18+
: You should have received a copy of the GNU Lesser General Public
19+
: License along with this library; if not, write to the Free Software
20+
: Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
:)
22+
xquery version "3.0";
23+
24+
module namespace fd="http://exist-db.org/xquery/test/convert-dates";
25+
26+
declare namespace test="http://exist-db.org/xquery/xqsuite";
27+
28+
(: verify that we can convert xs:string to :xs:dateTimeStamp :)
29+
declare
30+
%test:args("2012-06-26T23:14:22.566+02:00")
31+
%test:assertEquals("11:14 pm on Tuesday, June 26th, 2012")
32+
function fd:format-dateTimeStamp($date as xs:dateTimeStamp) {
33+
format-dateTime($date, "[h00]:[m00] [P] on [FNn], [MNn] [D1o], [Y]", "en", (), ())
34+
};
35+
36+
(: verify that we can't convert xs:string without timezone to :xs:dateTimeStamp :)
37+
declare
38+
%test:args("2012-06-26T23:14:22.566")
39+
%test:assertError
40+
function fd:convert-date-time-stamp($date as xs:dateTimeStamp) {
41+
format-dateTime($date, "[h00]:[m00] [P] on [FNn], [MNn] [D1o], [Y]", "en", (), ())
42+
};
43+
44+
declare
45+
%test:args("2022-05-17T16:24:06.003+02:00", "PT2H")
46+
%test:assertEquals("2022-05-17T18:24:06.003+02:00")
47+
function fd:add-test($date as xs:dateTimeStamp, $duration as xs:dayTimeDuration) {
48+
$duration + $date
49+
};
50+
51+
52+
(: verify that fn:current-dateTime() return type is xs:dateTimeStamp :)
53+
declare
54+
%test:assertEquals("true")
55+
function fd:current-dateTime-type() {
56+
fn:current-dateTime() instance of xs:dateTimeStamp
57+
};
58+
59+
declare
60+
%test:args("2022-05-17T16:24:06.003+02:00", "PT2H")
61+
%test:assertEquals("true")
62+
function fd:return-type-test($date as xs:dateTimeStamp, $duration as xs:dayTimeDuration) {
63+
($duration + $date) instance of xs:dateTimeStamp
64+
};
65+
66+
declare
67+
%test:args("not-a-dateTimeStamp")
68+
%test:assertError
69+
function fd:not-a-dateTimeStamp($date as xs:dateTimeStamp) {
70+
$date instance of xs:dateTimeStamp
71+
};
72+
73+
declare
74+
%test:args("2022-05-17T17:16:00.000")
75+
%test:assertError
76+
function fd:not-a-dateTimeStamp2($date as xs:dateTimeStamp) {
77+
$date instance of xs:dateTimeStamp
78+
};
79+
80+
declare
81+
%test:args("2022-05-17T17:16:00.000Z")
82+
%test:assertEquals("true")
83+
function fd:create-dateTimeStamp($date as xs:dateTimeStamp) {
84+
$date instance of xs:dateTimeStamp
85+
};
86+
87+
declare
88+
%test:args("2022-05-17T17:16:00.000+01:00")
89+
%test:assertEquals("true")
90+
function fd:create-dateTimeStamp2($date as xs:dateTimeStamp) {
91+
$date instance of xs:dateTimeStamp
92+
};

0 commit comments

Comments
 (0)