Added calendar-duration functions and timezone related function; fixed a small bug on printing timezone string.
git-svn-id: https://asterixdb.googlecode.com/svn/branches/asterix_stabilization_temporal_functionality@780 eaa15691-b419-025a-1212-ee371bd00084
diff --git a/asterix-app/src/test/resources/runtimets/queries/temp/adjust_timezone.aql b/asterix-app/src/test/resources/runtimets/queries/temp/adjust_timezone.aql
new file mode 100644
index 0000000..d7f6cca
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/temp/adjust_timezone.aql
@@ -0,0 +1,17 @@
+/*
+ * Description : Check the adjust-timezone functions
+ * Expected Result : Success
+ * Date : 15th Oct, 2012
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+write output to nc1:"rttest/temp_adjust_timezone.adm";
+
+let $t1 := time("20:15:10.327")
+let $dt1 := datetime("2010-10-23T01:12:13.329Z")
+let $s1 := adjust_time_for_timezone($t1, "+0800")
+let $s2 := adjust_datetime_for_timezone($dt1, "-0615")
+return { "string1" : $s1, "string2" : $s2 }
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/queries/temp/calendar_duration.aql b/asterix-app/src/test/resources/runtimets/queries/temp/calendar_duration.aql
new file mode 100644
index 0000000..8c9dee4
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/queries/temp/calendar_duration.aql
@@ -0,0 +1,28 @@
+/*
+ * Description : Check the calendar-duration functions
+ * Expected Result : Success
+ * Date : 15th Oct, 2012
+ */
+
+drop dataverse test if exists;
+create dataverse test;
+use dataverse test;
+
+write output to nc1:"rttest/temp_calendar_duration.adm";
+
+let $t1 := datetime("1987-11-19T23:49:23.938")
+let $t2 := date("-1328-10-23")
+let $dr1 := duration("P7382DT39283M3921.329S")
+let $dr2 := duration("-PT63H398212M3219.328S")
+let $dr3 := duration("P1Y90M")
+let $dr4 := duration("-P3Y89M4089DT47382.983S")
+let $cdr1 := calendar_duration_from_datetime($t1, $dr1)
+let $cdr2 := calendar_duration_from_datetime($t1, $dr2)
+let $cdr3 := calendar_duration_from_datetime($t1, $dr3)
+let $cdr4 := calendar_duration_from_datetime($t1, $dr4)
+let $cdr5 := calendar_duration_from_date($t2, $dr1)
+let $cdr6 := calendar_duration_from_date($t2, $dr2)
+let $cdr7 := calendar_duration_from_date($t2, $dr3)
+let $cdr8 := calendar_duration_from_date($t2, $dr4)
+
+return { "cduration1":$cdr1, "cduration2":$cdr2, "cduration3":$cdr3, "cduration4":$cdr4, "cduration5":$cdr5, "cduration6":$cdr6, "cduration7":$cdr7, "cduration8":$cdr8 }
diff --git a/asterix-app/src/test/resources/runtimets/results/temp/adjust_timezone.adm b/asterix-app/src/test/resources/runtimets/results/temp/adjust_timezone.adm
new file mode 100644
index 0000000..1f80fd9
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/results/temp/adjust_timezone.adm
@@ -0,0 +1 @@
+{ "string1": "04:15:10.327+08:00", "string2": "2010-10-22T18:57:13.329-06:15" }
\ No newline at end of file
diff --git a/asterix-app/src/test/resources/runtimets/results/temp/calendar_duration.adm b/asterix-app/src/test/resources/runtimets/results/temp/calendar_duration.adm
new file mode 100644
index 0000000..eb7d565
--- /dev/null
+++ b/asterix-app/src/test/resources/runtimets/results/temp/calendar_duration.adm
@@ -0,0 +1 @@
+{ "cduration1": duration("P20Y3M13DT7H48M21.329S"), "cduration2": duration("-P9M6DT4H45M39.328S"), "cduration3": duration("P8Y6M"), "cduration4": duration("-P21Y7M10DT13H9M42.983S"), "cduration5": duration("P20Y3M12DT7H48M21.329S"), "cduration6": duration("-P9M5DT4H45M39.328S"), "cduration7": duration("P8Y6M"), "cduration8": duration("-P21Y7M10DT13H9M42.983S") }
\ No newline at end of file
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/ADateAndTimeParser.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/ADateAndTimeParser.java
index 636b831..d8c4213 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/ADateAndTimeParser.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/ADateAndTimeParser.java
@@ -213,53 +213,111 @@
}
if (length > offset) {
- if (charAccessor.getCharAt(offset) != 'Z') {
- if ((charAccessor.getCharAt(offset) != '+' && charAccessor.getCharAt(offset) != '-')
- || (isExtendedForm && charAccessor.getCharAt(offset + 3) != ':')) {
- throw new Exception("Wrong timezone format: missing sign or missing colon in an extended form");
- }
-
- short timezoneHour = 0;
- short timezoneMinute = 0;
-
- for (int i = 0; i < 2; i++) {
- if ((charAccessor.getCharAt(offset + 1 + i) >= '0' && charAccessor.getCharAt(offset + 1 + i) <= '9')) {
- timezoneHour = (short) (timezoneHour * 10 + charAccessor.getCharAt(offset + 1 + i) - '0');
- } else {
- throw new Exception("Non-numeric value in timezone hour field");
- }
- }
-
- if (timezoneHour < GregorianCalendarSystem.TIMEZONE_HOUR_MIN
- || timezoneHour > GregorianCalendarSystem.TIMEZONE_HOUR_MAX) {
- throw new Exception(timeErrorMessage + ": time zone hour " + timezoneHour);
- }
-
- int temp_offset = (isExtendedForm) ? 1 : 0;
-
- for (int i = 0; i < 2; i++) {
- if ((charAccessor.getCharAt(offset + temp_offset + 3 + i) >= '0' && charAccessor.getCharAt(offset
- + temp_offset + 3 + i) <= '9')) {
- timezoneMinute = (short) (timezoneMinute * 10
- + charAccessor.getCharAt(offset + temp_offset + 3 + i) - '0');
- } else {
- throw new Exception("Non-numeric value in timezone minute field");
- }
- }
-
- if (timezoneMinute < GregorianCalendarSystem.TIMEZONE_MIN_MIN
- || timezoneMinute > GregorianCalendarSystem.TIMEZONE_MIN_MAX) {
- throw new Exception(timeErrorMessage + ": time zone minute " + timezoneMinute);
- }
-
- if (charAccessor.getCharAt(offset) == '-') {
- timezone = (byte) -((timezoneHour * 4) + timezoneMinute / 15);
- } else {
- timezone = (byte) ((timezoneHour * 4) + timezoneMinute / 15);
- }
- }
+ // if (charAccessor.getCharAt(offset) != 'Z') {
+ // if ((charAccessor.getCharAt(offset) != '+' && charAccessor.getCharAt(offset) != '-')
+ // || (isExtendedForm && charAccessor.getCharAt(offset + 3) != ':')) {
+ // throw new Exception("Wrong timezone format: missing sign or missing colon in an extended form");
+ // }
+ //
+ // short timezoneHour = 0;
+ // short timezoneMinute = 0;
+ //
+ // for (int i = 0; i < 2; i++) {
+ // if ((charAccessor.getCharAt(offset + 1 + i) >= '0' && charAccessor.getCharAt(offset + 1 + i) <= '9')) {
+ // timezoneHour = (short) (timezoneHour * 10 + charAccessor.getCharAt(offset + 1 + i) - '0');
+ // } else {
+ // throw new Exception("Non-numeric value in timezone hour field");
+ // }
+ // }
+ //
+ // if (timezoneHour < GregorianCalendarSystem.TIMEZONE_HOUR_MIN
+ // || timezoneHour > GregorianCalendarSystem.TIMEZONE_HOUR_MAX) {
+ // throw new Exception(timeErrorMessage + ": time zone hour " + timezoneHour);
+ // }
+ //
+ // int temp_offset = (isExtendedForm) ? 1 : 0;
+ //
+ // for (int i = 0; i < 2; i++) {
+ // if ((charAccessor.getCharAt(offset + temp_offset + 3 + i) >= '0' && charAccessor.getCharAt(offset
+ // + temp_offset + 3 + i) <= '9')) {
+ // timezoneMinute = (short) (timezoneMinute * 10
+ // + charAccessor.getCharAt(offset + temp_offset + 3 + i) - '0');
+ // } else {
+ // throw new Exception("Non-numeric value in timezone minute field");
+ // }
+ // }
+ //
+ // if (timezoneMinute < GregorianCalendarSystem.TIMEZONE_MIN_MIN
+ // || timezoneMinute > GregorianCalendarSystem.TIMEZONE_MIN_MAX) {
+ // throw new Exception(timeErrorMessage + ": time zone minute " + timezoneMinute);
+ // }
+ //
+ // if (charAccessor.getCharAt(offset) == '-') {
+ // timezone = (byte) -((timezoneHour * 4) + timezoneMinute / 15);
+ // } else {
+ // timezone = (byte) ((timezoneHour * 4) + timezoneMinute / 15);
+ // }
+ // }
+ timezone = parseTimezonePart(charAccessor, offset);
}
return gCalInstance.getChronon(hour, min, sec, millis, timezone);
}
+
+ /**
+ * Parse the given char sequence as a time string, and return the milliseconds represented by the time.
+ *
+ * @param charAccessor
+ * @return
+ * @throws Exception
+ */
+ public static <T> int parseTimezonePart(ICharSequenceAccessor<T> charAccessor, int offset) throws Exception {
+ int timezone = 0;
+
+ if (charAccessor.getCharAt(offset) != 'Z') {
+ if ((charAccessor.getCharAt(offset) != '+' && charAccessor.getCharAt(offset) != '-')) {
+ throw new Exception("Wrong timezone format: missing sign or missing colon for a time zone");
+ }
+
+ short timezoneHour = 0;
+ short timezoneMinute = 0;
+
+ for (int i = 0; i < 2; i++) {
+ if ((charAccessor.getCharAt(offset + 1 + i) >= '0' && charAccessor.getCharAt(offset + 1 + i) <= '9')) {
+ timezoneHour = (short) (timezoneHour * 10 + charAccessor.getCharAt(offset + 1 + i) - '0');
+ } else {
+ throw new Exception("Non-numeric value in timezone hour field");
+ }
+ }
+
+ if (timezoneHour < GregorianCalendarSystem.TIMEZONE_HOUR_MIN
+ || timezoneHour > GregorianCalendarSystem.TIMEZONE_HOUR_MAX) {
+ throw new Exception(timeErrorMessage + ": time zone hour " + timezoneHour);
+ }
+
+ int temp_offset = (charAccessor.getCharAt(offset + 3) == ':') ? 1 : 0;
+
+ for (int i = 0; i < 2; i++) {
+ if ((charAccessor.getCharAt(offset + temp_offset + 3 + i) >= '0' && charAccessor.getCharAt(offset
+ + temp_offset + 3 + i) <= '9')) {
+ timezoneMinute = (short) (timezoneMinute * 10
+ + charAccessor.getCharAt(offset + temp_offset + 3 + i) - '0');
+ } else {
+ throw new Exception("Non-numeric value in timezone minute field");
+ }
+ }
+
+ if (timezoneMinute < GregorianCalendarSystem.TIMEZONE_MIN_MIN
+ || timezoneMinute > GregorianCalendarSystem.TIMEZONE_MIN_MAX) {
+ throw new Exception(timeErrorMessage + ": time zone minute " + timezoneMinute);
+ }
+
+ if (charAccessor.getCharAt(offset) == '-') {
+ timezone = (byte) -((timezoneHour * 4) + timezoneMinute / 15);
+ } else {
+ timezone = (byte) ((timezoneHour * 4) + timezoneMinute / 15);
+ }
+ }
+ return timezone;
+ }
}
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/GregorianCalendarSystem.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/GregorianCalendarSystem.java
index 7b8d709..1c060c3 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/GregorianCalendarSystem.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/base/temporal/GregorianCalendarSystem.java
@@ -57,6 +57,7 @@
public static final int CHRONON_OF_MINUTE = 60 * CHRONON_OF_SECOND;
public static final int CHRONON_OF_HOUR = 60 * CHRONON_OF_MINUTE;
public static final long CHRONON_OF_DAY = 24 * CHRONON_OF_HOUR;
+ public static final int MONTHS_IN_A_YEAR = 12;
/**
* Minimum feasible value of each field
@@ -238,8 +239,13 @@
return chrononTime;
}
+ public long adjustChrononByTimezone(long chronon, int timezone) {
+ return chronon + timezone / 4 * CHRONON_OF_HOUR + (timezone % 4) * 15 * CHRONON_OF_MINUTE;
+ }
+
/**
- * Get the extended string representation of the given UTC chronon time under the given time zone. Only fields before
+ * Get the extended string representation of the given UTC chronon time under the given time zone. Only fields
+ * before
* the given field index will be returned.
* <p/>
* The extended string representation is like:<br/>
@@ -305,10 +311,13 @@
break;
}
- if (untilField.compareTo(Fields.DAY) > 0) {
+ if (timezone == 0) {
sbder.append("Z");
} else {
short tzMin = (short) ((timezone % 4) * 15);
+ if (tzMin < 0) {
+ tzMin = (short) (-1 * tzMin);
+ }
short tzHr = (short) (timezone / 4);
sbder.append((tzHr >= 0 ? "+" : "-")).append(String.format("%02d", (tzHr < 0 ? -tzHr : tzHr))).append(":")
.append(String.format("%02d", tzMin));
@@ -361,10 +370,13 @@
break;
}
- if (untilField.compareTo(Fields.DAY) > 0) {
+ if (timezone == 0) {
sbder.append("Z");
} else {
short tzMin = (short) ((timezone % 4) * 15);
+ if (tzMin < 0) {
+ tzMin = (short) (-1 * tzMin);
+ }
short tzHr = (short) (timezone / 4);
sbder.append((tzHr >= 0 ? "+" : "-")).append(String.format("%02d", (tzHr < 0 ? -tzHr : tzHr)))
.append(String.format("%02d", tzMin));
@@ -424,7 +436,7 @@
* @param year
* @return
*/
- protected boolean isLeapYear(int year) {
+ public boolean isLeapYear(int year) {
return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
}
@@ -456,7 +468,8 @@
* Get the year for the given chronon time.
* <p/>
* This code is directly from the Joda library BadicChronology.java.<br/>
- * The original authers are Stephen Colebourne, Brain S O'Neill and Guy Allard, and modified by JArod Wen on May 7th, 2012.
+ * The original authers are Stephen Colebourne, Brain S O'Neill and Guy Allard, and modified by JArod Wen on May
+ * 7th, 2012.
*
* @param chrononTime
* @return
@@ -503,7 +516,8 @@
* Get the month of the year for the given chronon time and the year.
* <p/>
* This code is directly from the Joda library BasicGJChronology.java.<br/>
- * The original authers are Stephen Colebourne, Brain S O'Neill and Guy Allard, and modified by JArod Wen on May 7th, 2012.
+ * The original authers are Stephen Colebourne, Brain S O'Neill and Guy Allard, and modified by JArod Wen on May
+ * 7th, 2012 and commented by Theodoros Ioannou on July 2012.
* <p/>
*
* @param millis
@@ -567,7 +581,8 @@
* Get the day of the given month and year for the input chronon time.
* <p/>
* This function is directly from Joda Library BasicChronology.java.<br/>
- * The original authers are Stephen Colebourne, Brain S O'Neill and Guy Allard, and modified by JArod Wen on May 7th, 2012.
+ * The original authers are Stephen Colebourne, Brain S O'Neill and Guy Allard, and modified by JArod Wen on May
+ * 7th, 2012.
* <p/>
*
* @param millis
diff --git a/asterix-om/src/main/java/edu/uci/ics/asterix/om/functions/AsterixBuiltinFunctions.java b/asterix-om/src/main/java/edu/uci/ics/asterix/om/functions/AsterixBuiltinFunctions.java
index c399354..3673e5b 100644
--- a/asterix-om/src/main/java/edu/uci/ics/asterix/om/functions/AsterixBuiltinFunctions.java
+++ b/asterix-om/src/main/java/edu/uci/ics/asterix/om/functions/AsterixBuiltinFunctions.java
@@ -427,6 +427,14 @@
"subtract_datetime", 2);
public final static FunctionIdentifier ADD_DATETIME_DURATION = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
"add_datetime_duration", 2);
+ public final static FunctionIdentifier CALENDAR_DURATION_FROM_DATETIME = new FunctionIdentifier(
+ FunctionConstants.ASTERIX_NS, "calendar_duration_from_datetime", 2);
+ public final static FunctionIdentifier CALENDAR_DURATION_FROM_DATE = new FunctionIdentifier(
+ FunctionConstants.ASTERIX_NS, "calendar_duration_from_date", 2);
+ public final static FunctionIdentifier ADJUST_TIME_FOR_TIMEZONE = new FunctionIdentifier(
+ FunctionConstants.ASTERIX_NS, "adjust_time_for_timezone", 2);
+ public final static FunctionIdentifier ADJUST_DATETIME_FOR_TIMEZONE = new FunctionIdentifier(
+ FunctionConstants.ASTERIX_NS, "adjust_datetime_for_timezone", 2);
public static final FunctionIdentifier EQ = AlgebricksBuiltinFunctions.EQ;
public static final FunctionIdentifier LE = AlgebricksBuiltinFunctions.LE;
@@ -702,6 +710,10 @@
add(DATETIME_FROM_UNIX_TIME_IN_MS, OptionalADateTimeTypeComputer.INSTANCE);
add(SUBTRACT_DATETIME, OptionalADurationTypeComputer.INSTANCE);
add(ADD_DATETIME_DURATION, OptionalADateTimeTypeComputer.INSTANCE);
+ add(CALENDAR_DURATION_FROM_DATETIME, OptionalADurationTypeComputer.INSTANCE);
+ add(CALENDAR_DURATION_FROM_DATE, OptionalADurationTypeComputer.INSTANCE);
+ add(ADJUST_DATETIME_FOR_TIMEZONE, OptionalAStringTypeComputer.INSTANCE);
+ add(ADJUST_TIME_FOR_TIMEZONE, OptionalAStringTypeComputer.INSTANCE);
String metadataFunctionLoaderClassName = "edu.uci.ics.asterix.metadata.functions.MetadataBuiltinFunctions";
try {
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/AdjustDateTimeForTimeZoneDescriptor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/AdjustDateTimeForTimeZoneDescriptor.java
new file mode 100644
index 0000000..72b3baa
--- /dev/null
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/AdjustDateTimeForTimeZoneDescriptor.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2009-2011 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.runtime.evaluators.functions.temporal;
+
+import java.io.DataOutput;
+
+import edu.uci.ics.asterix.common.functions.FunctionConstants;
+import edu.uci.ics.asterix.dataflow.data.nontagged.serde.ADateTimeSerializerDeserializer;
+import edu.uci.ics.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
+import edu.uci.ics.asterix.om.base.ANull;
+import edu.uci.ics.asterix.om.base.temporal.ADateAndTimeParser;
+import edu.uci.ics.asterix.om.base.temporal.ByteArrayCharSequenceAccessor;
+import edu.uci.ics.asterix.om.base.temporal.GregorianCalendarSystem;
+import edu.uci.ics.asterix.om.base.temporal.GregorianCalendarSystem.Fields;
+import edu.uci.ics.asterix.om.functions.IFunctionDescriptor;
+import edu.uci.ics.asterix.om.functions.IFunctionDescriptorFactory;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.BuiltinType;
+import edu.uci.ics.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluator;
+import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory;
+import edu.uci.ics.hyracks.api.dataflow.value.ISerializerDeserializer;
+import edu.uci.ics.hyracks.data.std.api.IDataOutputProvider;
+import edu.uci.ics.hyracks.data.std.util.ArrayBackedValueStorage;
+import edu.uci.ics.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+import edu.uci.ics.hyracks.dataflow.common.data.util.StringUtils;
+
+public class AdjustDateTimeForTimeZoneDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+
+ private final static long serialVersionUID = 1L;
+ public final static FunctionIdentifier FID = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
+ "adjust_datetime_for_timezone", 2);
+
+ // allowed input types
+ private final static byte SER_NULL_TYPE_TAG = ATypeTag.NULL.serialize();
+ private final static byte SER_DATETIME_TYPE_TAG = ATypeTag.DATETIME.serialize();
+ private final static byte SER_STRING_TYPE_TAG = ATypeTag.STRING.serialize();
+
+ public final static IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
+
+ @Override
+ public IFunctionDescriptor createFunctionDescriptor() {
+ return new AdjustDateTimeForTimeZoneDescriptor();
+ }
+ };
+
+ /* (non-Javadoc)
+ * @see edu.uci.ics.asterix.runtime.base.IScalarFunctionDynamicDescriptor#createEvaluatorFactory(edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory[])
+ */
+ @Override
+ public ICopyEvaluatorFactory createEvaluatorFactory(final ICopyEvaluatorFactory[] args) throws AlgebricksException {
+ return new ICopyEvaluatorFactory() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public ICopyEvaluator createEvaluator(final IDataOutputProvider output) throws AlgebricksException {
+ return new ICopyEvaluator() {
+
+ private DataOutput out = output.getDataOutput();
+ private ArrayBackedValueStorage argOut0 = new ArrayBackedValueStorage();
+ private ArrayBackedValueStorage argOut1 = new ArrayBackedValueStorage();
+ private ICopyEvaluator eval0 = args[0].createEvaluator(argOut0);
+ private ICopyEvaluator eval1 = args[1].createEvaluator(argOut1);
+
+ // possible output types
+ @SuppressWarnings("unchecked")
+ private ISerializerDeserializer<ANull> nullSerde = AqlSerializerDeserializerProvider.INSTANCE
+ .getSerializerDeserializer(BuiltinType.ANULL);
+
+ private ByteArrayCharSequenceAccessor charAccessor = new ByteArrayCharSequenceAccessor();
+
+ private GregorianCalendarSystem calInstance = GregorianCalendarSystem.getInstance();
+
+ @Override
+ public void evaluate(IFrameTupleReference tuple) throws AlgebricksException {
+ argOut0.reset();
+ eval0.evaluate(tuple);
+ argOut1.reset();
+ eval1.evaluate(tuple);
+
+ try {
+ if (argOut0.getByteArray()[0] == SER_NULL_TYPE_TAG
+ || argOut1.getByteArray()[0] == SER_NULL_TYPE_TAG) {
+ nullSerde.serialize(ANull.NULL, out);
+ return;
+ }
+
+ if (argOut0.getByteArray()[0] != SER_DATETIME_TYPE_TAG) {
+ throw new AlgebricksException(
+ "Inapplicable input type for parameter 0: expecting ATime, but got: "
+ + argOut0.getByteArray()[0]);
+ }
+
+ if (argOut1.getByteArray()[0] != SER_STRING_TYPE_TAG) {
+ throw new AlgebricksException(
+ "Inapplicable input type for parameter 0: expecting AString, but got: "
+ + argOut1.getByteArray()[0]);
+ }
+
+ charAccessor.reset(argOut1.getByteArray(), 3, 0);
+
+ int timezone = ADateAndTimeParser.parseTimezonePart(charAccessor, 0);
+
+ if (!calInstance.validateTimeZone(timezone)) {
+ throw new AlgebricksException("Wrong format for a time zone string!");
+ }
+
+ long chronon = ADateTimeSerializerDeserializer.getChronon(argOut0.getByteArray(), 1);
+
+ chronon = calInstance.adjustChrononByTimezone(chronon, timezone);
+
+ StringBuilder sbder = new StringBuilder();
+
+ calInstance.getExtendStringRepWithTimezoneUntilField(chronon, timezone, sbder, Fields.YEAR,
+ Fields.MILLISECOND);
+
+ out.writeByte(SER_STRING_TYPE_TAG);
+ out.writeUTF(sbder.toString());
+
+ } catch (Exception e1) {
+ throw new AlgebricksException(e1);
+ }
+ }
+ };
+ }
+ };
+ }
+
+ /* (non-Javadoc)
+ * @see edu.uci.ics.asterix.om.functions.IFunctionDescriptor#getIdentifier()
+ */
+ @Override
+ public FunctionIdentifier getIdentifier() {
+ return FID;
+ }
+
+}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/AdjustTimeForTimeZoneDescriptor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/AdjustTimeForTimeZoneDescriptor.java
new file mode 100644
index 0000000..29fbe65
--- /dev/null
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/AdjustTimeForTimeZoneDescriptor.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2009-2011 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.runtime.evaluators.functions.temporal;
+
+import java.io.DataOutput;
+
+import edu.uci.ics.asterix.common.functions.FunctionConstants;
+import edu.uci.ics.asterix.dataflow.data.nontagged.serde.ATimeSerializerDeserializer;
+import edu.uci.ics.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
+import edu.uci.ics.asterix.om.base.ANull;
+import edu.uci.ics.asterix.om.base.temporal.ADateAndTimeParser;
+import edu.uci.ics.asterix.om.base.temporal.ByteArrayCharSequenceAccessor;
+import edu.uci.ics.asterix.om.base.temporal.GregorianCalendarSystem;
+import edu.uci.ics.asterix.om.base.temporal.GregorianCalendarSystem.Fields;
+import edu.uci.ics.asterix.om.functions.IFunctionDescriptor;
+import edu.uci.ics.asterix.om.functions.IFunctionDescriptorFactory;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.BuiltinType;
+import edu.uci.ics.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluator;
+import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory;
+import edu.uci.ics.hyracks.api.dataflow.value.ISerializerDeserializer;
+import edu.uci.ics.hyracks.data.std.api.IDataOutputProvider;
+import edu.uci.ics.hyracks.data.std.util.ArrayBackedValueStorage;
+import edu.uci.ics.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+import edu.uci.ics.hyracks.dataflow.common.data.util.StringUtils;
+
+public class AdjustTimeForTimeZoneDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+
+ private final static long serialVersionUID = 1L;
+ public final static FunctionIdentifier FID = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
+ "adjust_time_for_timezone", 2);
+
+ // allowed input types
+ private final static byte SER_NULL_TYPE_TAG = ATypeTag.NULL.serialize();
+ private final static byte SER_TIME_TYPE_TAG = ATypeTag.TIME.serialize();
+ private final static byte SER_STRING_TYPE_TAG = ATypeTag.STRING.serialize();
+
+ public final static IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
+
+ @Override
+ public IFunctionDescriptor createFunctionDescriptor() {
+ return new AdjustTimeForTimeZoneDescriptor();
+ }
+ };
+
+ /* (non-Javadoc)
+ * @see edu.uci.ics.asterix.runtime.base.IScalarFunctionDynamicDescriptor#createEvaluatorFactory(edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory[])
+ */
+ @Override
+ public ICopyEvaluatorFactory createEvaluatorFactory(final ICopyEvaluatorFactory[] args) throws AlgebricksException {
+ return new ICopyEvaluatorFactory() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public ICopyEvaluator createEvaluator(final IDataOutputProvider output) throws AlgebricksException {
+ return new ICopyEvaluator() {
+
+ private DataOutput out = output.getDataOutput();
+ private ArrayBackedValueStorage argOut0 = new ArrayBackedValueStorage();
+ private ArrayBackedValueStorage argOut1 = new ArrayBackedValueStorage();
+ private ICopyEvaluator eval0 = args[0].createEvaluator(argOut0);
+ private ICopyEvaluator eval1 = args[1].createEvaluator(argOut1);
+
+ // possible output types
+ @SuppressWarnings("unchecked")
+ private ISerializerDeserializer<ANull> nullSerde = AqlSerializerDeserializerProvider.INSTANCE
+ .getSerializerDeserializer(BuiltinType.ANULL);
+
+ private ByteArrayCharSequenceAccessor charAccessor = new ByteArrayCharSequenceAccessor();
+
+ private GregorianCalendarSystem calInstance = GregorianCalendarSystem.getInstance();
+
+ @Override
+ public void evaluate(IFrameTupleReference tuple) throws AlgebricksException {
+ argOut0.reset();
+ eval0.evaluate(tuple);
+ argOut1.reset();
+ eval1.evaluate(tuple);
+
+ try {
+ if (argOut0.getByteArray()[0] == SER_NULL_TYPE_TAG
+ || argOut1.getByteArray()[0] == SER_NULL_TYPE_TAG) {
+ nullSerde.serialize(ANull.NULL, out);
+ return;
+ }
+
+ if (argOut0.getByteArray()[0] != SER_TIME_TYPE_TAG) {
+ throw new AlgebricksException(
+ "Inapplicable input type for parameter 0: expecting ATime, but got: "
+ + argOut0.getByteArray()[0]);
+ }
+
+ if (argOut1.getByteArray()[0] != SER_STRING_TYPE_TAG) {
+ throw new AlgebricksException(
+ "Inapplicable input type for parameter 0: expecting AString, but got: "
+ + argOut1.getByteArray()[0]);
+ }
+
+ charAccessor.reset(argOut1.getByteArray(), 3, 0);
+
+ int timezone = ADateAndTimeParser.parseTimezonePart(charAccessor, 0);
+
+ if (!calInstance.validateTimeZone(timezone)) {
+ throw new AlgebricksException("Wrong format for a time zone string!");
+ }
+
+ int chronon = ATimeSerializerDeserializer.getChronon(argOut0.getByteArray(), 1);
+
+ chronon = (int) calInstance.adjustChrononByTimezone(chronon, timezone);
+
+ StringBuilder sbder = new StringBuilder();
+
+ calInstance.getExtendStringRepWithTimezoneUntilField(chronon, timezone, sbder, Fields.HOUR,
+ Fields.MILLISECOND);
+
+ out.writeByte(SER_STRING_TYPE_TAG);
+ out.writeUTF(sbder.toString());
+
+ } catch (Exception e1) {
+ throw new AlgebricksException(e1);
+ }
+ }
+ };
+ }
+ };
+ }
+
+ /* (non-Javadoc)
+ * @see edu.uci.ics.asterix.om.functions.IFunctionDescriptor#getIdentifier()
+ */
+ @Override
+ public FunctionIdentifier getIdentifier() {
+ return FID;
+ }
+
+}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/CalendarDuartionFromDateDescriptor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/CalendarDuartionFromDateDescriptor.java
new file mode 100644
index 0000000..b72a11f
--- /dev/null
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/CalendarDuartionFromDateDescriptor.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2009-2011 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.runtime.evaluators.functions.temporal;
+
+import java.io.DataOutput;
+
+import edu.uci.ics.asterix.common.functions.FunctionConstants;
+import edu.uci.ics.asterix.dataflow.data.nontagged.serde.ADateSerializerDeserializer;
+import edu.uci.ics.asterix.dataflow.data.nontagged.serde.ADurationSerializerDeserializer;
+import edu.uci.ics.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
+import edu.uci.ics.asterix.om.base.ADuration;
+import edu.uci.ics.asterix.om.base.AMutableDuration;
+import edu.uci.ics.asterix.om.base.ANull;
+import edu.uci.ics.asterix.om.base.temporal.DurationArithmeticOperations;
+import edu.uci.ics.asterix.om.base.temporal.GregorianCalendarSystem;
+import edu.uci.ics.asterix.om.functions.IFunctionDescriptor;
+import edu.uci.ics.asterix.om.functions.IFunctionDescriptorFactory;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.BuiltinType;
+import edu.uci.ics.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluator;
+import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory;
+import edu.uci.ics.hyracks.api.dataflow.value.ISerializerDeserializer;
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+import edu.uci.ics.hyracks.data.std.api.IDataOutputProvider;
+import edu.uci.ics.hyracks.data.std.util.ArrayBackedValueStorage;
+import edu.uci.ics.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+public class CalendarDuartionFromDateDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+
+ private final static long serialVersionUID = 1L;
+ public final static FunctionIdentifier FID = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
+ "calendar_duration_from_date", 2);
+
+ // allowed input types
+ private final static byte SER_NULL_TYPE_TAG = ATypeTag.NULL.serialize();
+ private final static byte SER_DATE_TYPE_TAG = ATypeTag.DATE.serialize();
+ private final static byte SER_DURATION_TYPE_TAG = ATypeTag.DURATION.serialize();
+
+ public final static IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
+
+ @Override
+ public IFunctionDescriptor createFunctionDescriptor() {
+ return new CalendarDuartionFromDateDescriptor();
+ }
+ };
+
+ /* (non-Javadoc)
+ * @see edu.uci.ics.asterix.runtime.base.IScalarFunctionDynamicDescriptor#createEvaluatorFactory(edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory[])
+ */
+ @Override
+ public ICopyEvaluatorFactory createEvaluatorFactory(final ICopyEvaluatorFactory[] args) throws AlgebricksException {
+ return new ICopyEvaluatorFactory() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public ICopyEvaluator createEvaluator(final IDataOutputProvider output) throws AlgebricksException {
+
+ return new ICopyEvaluator() {
+
+ private DataOutput out = output.getDataOutput();
+ private ArrayBackedValueStorage argOut0 = new ArrayBackedValueStorage();
+ private ArrayBackedValueStorage argOut1 = new ArrayBackedValueStorage();
+ private ICopyEvaluator eval0 = args[0].createEvaluator(argOut0);
+ private ICopyEvaluator eval1 = args[1].createEvaluator(argOut1);
+
+ // possible output types
+ @SuppressWarnings("unchecked")
+ private ISerializerDeserializer<ANull> nullSerde = AqlSerializerDeserializerProvider.INSTANCE
+ .getSerializerDeserializer(BuiltinType.ANULL);
+ @SuppressWarnings("unchecked")
+ private ISerializerDeserializer<ADuration> durationSerde = AqlSerializerDeserializerProvider.INSTANCE
+ .getSerializerDeserializer(BuiltinType.ADURATION);
+
+ private AMutableDuration aDuration = new AMutableDuration(0, 0);
+
+ private GregorianCalendarSystem calInstanct = GregorianCalendarSystem.getInstance();
+
+ @Override
+ public void evaluate(IFrameTupleReference tuple) throws AlgebricksException {
+
+ argOut0.reset();
+ eval0.evaluate(tuple);
+ argOut1.reset();
+ eval1.evaluate(tuple);
+
+ try {
+ if (argOut0.getByteArray()[0] == SER_NULL_TYPE_TAG
+ || argOut1.getByteArray()[0] == SER_NULL_TYPE_TAG) {
+ nullSerde.serialize(ANull.NULL, out);
+ return;
+ }
+
+ if (argOut0.getByteArray()[0] != SER_DATE_TYPE_TAG) {
+ throw new AlgebricksException(
+ "Inapplicable input type for parameter 0: expecting ADateTime, but got: "
+ + argOut0.getByteArray()[0]);
+ }
+
+ if (argOut1.getByteArray()[0] != SER_DURATION_TYPE_TAG) {
+ throw new AlgebricksException(
+ "Inapplicable input type for parameter 1: expecting ADateTime, but got: "
+ + argOut1.getByteArray()[0]);
+ }
+
+ int yearMonthDurationInMonths = ADurationSerializerDeserializer.getYearMonth(
+ argOut1.getByteArray(), 1);
+ long dayTimeDurationInMs = ADurationSerializerDeserializer.getDayTime(
+ argOut1.getByteArray(), 1);
+
+ long startingTimePoint = ADateSerializerDeserializer.getChronon(argOut0.getByteArray(), 1)
+ * GregorianCalendarSystem.CHRONON_OF_DAY;
+
+ long endingTimePoint = DurationArithmeticOperations.addDuration(startingTimePoint,
+ yearMonthDurationInMonths, dayTimeDurationInMs);
+
+ if (startingTimePoint == endingTimePoint) {
+ aDuration.setValue(0, 0);
+ } else {
+
+ boolean negative = false;
+
+ if (endingTimePoint < startingTimePoint) {
+ negative = true;
+ // swap the starting and ending time, so that ending time is always larger than the starting time.
+ long tmpTime = endingTimePoint;
+ endingTimePoint = startingTimePoint;
+ startingTimePoint = tmpTime;
+ }
+
+ int year0 = calInstanct.getYear(startingTimePoint);
+ int month0 = calInstanct.getMonthOfYear(startingTimePoint, year0);
+
+ int year1 = calInstanct.getYear(endingTimePoint);
+ int month1 = calInstanct.getMonthOfYear(endingTimePoint, year1);
+
+ int year = year1 - year0;
+ int month = month1 - month0;
+ int day = calInstanct.getDayOfMonthYear(endingTimePoint, year1, month1)
+ - calInstanct.getDayOfMonthYear(startingTimePoint, year0, month0);
+ int hour = calInstanct.getHourOfDay(endingTimePoint)
+ - calInstanct.getHourOfDay(startingTimePoint);
+ int min = calInstanct.getMinOfHour(endingTimePoint)
+ - calInstanct.getMinOfHour(startingTimePoint);
+ int sec = calInstanct.getSecOfMin(endingTimePoint)
+ - calInstanct.getSecOfMin(startingTimePoint);
+ int ms = calInstanct.getMillisOfSec(endingTimePoint)
+ - calInstanct.getMillisOfSec(startingTimePoint);
+
+ if (ms < 0) {
+ ms += GregorianCalendarSystem.CHRONON_OF_SECOND;
+ sec -= 1;
+ }
+
+ if (sec < 0) {
+ sec += GregorianCalendarSystem.CHRONON_OF_MINUTE
+ / GregorianCalendarSystem.CHRONON_OF_SECOND;
+ min -= 1;
+ }
+
+ if (min < 0) {
+ min += GregorianCalendarSystem.CHRONON_OF_HOUR
+ / GregorianCalendarSystem.CHRONON_OF_MINUTE;
+ hour -= 1;
+ }
+
+ if (hour < 0) {
+ hour += GregorianCalendarSystem.CHRONON_OF_DAY
+ / GregorianCalendarSystem.CHRONON_OF_HOUR;
+ day -= 1;
+ }
+
+ if (day < 0) {
+ boolean isLeapYear = calInstanct.isLeapYear(year0);
+ day += (isLeapYear) ? (GregorianCalendarSystem.DAYS_OF_MONTH_LEAP[month0 - 1])
+ : (GregorianCalendarSystem.DAYS_OF_MONTH_ORDI[month0 - 1]);
+ month -= 1;
+ }
+
+ if (month < 0) {
+ month += GregorianCalendarSystem.MONTHS_IN_A_YEAR;
+ year -= 1;
+ }
+
+ if (negative) {
+ aDuration.setValue(-1 * (year * GregorianCalendarSystem.MONTHS_IN_A_YEAR + month),
+ -1
+ * (day * GregorianCalendarSystem.CHRONON_OF_DAY + hour
+ * GregorianCalendarSystem.CHRONON_OF_HOUR + min
+ * GregorianCalendarSystem.CHRONON_OF_MINUTE + sec
+ * GregorianCalendarSystem.CHRONON_OF_SECOND + ms));
+ } else {
+ aDuration.setValue(year * GregorianCalendarSystem.MONTHS_IN_A_YEAR + month, day
+ * GregorianCalendarSystem.CHRONON_OF_DAY + hour
+ * GregorianCalendarSystem.CHRONON_OF_HOUR + min
+ * GregorianCalendarSystem.CHRONON_OF_MINUTE + sec
+ * GregorianCalendarSystem.CHRONON_OF_SECOND + ms);
+ }
+ }
+
+ durationSerde.serialize(aDuration, out);
+
+ } catch (HyracksDataException hex) {
+ throw new AlgebricksException(hex);
+ }
+ }
+ };
+ }
+ };
+ }
+
+ /* (non-Javadoc)
+ * @see edu.uci.ics.asterix.om.functions.IFunctionDescriptor#getIdentifier()
+ */
+ @Override
+ public FunctionIdentifier getIdentifier() {
+ return FID;
+ }
+
+}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/CalendarDurationFromDateTimeDescriptor.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/CalendarDurationFromDateTimeDescriptor.java
new file mode 100644
index 0000000..c0b00a9
--- /dev/null
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/evaluators/functions/temporal/CalendarDurationFromDateTimeDescriptor.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2009-2011 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.runtime.evaluators.functions.temporal;
+
+import java.io.DataOutput;
+
+import edu.uci.ics.asterix.common.functions.FunctionConstants;
+import edu.uci.ics.asterix.dataflow.data.nontagged.serde.ADateTimeSerializerDeserializer;
+import edu.uci.ics.asterix.dataflow.data.nontagged.serde.ADurationSerializerDeserializer;
+import edu.uci.ics.asterix.formats.nontagged.AqlSerializerDeserializerProvider;
+import edu.uci.ics.asterix.om.base.ADuration;
+import edu.uci.ics.asterix.om.base.AMutableDuration;
+import edu.uci.ics.asterix.om.base.ANull;
+import edu.uci.ics.asterix.om.base.temporal.DurationArithmeticOperations;
+import edu.uci.ics.asterix.om.base.temporal.GregorianCalendarSystem;
+import edu.uci.ics.asterix.om.functions.IFunctionDescriptor;
+import edu.uci.ics.asterix.om.functions.IFunctionDescriptorFactory;
+import edu.uci.ics.asterix.om.types.ATypeTag;
+import edu.uci.ics.asterix.om.types.BuiltinType;
+import edu.uci.ics.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import edu.uci.ics.hyracks.algebricks.common.exceptions.AlgebricksException;
+import edu.uci.ics.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluator;
+import edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory;
+import edu.uci.ics.hyracks.api.dataflow.value.ISerializerDeserializer;
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+import edu.uci.ics.hyracks.data.std.api.IDataOutputProvider;
+import edu.uci.ics.hyracks.data.std.util.ArrayBackedValueStorage;
+import edu.uci.ics.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
+
+/**
+ * This function converts a given duration into a "human-readable" duration containing both year-month and day-time
+ * duration parts, by re-organizing values between the duration fields from the given reference time point.<p/>
+ *
+ * The basic algorithm for this convert is simple: <br/>
+ * 1. Calculate the time point by adding the given duration to the given time point;<br/>
+ * 2. Calculate the differences by fields between two different time points;<br/>
+ * 3. Re-format the duration into a human-readable one.<p/>
+ *
+ * In the implementation, we always do the subtraction from the later time point, resulting a positive duration always. Then
+ * the sign of the duration is decided by the input duration.<p/>
+ *
+ *
+ */
+public class CalendarDurationFromDateTimeDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+
+ private final static long serialVersionUID = 1L;
+ public final static FunctionIdentifier FID = new FunctionIdentifier(FunctionConstants.ASTERIX_NS,
+ "calendar_duration_from_datetime", 2);
+
+ // allowed input types
+ private final static byte SER_NULL_TYPE_TAG = ATypeTag.NULL.serialize();
+ private final static byte SER_DATETIME_TYPE_TAG = ATypeTag.DATETIME.serialize();
+ private final static byte SER_DURATION_TYPE_TAG = ATypeTag.DURATION.serialize();
+
+ public final static IFunctionDescriptorFactory FACTORY = new IFunctionDescriptorFactory() {
+
+ @Override
+ public IFunctionDescriptor createFunctionDescriptor() {
+ return new CalendarDurationFromDateTimeDescriptor();
+ }
+ };
+
+ /* (non-Javadoc)
+ * @see edu.uci.ics.asterix.runtime.base.IScalarFunctionDynamicDescriptor#createEvaluatorFactory(edu.uci.ics.hyracks.algebricks.runtime.base.ICopyEvaluatorFactory[])
+ */
+ @Override
+ public ICopyEvaluatorFactory createEvaluatorFactory(final ICopyEvaluatorFactory[] args) throws AlgebricksException {
+ return new ICopyEvaluatorFactory() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public ICopyEvaluator createEvaluator(final IDataOutputProvider output) throws AlgebricksException {
+ return new ICopyEvaluator() {
+
+ private DataOutput out = output.getDataOutput();
+ private ArrayBackedValueStorage argOut0 = new ArrayBackedValueStorage();
+ private ArrayBackedValueStorage argOut1 = new ArrayBackedValueStorage();
+ private ICopyEvaluator eval0 = args[0].createEvaluator(argOut0);
+ private ICopyEvaluator eval1 = args[1].createEvaluator(argOut1);
+
+ // possible output types
+ @SuppressWarnings("unchecked")
+ private ISerializerDeserializer<ANull> nullSerde = AqlSerializerDeserializerProvider.INSTANCE
+ .getSerializerDeserializer(BuiltinType.ANULL);
+ @SuppressWarnings("unchecked")
+ private ISerializerDeserializer<ADuration> durationSerde = AqlSerializerDeserializerProvider.INSTANCE
+ .getSerializerDeserializer(BuiltinType.ADURATION);
+
+ private AMutableDuration aDuration = new AMutableDuration(0, 0);
+
+ private GregorianCalendarSystem calInstanct = GregorianCalendarSystem.getInstance();
+
+ @Override
+ public void evaluate(IFrameTupleReference tuple) throws AlgebricksException {
+ argOut0.reset();
+ eval0.evaluate(tuple);
+ argOut1.reset();
+ eval1.evaluate(tuple);
+
+ try {
+ if (argOut0.getByteArray()[0] == SER_NULL_TYPE_TAG
+ || argOut1.getByteArray()[0] == SER_NULL_TYPE_TAG) {
+ nullSerde.serialize(ANull.NULL, out);
+ return;
+ }
+
+ if (argOut0.getByteArray()[0] != SER_DATETIME_TYPE_TAG) {
+ throw new AlgebricksException(
+ "Inapplicable input type for parameter 0: expecting ADateTime, but got: "
+ + argOut0.getByteArray()[0]);
+ }
+
+ if (argOut1.getByteArray()[0] != SER_DURATION_TYPE_TAG) {
+ throw new AlgebricksException(
+ "Inapplicable input type for parameter 1: expecting ADateTime, but got: "
+ + argOut1.getByteArray()[0]);
+ }
+
+ int yearMonthDurationInMonths = ADurationSerializerDeserializer.getYearMonth(
+ argOut1.getByteArray(), 1);
+ long dayTimeDurationInMs = ADurationSerializerDeserializer.getDayTime(
+ argOut1.getByteArray(), 1);
+
+ long startingTimePoint = ADateTimeSerializerDeserializer.getChronon(argOut0.getByteArray(),
+ 1);
+
+ long endingTimePoint = DurationArithmeticOperations.addDuration(startingTimePoint,
+ yearMonthDurationInMonths, dayTimeDurationInMs);
+
+ if (startingTimePoint == endingTimePoint) {
+ aDuration.setValue(0, 0);
+ } else {
+
+ boolean negative = false;
+
+ if (endingTimePoint < startingTimePoint) {
+ negative = true;
+ // swap the starting and ending time, so that ending time is always larger than the starting time.
+ long tmpTime = endingTimePoint;
+ endingTimePoint = startingTimePoint;
+ startingTimePoint = tmpTime;
+ }
+
+ int year0 = calInstanct.getYear(startingTimePoint);
+ int month0 = calInstanct.getMonthOfYear(startingTimePoint, year0);
+
+ int year1 = calInstanct.getYear(endingTimePoint);
+ int month1 = calInstanct.getMonthOfYear(endingTimePoint, year1);
+
+ int year = year1 - year0;
+ int month = month1 - month0;
+ int day = calInstanct.getDayOfMonthYear(endingTimePoint, year1, month1)
+ - calInstanct.getDayOfMonthYear(startingTimePoint, year0, month0);
+ int hour = calInstanct.getHourOfDay(endingTimePoint)
+ - calInstanct.getHourOfDay(startingTimePoint);
+ int min = calInstanct.getMinOfHour(endingTimePoint)
+ - calInstanct.getMinOfHour(startingTimePoint);
+ int sec = calInstanct.getSecOfMin(endingTimePoint)
+ - calInstanct.getSecOfMin(startingTimePoint);
+ int ms = calInstanct.getMillisOfSec(endingTimePoint)
+ - calInstanct.getMillisOfSec(startingTimePoint);
+
+ if (ms < 0) {
+ ms += GregorianCalendarSystem.CHRONON_OF_SECOND;
+ sec -= 1;
+ }
+
+ if (sec < 0) {
+ sec += GregorianCalendarSystem.CHRONON_OF_MINUTE
+ / GregorianCalendarSystem.CHRONON_OF_SECOND;
+ min -= 1;
+ }
+
+ if (min < 0) {
+ min += GregorianCalendarSystem.CHRONON_OF_HOUR
+ / GregorianCalendarSystem.CHRONON_OF_MINUTE;
+ hour -= 1;
+ }
+
+ if (hour < 0) {
+ hour += GregorianCalendarSystem.CHRONON_OF_DAY
+ / GregorianCalendarSystem.CHRONON_OF_HOUR;
+ day -= 1;
+ }
+
+ if (day < 0) {
+ boolean isLeapYear = calInstanct.isLeapYear(year0);
+ day += (isLeapYear) ? (GregorianCalendarSystem.DAYS_OF_MONTH_LEAP[month0 - 1])
+ : (GregorianCalendarSystem.DAYS_OF_MONTH_ORDI[month0 - 1]);
+ month -= 1;
+ }
+
+ if (month < 0) {
+ month += GregorianCalendarSystem.MONTHS_IN_A_YEAR;
+ year -= 1;
+ }
+
+ if (negative) {
+ aDuration.setValue(-1 * (year * GregorianCalendarSystem.MONTHS_IN_A_YEAR + month),
+ -1
+ * (day * GregorianCalendarSystem.CHRONON_OF_DAY + hour
+ * GregorianCalendarSystem.CHRONON_OF_HOUR + min
+ * GregorianCalendarSystem.CHRONON_OF_MINUTE + sec
+ * GregorianCalendarSystem.CHRONON_OF_SECOND + ms));
+ } else {
+ aDuration.setValue(year * GregorianCalendarSystem.MONTHS_IN_A_YEAR + month, day
+ * GregorianCalendarSystem.CHRONON_OF_DAY + hour
+ * GregorianCalendarSystem.CHRONON_OF_HOUR + min
+ * GregorianCalendarSystem.CHRONON_OF_MINUTE + sec
+ * GregorianCalendarSystem.CHRONON_OF_SECOND + ms);
+ }
+ }
+
+ durationSerde.serialize(aDuration, out);
+
+ } catch (HyracksDataException hex) {
+ throw new AlgebricksException(hex);
+ }
+ }
+ };
+ }
+ };
+ }
+
+ /* (non-Javadoc)
+ * @see edu.uci.ics.asterix.om.functions.IFunctionDescriptor#getIdentifier()
+ */
+ @Override
+ public FunctionIdentifier getIdentifier() {
+ return FID;
+ }
+
+}
diff --git a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java
index 85abde8..03ed3ae 100644
--- a/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java
+++ b/asterix-runtime/src/main/java/edu/uci/ics/asterix/runtime/formats/NonTaggedDataFormat.java
@@ -165,6 +165,10 @@
import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.AddDateDurationDescriptor;
import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.AddDatetimeDurationDescriptor;
import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.AddTimeDurationDescriptor;
+import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.AdjustDateTimeForTimeZoneDescriptor;
+import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.AdjustTimeForTimeZoneDescriptor;
+import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.CalendarDuartionFromDateDescriptor;
+import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.CalendarDurationFromDateTimeDescriptor;
import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.DateFromDatetimeDescriptor;
import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.DateFromUnixTimeInDaysDescriptor;
import edu.uci.ics.asterix.runtime.evaluators.functions.temporal.DatetimeFromDateAndTimeDescriptor;
@@ -412,6 +416,10 @@
temp.add(DatetimeFromDateAndTimeDescriptor.FACTORY);
temp.add(SubtractDatetimeDescriptor.FACTORY);
temp.add(AddDatetimeDurationDescriptor.FACTORY);
+ temp.add(CalendarDurationFromDateTimeDescriptor.FACTORY);
+ temp.add(CalendarDuartionFromDateDescriptor.FACTORY);
+ temp.add(AdjustDateTimeForTimeZoneDescriptor.FACTORY);
+ temp.add(AdjustTimeForTimeZoneDescriptor.FACTORY);
IFunctionManager mgr = new FunctionManagerImpl();
for (IFunctionDescriptorFactory fdFactory : temp) {