checkpoint: Updated the format-based temporal parsers to support
multiple format options; added comments for the parsing class.
diff --git a/asterix-app/src/test/resources/runtimets/queries/temporal/parse_01/parse_01.3.query.aql b/asterix-app/src/test/resources/runtimets/queries/temporal/parse_01/parse_01.3.query.aql
index 16c55dc..53e1285 100644
--- a/asterix-app/src/test/resources/runtimets/queries/temporal/parse_01/parse_01.3.query.aql
+++ b/asterix-app/src/test/resources/runtimets/queries/temporal/parse_01/parse_01.3.query.aql
@@ -5,6 +5,18 @@
use dataverse test;
-{ "date1": parse-date("2013-8-23", "YY-M-D"), "date2": parse-date("Aug 12 -12", "MMM D Y"), "date3": parse-date("-1234-01-01", "YYYY-MM-DD"), "date4": parse-date("09/11/-1980", "D/M/Y"),
- "time1": parse-time("8:23:49", "h:m:s"), "time2": parse-time("8.19.23:32", "h.m.s:nn"), "time3": parse-time("08.19.23:32 pm", "h.m.s:nn a"), "time4": parse-time("6:30:40.948 pm PST", "h:mm:ss.nnn a z"),
- "datetime1": parse-datetime("Dec 30 -1203 3:48:27 PM", "MMM DD YYYY h:m:s a"), "datetime2": parse-datetime("12/30/-1203 03:48:27.392 PM Asia/Shanghai", "MM/DD/YYY hh:mm:ss.nnn a z"), "datetime3": parse-datetime("1723-12-03T23:59:23.392Z", "YYYY-MM-DDThh:mm:ss.nnnz"), "datetime4": parse-datetime("1723-12-03T23:59:23.392-04:00", "YYYY-MM-DDThh:mm:ss.nnnz") }
\ No newline at end of file
+{ "date1": parse-date("2013-8-23", "YY-M-D"),
+ "date2": parse-date("Aug 12 -12", "MMM D Y"),
+ "date3": parse-date("-1234-01-01", "YYYY-MM-DD"),
+ "date4": parse-date("09/11/-1980", "D/M/Y"),
+ "date5": parse-date("09/11/-1990", "YY-M-D|MMM D Y|D/M/Y"),
+ "time1": parse-time("8:23:49", "h:m:s"),
+ "time2": parse-time("8.19.23:32", "h.m.s:nn"),
+ "time3": parse-time("08.19.23:32 pm", "h.m.s:nn a"),
+ "time4": parse-time("6:30:40.948 pm PST", "h:mm:ss.nnn a z"),
+ "time5": parse-time("6:30:40.948 pm PST", "h:m:s|h.m.s:nn|h.m.s:nn a|h:mm:ss.nnn a z"),
+ "datetime1": parse-datetime("Dec 30 -1203 3:48:27 PM", "MMM DD YYYY h:m:s a"),
+ "datetime2": parse-datetime("12/30/-1203 03:48:27.392 PM Asia/Shanghai", "MM/DD/YYY hh:mm:ss.nnn a z"),
+ "datetime3": parse-datetime("1723-12-03T23:59:23.392Z", "YYYY-MM-DDThh:mm:ss.nnnz"),
+ "datetime4": parse-datetime("1723-12-03T23:59:23.392-04:00", "YYYY-MM-DDThh:mm:ss.nnnz"),
+ "datetime5": parse-datetime("1723-12-03T23:59:23.392-04:00", "MMM DD YYYY h:m:s a|MM/DD/YYY hh:mm:ss.nnn a z|YYYY-MM-DDThh:mm:ss.nnnz") }
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/results/temporal/parse_01/parse_01.1.adm b/asterix-app/src/test/resources/runtimets/results/temporal/parse_01/parse_01.1.adm
index 67c3941..f86335c 100644
--- a/asterix-app/src/test/resources/runtimets/results/temporal/parse_01/parse_01.1.adm
+++ b/asterix-app/src/test/resources/runtimets/results/temporal/parse_01/parse_01.1.adm
@@ -1 +1 @@
-{ "date1": date("2013-08-23"), "date2": date("-0012-08-12"), "date3": date("-1234-01-01"), "date4": date("-1980-11-09"), "time1": time("08:23:49.000Z"), "time2": time("08:19:23.320Z"), "time3": time("20:19:23.320Z"), "time4": time("10:30:40.948Z"), "datetime1": datetime("-1203-12-30T15:48:27.000Z"), "datetime2": datetime("-1203-12-30T23:48:27.392Z"), "datetime3": datetime("1723-12-03T23:59:23.392Z"), "datetime4": datetime("1723-12-04T03:59:23.392Z") }
\ No newline at end of file
+{ "date1": date("2013-08-23"), "date2": date("-0012-08-12"), "date3": date("-1234-01-01"), "date4": date("-1980-11-09"), "date5": date("-1990-11-09"), "time1": time("08:23:49.000Z"), "time2": time("08:19:23.320Z"), "time3": time("20:19:23.320Z"), "time4": time("10:30:40.948Z"), "time5": time("10:30:40.948Z"), "datetime1": datetime("-1203-12-30T15:48:27.000Z"), "datetime2": datetime("-1203-12-30T23:48:27.392Z"), "datetime3": datetime("1723-12-03T23:59:23.392Z"), "datetime4": datetime("1723-12-04T03:59:23.392Z"), "datetime5": datetime("1723-12-04T03:59:23.392Z") }
\ No newline at end of file
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/AsterixTemporalTypeParseException.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/AsterixTemporalTypeParseException.java
new file mode 100644
index 0000000..9354d5f
--- /dev/null
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/AsterixTemporalTypeParseException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2009-2013 by The Regents of the University of California
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * you may obtain a copy of the License from
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package edu.uci.ics.asterix.om.base.temporal;
+
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+
+public class AsterixTemporalTypeParseException extends HyracksDataException {
+
+ private static final long serialVersionUID = 1L;
+
+ public AsterixTemporalTypeParseException() {
+ super();
+ }
+
+ public AsterixTemporalTypeParseException(Exception ex) {
+ super(ex);
+ }
+
+ public AsterixTemporalTypeParseException(String msg) {
+ super(msg);
+ }
+
+}
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/DateTimeFormatUtils.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/DateTimeFormatUtils.java
index 31d7263..bd74ad4 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/DateTimeFormatUtils.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/DateTimeFormatUtils.java
@@ -23,7 +23,26 @@
/**
* {@link DateTimeFormatUtils} provides the utility methods to parse and print a date/time/datetime
- * value based on the given format string.
+ * value based on the given format string. The format string may contain the following <b>format characters</b> (note that
+ * format string is <b>case-sensitive</b>):
+ * <p/>
+ * - <b>Y</b>: a digit for the year field. At most 4 year format characters are allowed for a valid format string.<br/>
+ * - <b>M</b>: a digit or character for the month field. At most 3 month format characters are allowed for a valid format string. When three month format characters are used, the shorten month names (like JAN, FEB etc.) are expected in the string to be parsed. Otherwise digits are expected.<br/>
+ * - <b>D</b>: a digit for the day field. At most 2 day format characters are allowed.<br/>
+ * - <b>h</b>: a digit for the hour field. At most 2 hour format characters are allowed.<br/>
+ * - <b>m</b>: a digit for the minute field. At most 2 minute format characters are allowed.<br/>
+ * - <b>s</b>: a digit for the second field. At most 2 second format characters are allowed.<br/>
+ * - <b>n</b>: a digit for the millisecond field. At most 3 millisecond format characters are allowed.<br/>
+ * - <b>a</b>: the AM/PM field. At most 1 am/pm format character is allowed, and it matches with AM and PM case-insensitively. <br/>
+ * - <b>z</b>: the timezone field. At most 1 timezone format characters are allowed. The valid timezone string matching with this format character include:<br/>
+ * -- <b>Z</b>: a single upper-case character representing the UTC timezone;<br/>
+ * -- <b>[UTC|GMT]+xx[:]xx</b>: representing a timezone by providing the actual offset time from the UTC time;<br/>
+ * -- A string representation of a timezone like PST, Asia/Shanghai. The names of the timezones are following the Zoneinfo database provided by the JDK library. See {@link TimeZone} for more details on this.<br/>
+ * - <b>Separators</b>: separators that can be used to separate the different fields. Currently only the following characters can be used as separator: <b>-(hyphen), :(colon), /(solidus), .(period) and ,(comma)</b>.
+ * <p/>
+ * For the matching algorithm, both the format string and the data string are scanned from the beginning to the end, and the algorithm tried to match the format with the characters/digits/separators in the data string. The format string represents the <b>minimum</b> length of the required field (similar to the C-style printf formatting). This means that something like a year <it>1990</it> will match with the format strings <it>Y, YY, YYY and YYYY</it>.
+ * <p/>
+ * If the given string cannot be parsed by the given format string, an {@link AsterixTemporalTypeParseException} will be returned.
*/
public class DateTimeFormatUtils {
@@ -199,12 +218,6 @@
return -1;
}
- private void append(Appendable appender, byte[] bs) throws IOException {
- for (int i = 0; i < bs.length; i++) {
- appender.append((char) bs[i]);
- }
- }
-
private byte toLower(byte b) {
if (b >= 'A' && b <= 'Z') {
return (byte) (b - TO_LOWER_OFFSET);
@@ -220,7 +233,7 @@
}
public long parseDateTime(byte[] data, int dataStart, int dataLength, byte[] format, int formatStart,
- int formatLength, DateTimeParseMode parseMode) throws HyracksDataException {
+ int formatLength, DateTimeParseMode parseMode) throws AsterixTemporalTypeParseException {
int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0, ms = 0, timezone = 0;
boolean negativeYear = false;
@@ -321,8 +334,8 @@
break;
default:
- throw new HyracksDataException("Unexpected date format string at " + (formatStart + formatPointer)
- + ": " + format[formatStart + formatPointer]);
+ throw new AsterixTemporalTypeParseException("Unexpected date format string at "
+ + (formatStart + formatPointer) + ": " + format[formatStart + formatPointer]);
}
// check whether the process state is valid for the parse mode
@@ -332,7 +345,8 @@
case MONTH:
case DAY:
if (parseMode == DateTimeParseMode.TIME_ONLY) {
- throw new HyracksDataException("Unexpected date format string when parsing a time value");
+ throw new AsterixTemporalTypeParseException(
+ "Unexpected date format string when parsing a time value");
}
break;
case HOUR:
@@ -342,7 +356,8 @@
case AMPM:
case TIMEZONE:
if (parseMode == DateTimeParseMode.DATE_ONLY) {
- throw new HyracksDataException("Unexpected time format string when parsing a date value");
+ throw new AsterixTemporalTypeParseException(
+ "Unexpected time format string when parsing a date value");
}
break;
default:
@@ -364,7 +379,7 @@
int processedFieldsCount = 0;
for (int i = 0; i < formatCharCopies; i++) {
if (data[dataStart + dataStringPointer] < '0' || data[dataStart + dataStringPointer] > '9') {
- throw new HyracksDataException("Unexpected char for year field at "
+ throw new AsterixTemporalTypeParseException("Unexpected char for year field at "
+ (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
}
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
@@ -395,22 +410,22 @@
month = monthNameMatch + 1;
dataStringPointer += 3;
} else {
- throw new HyracksDataException("Unrecognizable month string "
- + data[dataStart + dataStringPointer] + " "
- + data[dataStart + dataStringPointer + 1] + " "
- + data[dataStart + dataStringPointer + 2]);
+ throw new AsterixTemporalTypeParseException("Unrecognizable month string "
+ + (char) data[dataStart + dataStringPointer] + " "
+ + (char) data[dataStart + dataStringPointer + 1] + " "
+ + (char) data[dataStart + dataStringPointer + 2]);
}
} else {
int processedMonthFieldsCount = 0;
for (int i = 0; i < formatCharCopies; i++) {
if (data[dataStart + dataStringPointer] < '0' || data[dataStart + dataStringPointer] > '9') {
- throw new HyracksDataException("Unexpected char for month field at "
+ throw new AsterixTemporalTypeParseException("Unexpected char for month field at "
+ (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
}
month = month * 10 + (data[dataStart + dataStringPointer] - '0');
dataStringPointer++;
if (processedMonthFieldsCount++ > 2) {
- throw new HyracksDataException("Unexpected char for month field at "
+ throw new AsterixTemporalTypeParseException("Unexpected char for month field at "
+ (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
}
}
@@ -433,14 +448,15 @@
parsedValue = 0;
for (int i = 0; i < formatCharCopies; i++) {
if (data[dataStart + dataStringPointer] < '0' || data[dataStart + dataStringPointer] > '9') {
- throw new HyracksDataException("Unexpected char for " + processState.name() + " field at "
- + (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
+ throw new AsterixTemporalTypeParseException("Unexpected char for " + processState.name()
+ + " field at " + (dataStart + dataStringPointer) + ": "
+ + data[dataStart + dataStringPointer]);
}
parsedValue = parsedValue * 10 + (data[dataStart + dataStringPointer] - '0');
dataStringPointer++;
if (processFieldsCount++ > expectedMaxCount) {
- throw new HyracksDataException("Unexpected char for " + processState.name() + " field at "
- + dataStringPointer + ": " + data[dataStart + dataStringPointer]);
+ throw new AsterixTemporalTypeParseException("Unexpected char for " + processState.name()
+ + " field at " + dataStringPointer + ": " + data[dataStart + dataStringPointer]);
}
}
// if there are more than formatCharCopies digits for the hour string
@@ -471,6 +487,7 @@
+ dataStringPointer + 1] > 'z'))) {
// UTC as Z
timezone = 0;
+ dataStringPointer++;
} else if ((data[dataStart + dataStringPointer] == '+' || data[dataStart + dataStringPointer] == '-')
|| (dataStringPointer + 3 < dataLength && (data[dataStart + dataStringPointer + 3] == '+' || data[dataStart
+ dataStringPointer + 3] == '-'))) {
@@ -488,7 +505,7 @@
} else if (data[dataStart + dataStringPointer] == '+') {
dataStringPointer++;
} else {
- throw new HyracksDataException(
+ throw new AsterixTemporalTypeParseException(
"Incorrect timezone hour field: expecting sign + or - but got: "
+ data[dataStart + dataStringPointer]);
}
@@ -498,8 +515,10 @@
&& data[dataStart + dataStringPointer + i] <= '9') {
timezone += (data[dataStart + dataStringPointer + i] - '0') * MS_PER_HOUR;
} else {
- throw new HyracksDataException("Unexpected character for timezone hour field at "
- + (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
+ throw new AsterixTemporalTypeParseException(
+ "Unexpected character for timezone hour field at "
+ + (dataStart + dataStringPointer) + ": "
+ + data[dataStart + dataStringPointer]);
}
}
dataStringPointer += 2;
@@ -513,8 +532,10 @@
&& data[dataStart + dataStringPointer + i] <= '9') {
timezone += (data[dataStart + dataStringPointer + i] - '0') * MS_PER_MINUTE;
} else {
- throw new HyracksDataException("Unexpected character for timezone minute field at "
- + (dataStart + dataStringPointer) + ": " + data[dataStart + dataStringPointer]);
+ throw new AsterixTemporalTypeParseException(
+ "Unexpected character for timezone minute field at "
+ + (dataStart + dataStringPointer) + ": "
+ + data[dataStart + dataStringPointer]);
}
}
dataStringPointer += 2;
@@ -539,7 +560,7 @@
if (searchIdx >= 0) {
timezone = TIMEZONE_OFFSETS[searchIdx];
} else {
- throw new HyracksDataException("Unexpected timezone string: "
+ throw new AsterixTemporalTypeParseException("Unexpected timezone string: "
+ new String(Arrays.copyOfRange(data, dataStart + dataStringPointer, dataStart
+ dataStringPointer)));
}
@@ -559,33 +580,44 @@
hour = 0;
}
} else {
- throw new HyracksDataException("Unexpected string for AM/PM marker "
+ throw new AsterixTemporalTypeParseException("Unexpected string for AM/PM marker "
+ new String(Arrays.copyOfRange(data, dataStart + dataStringPointer, dataStart
+ dataStringPointer + 2)));
}
dataStringPointer += 2;
} else {
- throw new HyracksDataException("Cannot find valid AM/PM marker.");
+ throw new AsterixTemporalTypeParseException("Cannot find valid AM/PM marker.");
}
break;
case SEPARATOR:
if (separatorChar == '\0') {
- throw new HyracksDataException("Incorrect separator char in date string as "
+ throw new AsterixTemporalTypeParseException("Incorrect separator char in date string as "
+ data[dataStart + dataStringPointer]);
}
for (int i = 0; i < formatCharCopies; i++) {
if (data[dataStart + dataStringPointer] != separatorChar) {
- throw new HyracksDataException("Expecting separator " + separatorChar + " but got "
- + data[dataStart + dataStringPointer]);
+ throw new AsterixTemporalTypeParseException("Expecting separator " + separatorChar
+ + " but got " + data[dataStart + dataStringPointer]);
}
dataStringPointer++;
}
break;
default:
- throw new HyracksDataException("Unexpected time format information when parsing a date value");
+ throw new AsterixTemporalTypeParseException(
+ "Unexpected time format information when parsing a date value");
}
}
+ if (dataStringPointer < dataLength) {
+ throw new AsterixTemporalTypeParseException(
+ "The given data string is not fully parsed by the given format string");
+ }
+
+ if (formatPointer < formatLength) {
+ throw new AsterixTemporalTypeParseException(
+ "The given format string is not fully used for the given format string");
+ }
+
if (parseMode == DateTimeParseMode.TIME_ONLY) {
return CAL.getChronon(hour, min, sec, ms, timezone);
}
@@ -752,7 +784,7 @@
case MONTH:
if (processState == DateTimeProcessState.MONTH && formatCharCopies == 3) {
for (byte b : MONTH_NAMES[month - 1]) {
- appender.append((char)toUpper(b));
+ appender.append((char) toUpper(b));
}
break;
}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseDateDescriptor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseDateDescriptor.java
index 4a4dff4..782d424 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseDateDescriptor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseDateDescriptor.java
@@ -20,6 +20,7 @@
import edu.uci.ics.asterix.om.base.ADate;
import edu.uci.ics.asterix.om.base.AMutableDate;
import edu.uci.ics.asterix.om.base.ANull;
+import edu.uci.ics.asterix.om.base.temporal.AsterixTemporalTypeParseException;
import edu.uci.ics.asterix.om.base.temporal.DateTimeFormatUtils;
import edu.uci.ics.asterix.om.base.temporal.GregorianCalendarSystem;
import edu.uci.ics.asterix.om.base.temporal.DateTimeFormatUtils.DateTimeParseMode;
@@ -40,6 +41,11 @@
import edu.uci.ics.hyracks.data.std.util.ArrayBackedValueStorage;
import edu.uci.ics.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+/**
+ * <b>|(bar)</b> is a special separator used to separate different formatting options.
+ * Multiple format strings can be used by separating them using <b>|(bar)</b>, and the parsing will be successful only when the format string has the <b>exact</b> match with the given data string. This means that a time string like <it>08:23:12 AM</it> will not be valid for the format string <it>h:m:s</it> as there is no AM/PM format character in the format string.
+ * <p/>
+ */
public class ParseDateDescriptor extends AbstractScalarFunctionDynamicDescriptor {
private static final long serialVersionUID = 1L;
@@ -109,8 +115,34 @@
+ (argOut0.getByteArray()[2] & 0xff << 0);
int length1 = (argOut1.getByteArray()[1] & 0xff << 8)
+ (argOut1.getByteArray()[2] & 0xff << 0);
- long chronon = DT_UTILS.parseDateTime(argOut0.getByteArray(), 3, length0,
- argOut1.getByteArray(), 3, length1, DateTimeParseMode.DATE_ONLY);
+ long chronon = 0;
+
+ int formatStart = 3;
+ int formatLength = 0;
+ boolean processSuccessfully = false;
+ while (!processSuccessfully && formatStart < 3 + length1) {
+ // search for "|"
+ formatLength = 0;
+ for (; formatStart + formatLength < 3 + length1; formatLength++) {
+ if (argOut1.getByteArray()[formatStart + formatLength] == '|') {
+ break;
+ }
+ }
+ try {
+ chronon = DT_UTILS.parseDateTime(argOut0.getByteArray(), 3, length0,
+ argOut1.getByteArray(), formatStart, formatLength,
+ DateTimeParseMode.DATE_ONLY);
+ } catch (AsterixTemporalTypeParseException ex) {
+ formatStart += formatLength + 1;
+ continue;
+ }
+ processSuccessfully = true;
+ }
+
+ if (!processSuccessfully) {
+ throw new HyracksDataException(
+ "parse-date: Failed to match with any given format string!");
+ }
aDate.setValue((int) (chronon / GregorianCalendarSystem.CHRONON_OF_DAY));
dateSerde.serialize(aDate, out);
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseDateTimeDescriptor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseDateTimeDescriptor.java
index f679839..89cfbe5 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseDateTimeDescriptor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseDateTimeDescriptor.java
@@ -20,6 +20,7 @@
import edu.uci.ics.asterix.om.base.ADateTime;
import edu.uci.ics.asterix.om.base.AMutableDateTime;
import edu.uci.ics.asterix.om.base.ANull;
+import edu.uci.ics.asterix.om.base.temporal.AsterixTemporalTypeParseException;
import edu.uci.ics.asterix.om.base.temporal.DateTimeFormatUtils;
import edu.uci.ics.asterix.om.base.temporal.DateTimeFormatUtils.DateTimeParseMode;
import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
@@ -108,8 +109,34 @@
+ (argOut0.getByteArray()[2] & 0xff << 0);
int length1 = (argOut1.getByteArray()[1] & 0xff << 8)
+ (argOut1.getByteArray()[2] & 0xff << 0);
- long chronon = DT_UTILS.parseDateTime(argOut0.getByteArray(), 3, length0,
- argOut1.getByteArray(), 3, length1, DateTimeParseMode.DATETIME);
+ long chronon = 0;
+
+ int formatStart = 3;
+ int formatLength = 0;
+ boolean processSuccessfully = false;
+ while (!processSuccessfully && formatStart < 3 + length1) {
+ // search for "|"
+ formatLength = 0;
+ for (; formatStart + formatLength < 3 + length1; formatLength++) {
+ if (argOut1.getByteArray()[formatStart + formatLength] == '|') {
+ break;
+ }
+ }
+ try {
+ chronon = DT_UTILS.parseDateTime(argOut0.getByteArray(), 3, length0,
+ argOut1.getByteArray(), formatStart, formatLength,
+ DateTimeParseMode.DATETIME);
+ } catch (AsterixTemporalTypeParseException ex) {
+ formatStart += formatLength + 1;
+ continue;
+ }
+ processSuccessfully = true;
+ }
+
+ if (!processSuccessfully) {
+ throw new HyracksDataException(
+ "parse-date: Failed to match with any given format string!");
+ }
aDateTime.setValue(chronon);
datetimeSerde.serialize(aDateTime, out);
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseTimeDescriptor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseTimeDescriptor.java
index b92db54..8ee76e7 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseTimeDescriptor.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/ParseTimeDescriptor.java
@@ -20,6 +20,7 @@
import edu.uci.ics.asterix.om.base.AMutableTime;
import edu.uci.ics.asterix.om.base.ANull;
import edu.uci.ics.asterix.om.base.ATime;
+import edu.uci.ics.asterix.om.base.temporal.AsterixTemporalTypeParseException;
import edu.uci.ics.asterix.om.base.temporal.DateTimeFormatUtils;
import edu.uci.ics.asterix.om.base.temporal.DateTimeFormatUtils.DateTimeParseMode;
import edu.uci.ics.asterix.om.functions.AsterixBuiltinFunctions;
@@ -108,8 +109,34 @@
+ (argOut0.getByteArray()[2] & 0xff << 0);
int length1 = (argOut1.getByteArray()[1] & 0xff << 8)
+ (argOut1.getByteArray()[2] & 0xff << 0);
- long chronon = DT_UTILS.parseDateTime(argOut0.getByteArray(), 3, length0,
- argOut1.getByteArray(), 3, length1, DateTimeParseMode.TIME_ONLY);
+ long chronon = 0;
+
+ int formatStart = 3;
+ int formatLength = 0;
+ boolean processSuccessfully = false;
+ while (!processSuccessfully && formatStart < 3 + length1) {
+ // search for "|"
+ formatLength = 0;
+ for (; formatStart + formatLength < 3 + length1; formatLength++) {
+ if (argOut1.getByteArray()[formatStart + formatLength] == '|') {
+ break;
+ }
+ }
+ try {
+ chronon = DT_UTILS.parseDateTime(argOut0.getByteArray(), 3, length0,
+ argOut1.getByteArray(), formatStart, formatLength,
+ DateTimeParseMode.TIME_ONLY);
+ } catch (AsterixTemporalTypeParseException ex) {
+ formatStart += formatLength + 1;
+ continue;
+ }
+ processSuccessfully = true;
+ }
+
+ if (!processSuccessfully) {
+ throw new HyracksDataException(
+ "parse-date: Failed to match with any given format string!");
+ }
aTime.setValue((int) chronon);
timeSerde.serialize(aTime, out);