HAWQ-1771. Add newQE DOUBLE_TO_TIMESTAMP function
diff --git a/depends/dbcommon/src/dbcommon/function/func-kind.h b/depends/dbcommon/src/dbcommon/function/func-kind.h
index 4c1f487..4fbf961 100644
--- a/depends/dbcommon/src/dbcommon/function/func-kind.h
+++ b/depends/dbcommon/src/dbcommon/function/func-kind.h
@@ -194,6 +194,7 @@
   DECIMAL_TO_TEXT,
   TEXT_TO_CHAR,
   INT_TO_CHAR,
+  DOUBLE_TO_TIMESTAMP,
 
   // date/time related functions
   DATE_TO_TIMESTAMP,
diff --git a/depends/dbcommon/src/dbcommon/function/func.cc b/depends/dbcommon/src/dbcommon/function/func.cc
index 7a18187..f9222b3 100644
--- a/depends/dbcommon/src/dbcommon/function/func.cc
+++ b/depends/dbcommon/src/dbcommon/function/func.cc
@@ -327,6 +327,7 @@
   FuncEntryArray.push_back({DECIMAL_TO_TEXT, "decimal_to_text", STRINGID, {DECIMALNEWID}, decimal_to_text});
   FuncEntryArray.push_back({TEXT_TO_CHAR, "text_to_char", TINYINTID, {STRINGID}, text_to_char});
   FuncEntryArray.push_back({INT_TO_CHAR, "int4_to_char", TINYINTID, {INTID}, int4_to_char});
+  FuncEntryArray.push_back({DOUBLE_TO_TIMESTAMP, "double_to_timestamp", TIMESTAMPTZID, {DOUBLEID}, double_to_timestamp});
 
   FuncEntryArray.push_back({CHAR_TO_STRING, "char_to_string", STRINGID, {CHARID},char_to_string, false});
   FuncEntryArray.push_back({DATE_TO_TIMESTAMP, "date_to_timestamp", TIMESTAMPID, {DATEID}, date_to_timestamp, false});
diff --git a/depends/dbcommon/src/dbcommon/function/typecast-func.cc b/depends/dbcommon/src/dbcommon/function/typecast-func.cc
index 958f13d..43ef097 100644
--- a/depends/dbcommon/src/dbcommon/function/typecast-func.cc
+++ b/depends/dbcommon/src/dbcommon/function/typecast-func.cc
@@ -18,6 +18,7 @@
  */
 
 #include <cmath>
+#include <tuple>
 #include <fstream>
 
 //#include <boost/lexical_cast.hpp>
diff --git a/depends/dbcommon/src/dbcommon/function/typecast-function.cc b/depends/dbcommon/src/dbcommon/function/typecast-function.cc
index cb547cc..deee42f 100644
--- a/depends/dbcommon/src/dbcommon/function/typecast-function.cc
+++ b/depends/dbcommon/src/dbcommon/function/typecast-function.cc
@@ -21,6 +21,7 @@
 
 #include <iomanip>
 #include <string>
+#include <tuple>
 #include <typeinfo>
 
 #include "dbcommon/common/vector-transformer.h"
@@ -225,5 +226,42 @@
 Datum float8_to_text(Datum *params, uint64_t size) {
   return floattype_to_text<double>(params, size);
 }
+inline std::tuple<int64_t, int64_t> double_to_time(double epoch) {
+  int64_t second, nanosecond;
+  second = (int64_t)epoch;
+  nanosecond = (int64_t)((epoch - second) / 1e-6) * 1000;
+  TimezoneUtil::setGMTOffset("PRC");
+  return std::make_tuple(second, nanosecond);
+}
+Datum double_to_timestamp(Datum *params, uint64_t size) {
+  assert(size == 2);
+  Object *para = params[1];
+  if (dynamic_cast<Vector *>(para)) {
+    Vector *retVector = params[0];
+    Vector *srcVector = params[1];
+
+    FixedSizeTypeVectorRawData<double> src(srcVector);
+    retVector->resize(src.plainSize, src.sel, src.nulls);
+    TimestampVectorRawData ret(retVector);
+
+    auto totimestamp = [&](uint64_t plainIdx) {
+      std::tie(ret.seconds[plainIdx], ret.nanoseconds[plainIdx]) =
+          double_to_time(src.values[plainIdx]);
+    };
+    dbcommon::transformVector(ret.plainSize, ret.sel, ret.nulls, totimestamp);
+  } else {
+    Scalar *retScalar = params[0];
+    Scalar *srcScalar = params[1];
+    if (srcScalar->isnull) {
+      retScalar->isnull = true;
+    } else {
+      retScalar->isnull = false;
+      double src = srcScalar->value;
+      Timestamp *ret = retScalar->allocateValue<Timestamp>();
+      std::tie(ret->second, ret->nanosecond) = double_to_time(src);
+    }
+  }
+  return params[0];
+}
 
 }  // namespace dbcommon
diff --git a/depends/dbcommon/src/dbcommon/function/typecast-function.h b/depends/dbcommon/src/dbcommon/function/typecast-function.h
index 7171030..b776dd9 100644
--- a/depends/dbcommon/src/dbcommon/function/typecast-function.h
+++ b/depends/dbcommon/src/dbcommon/function/typecast-function.h
@@ -34,6 +34,7 @@
 Datum text_to_char(Datum *params, uint64_t size);
 Datum int4_to_char(Datum *params, uint64_t size);
 Datum decimal_to_text(Datum *params, uint64_t size);
+Datum double_to_timestamp(Datum *params, uint64_t size);
 
 }  // namespace dbcommon
 
diff --git a/depends/dbcommon/src/dbcommon/type/date.h b/depends/dbcommon/src/dbcommon/type/date.h
index 1900631..4a33727 100644
--- a/depends/dbcommon/src/dbcommon/type/date.h
+++ b/depends/dbcommon/src/dbcommon/type/date.h
@@ -37,6 +37,8 @@
 #define POSTGRES_EPOCH_JDATE 2451545      /* == date2j(2000, 1, 1) */
 #define ORC_TIMESTAMP_EPOCH_JDATE 2457024 /* == date2j(2015, 1, 1) */
 #define AD_EPOCH_JDATE 719162             /* == date2j(0001, 1, 1) */
+#define TIMEZONE_ADJUST \
+  -1325491552 /* == date_part('epoch','1927-12-31 23:54:08')*/
 
 const int64_t SECONDS_PER_HOUR = 60 * 60;
 const int64_t SECONDS_PER_DAY = SECONDS_PER_HOUR * 24;
@@ -774,6 +776,9 @@
 
   static std::string timezoneToString(int64_t offset) {
     int timezone = offset / SECONDS_PER_HOUR;
+    int time = offset - timezone * SECONDS_PER_HOUR;
+    int t_minute = time / 60;
+    int t_second = time % 60;
     std::string result = "";
     if (timezone < 0) {
       result += "-";
@@ -782,6 +787,14 @@
     }
     if (timezone < 10) result += "0";
     result += std::to_string(std::abs(timezone));
+    if (time) {
+      result += ":";
+      if (t_minute > 0 && t_minute < 10) result += "0";
+      result += std::to_string(std::abs(t_minute));
+      result += ":";
+      if (t_second > 0 && t_second < 10) result += "0";
+      result += std::to_string(std::abs(t_second));
+    }
     return result;
   }
 
@@ -840,6 +853,10 @@
 
     int32_t timezoneOffset = TimezoneUtil::getGMTOffset(second);
     second += timezoneOffset;
+    if (second < timezoneOffset + TIMEZONE_ADJUST) {
+      timezoneOffset += 352;
+      second += 352;
+    }
     int32_t days = (int32_t)(second / SECONDS_PER_DAY);
     int64_t seconds = second % SECONDS_PER_DAY * 1000000;
     if (seconds < 0) {
diff --git a/depends/dbcommon/test/unit/function/test-typecast-function.cc b/depends/dbcommon/test/unit/function/test-typecast-function.cc
index 938db38..e2a8fe7 100644
--- a/depends/dbcommon/test/unit/function/test-typecast-function.cc
+++ b/depends/dbcommon/test/unit/function/test-typecast-function.cc
@@ -291,5 +291,13 @@
                       TestFunctionEntry{FuncKind::BIGINT_TO_BOOLEAN,
                                         "Vector: t t t f NULL",
                                         {"Vector: 1 3 -2 0 NULL"}}));
+// TEST(TestFunction, double_to_timestamp) {}
+INSTANTIATE_TEST_CASE_P(
+    double_to_timestamp, TestFunction,
+    ::testing::Values(TestFunctionEntry{
+        FuncKind::DOUBLE_TO_TIMESTAMP,
+        "Vector{delimiter=,}: 1927-12-31 23:54:08+08,1973-11-30 "
+        "05:33:09+08,NULL",
+        {"Vector{delimiter=,}: -1325491552,NULL"}}));
 
 }  // namespace dbcommon