diff --git a/basex-core/src/main/java/org/basex/query/func/fn/FnBuildDateTime.java b/basex-core/src/main/java/org/basex/query/func/fn/FnBuildDateTime.java index f55c28ae41..5c7dc8f19f 100644 --- a/basex-core/src/main/java/org/basex/query/func/fn/FnBuildDateTime.java +++ b/basex-core/src/main/java/org/basex/query/func/fn/FnBuildDateTime.java @@ -175,10 +175,10 @@ private static DTDur getDuration(final XQMap map, final Str key) throws QueryExc * Checks the year component for validity. * @param year the year to check * @param info input info for error reporting - * @throws QueryException if the year is out of range or zero + * @throws QueryException if the year is out of range */ private static void checkYear(final long year, final InputInfo info) throws QueryException { - if(year <= ADate.MIN_YEAR || year > ADate.MAX_YEAR || year == 0) + if(year <= ADate.MIN_YEAR || year > ADate.MAX_YEAR) throw INVDATETIMEVALUE_X_X.get(info, YEAR, year); } @@ -233,7 +233,7 @@ private static void checkDate(final long year, final long month, final long day, checkYear(year, info); checkMonth(month, info); checkDayOnly(day, info); - final int dom = ADate.daysOfMonth(year < 0 ? year + 1 : year, (int) month - 1); + final int dom = ADate.daysOfMonth(year, (int) month - 1); if(day > dom) throw INVDATETIMEVALUE_X_X.get(info, DAY, day); } diff --git a/basex-core/src/main/java/org/basex/query/value/item/ADate.java b/basex-core/src/main/java/org/basex/query/value/item/ADate.java index 008589f712..29f83867bb 100644 --- a/basex-core/src/main/java/org/basex/query/value/item/ADate.java +++ b/basex-core/src/main/java/org/basex/query/value/item/ADate.java @@ -32,7 +32,7 @@ public abstract class ADate extends ADateDur { /** Pattern for two digits. */ static final String DD = "(\\d{2})"; /** Year pattern. */ - static final String YEAR = "(-?(000[1-9]|00[1-9]\\d|0[1-9]\\d{2}|[1-9]\\d{3,}))"; + static final String YEAR = "(-?([1-9]\\d{3,}|0\\d{3}))"; /** Date pattern. */ static final String ZONE = "(([-+])" + DD + ':' + DD + "|Z)?"; /** Day per months. */ @@ -47,7 +47,7 @@ public abstract class ADate extends ADateDur { /** Year. * */ long year = Long.MAX_VALUE; @@ -110,8 +110,6 @@ final void date(final byte[] date, final String exp, final InputInfo info) throw final Matcher mt = DATE.matcher(Token.string(date).trim()); if(!mt.matches()) throw dateError(date, exp, info); year = toLong(mt.group(1), false, info); - // +1 is added to BC values to simplify computations - if(year < 0) year++; month = (byte) (Strings.toInt(mt.group(3)) - 1); day = (byte) (Strings.toInt(mt.group(4)) - 1); @@ -282,7 +280,7 @@ protected void tz(final DTDur dur, final boolean undefined, final InputInfo info @Override public final long yea() { - return year > 0 ? year : year - 1; + return year; } @Override @@ -339,7 +337,7 @@ public byte[] string(final InputInfo ii) { final TokenBuilder tb = new TokenBuilder(); final boolean ymd = year != Long.MAX_VALUE; if(ymd) { - if(year <= 0) tb.add('-'); + if(year < 0) tb.add('-'); prefix(tb, Math.abs(yea()), 4); tb.add('-'); prefix(tb, mon(), 2); @@ -427,7 +425,7 @@ private int compare(final Item item, final InputInfo info) throws QueryException @Override public final XMLGregorianCalendar toJava() { return DF.newXMLGregorianCalendar( - year == Long.MAX_VALUE ? null : BigInteger.valueOf(year > 0 ? year : year - 1), + year == Long.MAX_VALUE ? null : BigInteger.valueOf(year), month >= 0 ? month + 1 : Integer.MIN_VALUE, day >= 0 ? day + 1 : Integer.MIN_VALUE, hour >= 0 ? hour : Integer.MIN_VALUE, diff --git a/basex-core/src/main/java/org/basex/query/value/item/Dbl.java b/basex-core/src/main/java/org/basex/query/value/item/Dbl.java index f2ca098b1d..a0ab5cc0de 100644 --- a/basex-core/src/main/java/org/basex/query/value/item/Dbl.java +++ b/basex-core/src/main/java/org/basex/query/value/item/Dbl.java @@ -156,7 +156,7 @@ public static double parse(final byte[] value, final InputInfo info) throws Quer final byte[] v = Token.trim(value); if(Token.eq(v, Token.NAN)) return Double.NaN; - if(Token.eq(v, Token.POSITIVE_INF)) return Double.POSITIVE_INFINITY; + if(Token.eq(v, Token.POSITIVE_INF, Token.POSITIVE_INF_PLUS)) return Double.POSITIVE_INFINITY; if(Token.eq(v, Token.NEGATIVE_INF)) return Double.NEGATIVE_INFINITY; throw BasicType.DOUBLE.castError(value, info); } diff --git a/basex-core/src/main/java/org/basex/query/value/item/Dtm.java b/basex-core/src/main/java/org/basex/query/value/item/Dtm.java index 41a00519af..c4b72e01fb 100644 --- a/basex-core/src/main/java/org/basex/query/value/item/Dtm.java +++ b/basex-core/src/main/java/org/basex/query/value/item/Dtm.java @@ -140,7 +140,7 @@ public boolean comparable(final Item item) { * *

Components must be supplied in their lexical representation: * month 1–12, day 1–31, hours 0–23, minutes 0–59, seconds in [0–60). - * For BC years, pass a negative year (not 0). Undefined components must + * For BC years, pass a negative year or 0 (for year 0). Undefined components must * be {@code null}.

* *

This method is intended as a low-level construction helper for @@ -164,7 +164,7 @@ public static ADate buildUnchecked(final BasicType targetType, final Long hours, final Long minutes, final BigDecimal seconds, final DTDur zone, final InputInfo info) throws QueryException { final Dtm base = new Dtm(targetType); - base.year = year == null ? Long.MAX_VALUE : year < 0 ? year + 1 : year; + base.year = year == null ? Long.MAX_VALUE : year; base.month = month == null ? -1 : (byte) (month - 1); base.day = day == null ? -1 : (byte) (day - 1); base.hour = hours == null ? -1 : hours.byteValue(); diff --git a/basex-core/src/main/java/org/basex/query/value/item/Flt.java b/basex-core/src/main/java/org/basex/query/value/item/Flt.java index 7630c1da74..5a940f344f 100644 --- a/basex-core/src/main/java/org/basex/query/value/item/Flt.java +++ b/basex-core/src/main/java/org/basex/query/value/item/Flt.java @@ -141,7 +141,7 @@ public boolean equals(final Object obj) { public static float parse(final byte[] value, final InputInfo info) throws QueryException { final byte[] v = Token.trim(value); if(Token.eq(v, Token.NAN)) return Float.NaN; - if(Token.eq(v, Token.POSITIVE_INF)) return Float.POSITIVE_INFINITY; + if(Token.eq(v, Token.POSITIVE_INF, Token.POSITIVE_INF_PLUS)) return Float.POSITIVE_INFINITY; if(Token.eq(v, Token.NEGATIVE_INF)) return Float.NEGATIVE_INFINITY; if(!Token.eq(v, Token.POSITIVE_INFINITY, Token.NEGATIVE_INFINITY)) { try { diff --git a/basex-core/src/main/java/org/basex/query/value/item/GDt.java b/basex-core/src/main/java/org/basex/query/value/item/GDt.java index a61a1309e1..929a9babf5 100644 --- a/basex-core/src/main/java/org/basex/query/value/item/GDt.java +++ b/basex-core/src/main/java/org/basex/query/value/item/GDt.java @@ -65,8 +65,6 @@ public GDt(final byte[] date, final Type type, final InputInfo info) throws Quer if(i < 2) { year = toLong(mt.group(1), false, info); - // +1 is added to BC values to simplify computations - if(year < 0) year++; if(year < MIN_YEAR || year >= MAX_YEAR) throw DATERANGE_X_X.get(info, type, date); } if(i > 0 && i < 4) { @@ -105,7 +103,7 @@ public byte[] string(final InputInfo ii) { if(year == Long.MAX_VALUE) { tb.add('-'); } else { - if(year <= 0) tb.add('-'); + if(year < 0) tb.add('-'); prefix(tb, Math.abs(yea()), 4); } if(month >= 0 || day >= 0) tb.add('-'); diff --git a/basex-core/src/main/java/org/basex/util/Token.java b/basex-core/src/main/java/org/basex/util/Token.java index c3954d024b..47b2621b70 100644 --- a/basex-core/src/main/java/org/basex/util/Token.java +++ b/basex-core/src/main/java/org/basex/util/Token.java @@ -46,6 +46,8 @@ public final class Token { public static final byte[] NAN = token("NaN"); /** Token 'INF'. */ public static final byte[] POSITIVE_INF = token("INF"); + /** Token '+INF'. */ + public static final byte[] POSITIVE_INF_PLUS = token("+INF"); /** Token '-INF'. */ public static final byte[] NEGATIVE_INF = token("-INF"); /** Token 'Infinity'. */ diff --git a/basex-core/src/test/java/org/basex/query/func/FnModuleTest.java b/basex-core/src/test/java/org/basex/query/func/FnModuleTest.java index c657209399..70acae56b6 100644 --- a/basex-core/src/test/java/org/basex/query/func/FnModuleTest.java +++ b/basex-core/src/test/java/org/basex/query/func/FnModuleTest.java @@ -415,6 +415,8 @@ public final class FnModuleTest extends SandboxTest { + " \"timezone\": xs:dayTimeDuration('PT1H') }"), "---03+01:00"); query(func.args(" dateTime-record(day:=4)"), "---04"); + // year 0 + query(func.args(" {\"year\": 0, \"month\": 1, \"day\": 1}"), "0000-01-01"); // empty map error(func.args(" {}"), INVDATETIMEFIELDS_X); @@ -427,8 +429,6 @@ public final class FnModuleTest extends SandboxTest { // out of range component (minutes) error(func.args(" {\"hours\": 14, \"minutes\": 60, \"seconds\": 0," + " \"timezone\": xs:dayTimeDuration('PT1H') }"), INVDATETIMEVALUE_X_X); - // invalid year (0) - error(func.args(" {\"year\": 0}"), INVDATETIMEVALUE_X_X); // invalid date (March 0) error(func.args(" {\"year\": 2026, \"month\": 3, \"day\": 0," + " \"timezone\": xs:dayTimeDuration('PT1H') }"), INVDATETIMEVALUE_X_X); diff --git a/basex-core/src/test/java/org/basex/query/simple/SimpleTest.java b/basex-core/src/test/java/org/basex/query/simple/SimpleTest.java index 2718b52e26..ab5a690036 100644 --- a/basex-core/src/test/java/org/basex/query/simple/SimpleTest.java +++ b/basex-core/src/test/java/org/basex/query/simple/SimpleTest.java @@ -25,6 +25,7 @@ public final class SimpleTest extends QueryTest { { "Float 6", "xs:float('-infinity')" }, { "Float 7", booleans(true), "xs:float('-INF') < 0" }, { "Float 8", "xs:float('-inf')" }, + { "Float 9", booleans(true), "xs:float('+INF') > 0" }, { "Double 1", "xs:double('Infinity')" }, { "Double 2", "xs:double('infinity')" }, @@ -34,6 +35,7 @@ public final class SimpleTest extends QueryTest { { "Double 6", "xs:double('-infinity')" }, { "Double 7", booleans(true), "xs:double('-INF') < 0" }, { "Double 8", "xs:double('-inf')" }, + { "Double 9", booleans(true), "xs:double('+INF') > 0" }, { "UnsignedLong 1", booleans(false), "xs:unsignedLong('3') eq 3.1"}, { "UnsignedLong 2", booleans(false), "3.1 eq xs:unsignedLong('3')"},