You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@asterixdb.apache.org by im...@apache.org on 2023/03/24 16:37:29 UTC

[asterixdb] 02/03: [ASTERIXDB-3118][FUN] Add unix-time-from-date-in-ms

This is an automated email from the ASF dual-hosted git repository.

imaxon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/asterixdb.git

commit 6d4622b90edbf1d080da145207c5d5028b5d1ce4
Author: Ian Maxon <ia...@maxons.email>
AuthorDate: Mon Mar 20 13:15:09 2023 -0700

    [ASTERIXDB-3118][FUN] Add unix-time-from-date-in-ms
    
    - user model changes: no
    - storage format changes: no
    - interface changes: no
    
    Change-Id: I42e9ad0b13d6c185d633561387150e975ef1b50f
    Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/17439
    Integration-Tests: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Tested-by: Jenkins <je...@fulliautomatix.ics.uci.edu>
    Reviewed-by: Ian Maxon <im...@uci.edu>
    Reviewed-by: Glenn Galvizo <gg...@uci.edu>
---
 .../date_functions/date_functions.3.query.sqlpp    |   1 +
 .../temporal/date_functions/date_functions.1.adm   |   2 +-
 .../temporal/date_functions/date_functions.3.ast   |   9 ++
 .../asterix/om/functions/BuiltinFunctions.java     |   4 +
 ...DatetimeEval.java => AbstractUnixTimeEval.java} |  33 +++++--
 .../temporal/AbstractUnixTimeFromDateEval.java     |  38 ++++++++
 .../temporal/AbstractUnixTimeFromDatetimeEval.java | 108 +--------------------
 .../temporal/UnixTimeFromDateInMsDescriptor.java   |  54 +++++++++++
 .../temporal/UnixTimeFromDateInMsEval.java         |  38 ++++++++
 .../temporal/UnixTimeFromTimeInMsDescriptor.java   |   1 +
 .../runtime/functions/FunctionCollection.java      |   2 +
 11 files changed, 175 insertions(+), 115 deletions(-)

diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/date_functions/date_functions.3.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/date_functions/date_functions.3.query.sqlpp
index cd03a90831..fad55d55c4 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/date_functions/date_functions.3.query.sqlpp
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/temporal/date_functions/date_functions.3.query.sqlpp
@@ -28,6 +28,7 @@ set `import-private-functions` `true`;
 , 'date4' : (test.`date-from-unix-time-in-days`(15600) + test.duration('-P2Y1M90DT30H'))
 , 'date5' : (test.`get-date-from-datetime`(test.datetime('1327-12-02T23:35:49.938Z')) + test.duration('P300Y900MT360000M'))
 , 'unix1' : test.`unix-time-from-date-in-days`(test.`date-from-unix-time-in-days`(15600))
+, 'unix2' : test.`unix-time-from-date-in-ms`(test.`date-from-unix-time-in-days`(15600))
 , 'duration1' : ((test.`get-date-from-datetime`(test.datetime('1327-12-02T23:35:49.938Z')) + test.duration('P300Y900MT360000M')) - test.`get-date-from-datetime`(test.datetime('1327-12-02T23:35:49.938Z')))
 , 'duration2' : ((test.`date-from-unix-time-in-days`(15600) + test.duration('-P2Y1M90DT30H')) - test.`date-from-unix-time-in-days`(15600))
 , 'c1' : (test.`date-from-unix-time-in-days`(15600) = ((test.`date-from-unix-time-in-days`(15600) + test.duration('-P2Y1M90DT30H')) + (test.`date-from-unix-time-in-days`(15600) - (test.`date-from-unix-time-in-days`(15600) + test.duration('-P2Y1M90DT30H')))))
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/date_functions/date_functions.1.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/date_functions/date_functions.1.adm
index e568b7bf42..76f34b8ac0 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/date_functions/date_functions.1.adm
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/temporal/date_functions/date_functions.1.adm
@@ -1 +1 @@
-{ "date1": date("2012-09-17"), "date2": date("1327-12-02"), "date3": date("2012-10-11"), "date4": date("2010-05-17"), "date5": date("1703-08-09"), "unix1": 15600, "duration1": duration("P137216D"), "duration2": duration("-P854D"), "c1": true, "c2": true, "null1": null, "nullunix1": null, "null2": null, "null3": null, "null4": null, "null5": null, "null6": null }
+{ "date1": date("2012-09-17"), "date2": date("1327-12-02"), "date3": date("2012-10-11"), "date4": date("2010-05-17"), "date5": date("1703-08-09"), "unix1": 15600, "unix2": 1347840000000, "duration1": duration("P137216D"), "duration2": duration("-P854D"), "c1": true, "c2": true, "null1": null, "nullunix1": null, "null2": null, "null3": null, "null4": null, "null5": null, "null6": null }
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/temporal/date_functions/date_functions.3.ast b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/temporal/date_functions/date_functions.3.ast
index 674377eb17..9957214990 100644
--- a/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/temporal/date_functions/date_functions.3.ast
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results_parser_sqlpp/temporal/date_functions/date_functions.3.ast
@@ -64,6 +64,15 @@ RecordConstructor [
       ]
     ]
   )
+  (
+    LiteralExpr [STRING] [unix2]
+    :
+    FunctionCall asterix.unix-time-from-date-in-ms@1[
+      FunctionCall asterix.date-from-unix-time-in-days@1[
+        LiteralExpr [LONG] [15600]
+      ]
+    ]
+  )
   (
     LiteralExpr [STRING] [duration1]
     :
diff --git a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
index cdc811176f..0034e9b338 100644
--- a/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
+++ b/asterixdb/asterix-om/src/main/java/org/apache/asterix/om/functions/BuiltinFunctions.java
@@ -1515,6 +1515,9 @@ public class BuiltinFunctions {
     // Temporal functions
     public static final FunctionIdentifier UNIX_TIME_FROM_DATE_IN_DAYS =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "unix-time-from-date-in-days", 1);
+
+    public static final FunctionIdentifier UNIX_TIME_FROM_DATE_IN_MS =
+            new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "unix-time-from-date-in-ms", 1);
     public final static FunctionIdentifier UNIX_TIME_FROM_TIME_IN_MS =
             new FunctionIdentifier(FunctionConstants.ASTERIX_NS, "unix-time-from-time-in-ms", 1);
     public final static FunctionIdentifier UNIX_TIME_FROM_DATETIME_IN_MS =
@@ -2468,6 +2471,7 @@ public class BuiltinFunctions {
 
         // temporal functions
         addFunction(UNIX_TIME_FROM_DATE_IN_DAYS, AInt64TypeComputer.INSTANCE, true);
+        addFunction(UNIX_TIME_FROM_DATE_IN_MS, AInt64TypeComputer.INSTANCE, true);
         addFunction(UNIX_TIME_FROM_TIME_IN_MS, AInt64TypeComputer.INSTANCE, true);
         addFunction(UNIX_TIME_FROM_DATETIME_IN_MS, AInt64TypeComputer.INSTANCE, true);
         addFunction(UNIX_TIME_FROM_DATETIME_IN_MS_WITH_TZ, AInt64TypeComputer.INSTANCE, false);
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeFromDatetimeEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeEval.java
similarity index 82%
copy from asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeFromDatetimeEval.java
copy to asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeEval.java
index 2723a64395..402cca0c42 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeFromDatetimeEval.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeEval.java
@@ -19,15 +19,16 @@
 
 package org.apache.asterix.runtime.evaluators.functions.temporal;
 
-import static org.apache.asterix.om.types.ATypeTag.SERIALIZED_DATETIME_TYPE_TAG;
-
 import java.io.DataOutput;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
 import java.time.zone.ZoneRules;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
 
+import org.apache.asterix.dataflow.data.nontagged.serde.ADateSerializerDeserializer;
 import org.apache.asterix.dataflow.data.nontagged.serde.ADateTimeSerializerDeserializer;
+import org.apache.asterix.dataflow.data.nontagged.serde.ATimeSerializerDeserializer;
 import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
 import org.apache.asterix.om.base.AInt64;
 import org.apache.asterix.om.base.AMutableInt64;
@@ -48,7 +49,7 @@ import org.apache.hyracks.data.std.primitive.VoidPointable;
 import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
 import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
 
-abstract class AbstractUnixTimeFromDatetimeEval extends AbstractScalarEval {
+abstract class AbstractUnixTimeEval extends AbstractScalarEval {
 
     private final IScalarEvaluator arg0;
     private final IScalarEvaluator arg1;
@@ -67,12 +68,11 @@ abstract class AbstractUnixTimeFromDatetimeEval extends AbstractScalarEval {
     private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
     private final DataOutput out = resultStorage.getDataOutput();
 
-    AbstractUnixTimeFromDatetimeEval(IScalarEvaluator arg0, SourceLocation sourceLoc,
-            FunctionIdentifier functionIdentifier) {
+    AbstractUnixTimeEval(IScalarEvaluator arg0, SourceLocation sourceLoc, FunctionIdentifier functionIdentifier) {
         this(arg0, null, sourceLoc, functionIdentifier);
     }
 
-    AbstractUnixTimeFromDatetimeEval(IScalarEvaluator arg0, IScalarEvaluator arg1, SourceLocation sourceLoc,
+    AbstractUnixTimeEval(IScalarEvaluator arg0, IScalarEvaluator arg1, SourceLocation sourceLoc,
             FunctionIdentifier fid) {
         super(sourceLoc, fid);
         this.arg0 = arg0;
@@ -83,6 +83,21 @@ abstract class AbstractUnixTimeFromDatetimeEval extends AbstractScalarEval {
         this.tzHelper = new TimezoneHelper(sourceLoc, fid);
     }
 
+    private long getChronon(byte[] bytes, int offset, ATypeTag tag) {
+        switch (tag) {
+            case TIME:
+                return ATimeSerializerDeserializer.getChronon(bytes, offset);
+            case DATE:
+                return ADateSerializerDeserializer.getChronon(bytes, offset);
+            case DATETIME:
+                return ADateTimeSerializerDeserializer.getChronon(bytes, offset);
+        }
+        return -1l;
+    }
+
+    protected ATypeTag tag = ATypeTag.NULL;
+    protected Predicate<Byte> incorrectTag = i -> i != tag.serialize();
+
     @Override
     public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
         arg0.evaluate(tuple, argPtr0);
@@ -96,11 +111,11 @@ abstract class AbstractUnixTimeFromDatetimeEval extends AbstractScalarEval {
 
         byte[] bytes0 = argPtr0.getByteArray();
         int offset0 = argPtr0.getStartOffset();
-        if (bytes0[offset0] != SERIALIZED_DATETIME_TYPE_TAG) {
-            throw new TypeMismatchException(srcLoc, funID, 0, bytes0[offset0], ATypeTag.SERIALIZED_DATETIME_TYPE_TAG);
+        if (incorrectTag.test(bytes0[offset0])) {
+            throw new TypeMismatchException(srcLoc, funID, 0, bytes0[offset0], tag.serialize());
         }
 
-        long chrononLocal = ADateTimeSerializerDeserializer.getChronon(bytes0, offset0 + 1);
+        long chrononLocal = getChronon(bytes0, offset0 + 1, tag);
         long chrononUTC;
         if (arg1 != null) {
             byte[] bytes1 = argPtr1.getByteArray();
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeFromDateEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeFromDateEval.java
new file mode 100644
index 0000000000..241a64f7a0
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeFromDateEval.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 at
+ *
+ *   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 org.apache.asterix.runtime.evaluators.functions.temporal;
+
+import org.apache.asterix.om.types.ATypeTag;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+
+public abstract class AbstractUnixTimeFromDateEval extends AbstractUnixTimeEval {
+
+    AbstractUnixTimeFromDateEval(IScalarEvaluator arg0, SourceLocation sourceLoc,
+            FunctionIdentifier functionIdentifier) {
+        this(arg0, null, sourceLoc, functionIdentifier);
+    }
+
+    AbstractUnixTimeFromDateEval(IScalarEvaluator arg0, IScalarEvaluator arg1, SourceLocation sourceLoc,
+            FunctionIdentifier fid) {
+        super(arg0, arg1, sourceLoc, fid);
+        this.tag = ATypeTag.DATE;
+    }
+}
\ No newline at end of file
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeFromDatetimeEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeFromDatetimeEval.java
index 2723a64395..a7e834f23b 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeFromDatetimeEval.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/AbstractUnixTimeFromDatetimeEval.java
@@ -19,53 +19,12 @@
 
 package org.apache.asterix.runtime.evaluators.functions.temporal;
 
-import static org.apache.asterix.om.types.ATypeTag.SERIALIZED_DATETIME_TYPE_TAG;
-
-import java.io.DataOutput;
-import java.time.LocalDateTime;
-import java.time.ZoneOffset;
-import java.time.zone.ZoneRules;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.asterix.dataflow.data.nontagged.serde.ADateTimeSerializerDeserializer;
-import org.apache.asterix.formats.nontagged.SerializerDeserializerProvider;
-import org.apache.asterix.om.base.AInt64;
-import org.apache.asterix.om.base.AMutableInt64;
-import org.apache.asterix.om.base.temporal.GregorianCalendarSystem;
 import org.apache.asterix.om.types.ATypeTag;
-import org.apache.asterix.om.types.BuiltinType;
-import org.apache.asterix.runtime.evaluators.functions.AbstractScalarEval;
-import org.apache.asterix.runtime.evaluators.functions.PointableHelper;
-import org.apache.asterix.runtime.exceptions.TypeMismatchException;
 import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
 import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
-import org.apache.hyracks.api.dataflow.value.ISerializerDeserializer;
-import org.apache.hyracks.api.exceptions.HyracksDataException;
 import org.apache.hyracks.api.exceptions.SourceLocation;
-import org.apache.hyracks.data.std.api.IPointable;
-import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
-import org.apache.hyracks.data.std.primitive.VoidPointable;
-import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
-import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
-
-abstract class AbstractUnixTimeFromDatetimeEval extends AbstractScalarEval {
-
-    private final IScalarEvaluator arg0;
-    private final IScalarEvaluator arg1;
 
-    private final IPointable argPtr0;
-    private final IPointable argPtr1;
-    private final UTF8StringPointable utf8Ptr;
-
-    protected final GregorianCalendarSystem cal = GregorianCalendarSystem.getInstance();
-    protected final TimezoneHelper tzHelper;
-
-    @SuppressWarnings("unchecked")
-    private final ISerializerDeserializer<AInt64> int64Serde =
-            SerializerDeserializerProvider.INSTANCE.getSerializerDeserializer(BuiltinType.AINT64);
-    private final AMutableInt64 aInt64 = new AMutableInt64(0);
-    private final ArrayBackedValueStorage resultStorage = new ArrayBackedValueStorage();
-    private final DataOutput out = resultStorage.getDataOutput();
+abstract class AbstractUnixTimeFromDatetimeEval extends AbstractUnixTimeEval {
 
     AbstractUnixTimeFromDatetimeEval(IScalarEvaluator arg0, SourceLocation sourceLoc,
             FunctionIdentifier functionIdentifier) {
@@ -74,69 +33,8 @@ abstract class AbstractUnixTimeFromDatetimeEval extends AbstractScalarEval {
 
     AbstractUnixTimeFromDatetimeEval(IScalarEvaluator arg0, IScalarEvaluator arg1, SourceLocation sourceLoc,
             FunctionIdentifier fid) {
-        super(sourceLoc, fid);
-        this.arg0 = arg0;
-        this.arg1 = arg1;
-        this.argPtr0 = new VoidPointable();
-        this.argPtr1 = arg1 != null ? new VoidPointable() : null;
-        this.utf8Ptr = arg1 != null ? new UTF8StringPointable() : null;
-        this.tzHelper = new TimezoneHelper(sourceLoc, fid);
-    }
-
-    @Override
-    public void evaluate(IFrameTupleReference tuple, IPointable result) throws HyracksDataException {
-        arg0.evaluate(tuple, argPtr0);
-        if (arg1 != null) {
-            arg1.evaluate(tuple, argPtr1);
-        }
-
-        if (PointableHelper.checkAndSetMissingOrNull(result, argPtr0, argPtr1)) {
-            return;
-        }
-
-        byte[] bytes0 = argPtr0.getByteArray();
-        int offset0 = argPtr0.getStartOffset();
-        if (bytes0[offset0] != SERIALIZED_DATETIME_TYPE_TAG) {
-            throw new TypeMismatchException(srcLoc, funID, 0, bytes0[offset0], ATypeTag.SERIALIZED_DATETIME_TYPE_TAG);
-        }
-
-        long chrononLocal = ADateTimeSerializerDeserializer.getChronon(bytes0, offset0 + 1);
-        long chrononUTC;
-        if (arg1 != null) {
-            byte[] bytes1 = argPtr1.getByteArray();
-            int offset1 = argPtr1.getStartOffset();
-            int len1 = argPtr1.getLength();
-            if (bytes1[offset1] != ATypeTag.SERIALIZED_STRING_TYPE_TAG) {
-                throw new TypeMismatchException(srcLoc, funID, 1, bytes1[offset1], ATypeTag.SERIALIZED_STRING_TYPE_TAG);
-            }
-            utf8Ptr.set(bytes1, offset1 + 1, len1 - 1);
-            ZoneRules tzRules = tzHelper.parseTimeZone(utf8Ptr);
-            LocalDateTime dt = toLocalDateTime(chrononLocal, cal);
-            ZoneOffset tzOffset = tzRules.getOffset(dt);
-            int tzOffsetMillis = (int) TimeUnit.SECONDS.toMillis(tzOffset.getTotalSeconds());
-            chrononUTC = cal.adjustChrononByTimezone(chrononLocal, tzOffsetMillis);
-        } else {
-            chrononUTC = chrononLocal;
-        }
-        long unixTime = chrononToUnixTime(chrononUTC);
-
-        resultStorage.reset();
-        aInt64.setValue(unixTime);
-        int64Serde.serialize(aInt64, out);
-        result.set(resultStorage);
-    }
-
-    private static LocalDateTime toLocalDateTime(long chronon, GregorianCalendarSystem cal) {
-        int year = cal.getYear(chronon);
-        int month = cal.getMonthOfYear(chronon, year);
-        int day = cal.getDayOfMonthYear(chronon, year, month);
-        int hour = cal.getHourOfDay(chronon);
-        int minute = cal.getMinOfHour(chronon);
-        int second = cal.getSecOfMin(chronon);
-        int milli = cal.getMillisOfSec(chronon);
-        int nano = (int) TimeUnit.MILLISECONDS.toNanos(milli);
-        return LocalDateTime.of(year, month, day, hour, minute, second, nano);
+        super(arg0, arg1, sourceLoc, fid);
+        this.tag = ATypeTag.DATETIME;
     }
 
-    abstract long chrononToUnixTime(long chronon);
 }
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/UnixTimeFromDateInMsDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/UnixTimeFromDateInMsDescriptor.java
new file mode 100644
index 0000000000..15be21a409
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/UnixTimeFromDateInMsDescriptor.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 at
+ *
+ *   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 org.apache.asterix.runtime.evaluators.functions.temporal;
+
+import org.apache.asterix.common.annotations.MissingNullInOutFunction;
+import org.apache.asterix.om.functions.BuiltinFunctions;
+import org.apache.asterix.om.functions.IFunctionDescriptorFactory;
+import org.apache.asterix.runtime.evaluators.base.AbstractScalarFunctionDynamicDescriptor;
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IEvaluatorContext;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluatorFactory;
+import org.apache.hyracks.api.exceptions.HyracksDataException;
+
+@MissingNullInOutFunction
+public final class UnixTimeFromDateInMsDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+
+    public static final IFunctionDescriptorFactory FACTORY = UnixTimeFromDateInMsDescriptor::new;
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    public IScalarEvaluatorFactory createEvaluatorFactory(final IScalarEvaluatorFactory[] args) {
+        return new IScalarEvaluatorFactory() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public IScalarEvaluator createScalarEvaluator(final IEvaluatorContext ctx) throws HyracksDataException {
+                IScalarEvaluator argEval = args[0].createScalarEvaluator(ctx);
+                return new UnixTimeFromDateInMsEval(argEval, sourceLoc, getIdentifier());
+            }
+        };
+    }
+
+    @Override
+    public FunctionIdentifier getIdentifier() {
+        return BuiltinFunctions.UNIX_TIME_FROM_DATE_IN_MS;
+    }
+}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/UnixTimeFromDateInMsEval.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/UnixTimeFromDateInMsEval.java
new file mode 100644
index 0000000000..66c1cf0eb2
--- /dev/null
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/UnixTimeFromDateInMsEval.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 at
+ *
+ *   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 org.apache.asterix.runtime.evaluators.functions.temporal;
+
+import org.apache.hyracks.algebricks.core.algebra.functions.FunctionIdentifier;
+import org.apache.hyracks.algebricks.runtime.base.IScalarEvaluator;
+import org.apache.hyracks.api.exceptions.SourceLocation;
+
+final class UnixTimeFromDateInMsEval extends AbstractUnixTimeFromDateEval {
+
+    public static final long MS_IN_DAY = 86400000l;
+
+    UnixTimeFromDateInMsEval(IScalarEvaluator arg0, SourceLocation sourceLoc, FunctionIdentifier functionIdentifier) {
+        super(arg0, sourceLoc, functionIdentifier);
+    }
+
+    @Override
+    long chrononToUnixTime(long chronon) {
+        return chronon * MS_IN_DAY;
+    }
+}
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/UnixTimeFromTimeInMsDescriptor.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/UnixTimeFromTimeInMsDescriptor.java
index 184d0ad927..9a05897c41 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/UnixTimeFromTimeInMsDescriptor.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/evaluators/functions/temporal/UnixTimeFromTimeInMsDescriptor.java
@@ -45,6 +45,7 @@ import org.apache.hyracks.dataflow.common.data.accessors.IFrameTupleReference;
 
 @MissingNullInOutFunction
 public class UnixTimeFromTimeInMsDescriptor extends AbstractScalarFunctionDynamicDescriptor {
+    //TODO: make this extend AbstractUnixTimeEval to avoid duplication
     private static final long serialVersionUID = 1L;
     public static final IFunctionDescriptorFactory FACTORY = UnixTimeFromTimeInMsDescriptor::new;
 
diff --git a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
index 63dae91f55..949afed799 100644
--- a/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
+++ b/asterixdb/asterix-runtime/src/main/java/org/apache/asterix/runtime/functions/FunctionCollection.java
@@ -608,6 +608,7 @@ import org.apache.asterix.runtime.evaluators.functions.temporal.QuarterOfYearDes
 import org.apache.asterix.runtime.evaluators.functions.temporal.TimeFromDatetimeDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.temporal.TimeFromUnixTimeInMsDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.temporal.UnixTimeFromDateInDaysDescriptor;
+import org.apache.asterix.runtime.evaluators.functions.temporal.UnixTimeFromDateInMsDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.temporal.UnixTimeFromDatetimeInMsDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.temporal.UnixTimeFromDatetimeInMsWithTzDescriptor;
 import org.apache.asterix.runtime.evaluators.functions.temporal.UnixTimeFromDatetimeInSecsDescriptor;
@@ -1221,6 +1222,7 @@ public final class FunctionCollection implements IFunctionCollection {
 
         // Temporal functions
         fc.add(UnixTimeFromDateInDaysDescriptor.FACTORY);
+        fc.add(UnixTimeFromDateInMsDescriptor.FACTORY);
         fc.add(UnixTimeFromTimeInMsDescriptor.FACTORY);
         fc.add(UnixTimeFromDatetimeInMsDescriptor.FACTORY);
         fc.add(UnixTimeFromDatetimeInMsWithTzDescriptor.FACTORY);