diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala index 97aacb3f7530..bf5ffa2607f2 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/datetimeExpressions.scala @@ -353,6 +353,16 @@ case class SecondWithFraction(child: Expression, timeZoneId: Option[String] = No override val funcName = "getSecondsWithFraction" } +case class SecondsSinceEpoch(child: Expression, timeZoneId: Option[String] = None) + extends GetTimeField { + def this(child: Expression) = this(child, None) + override def dataType: DataType = DoubleType + override def withTimeZone(timeZoneId: String): SecondsSinceEpoch = + copy(timeZoneId = Option(timeZoneId)) + override val func = DateTimeUtils.getSecondsAfterEpoch + override val funcName = "getSecondsAfterEpoch" +} + trait GetDateField extends UnaryExpression with ImplicitCastInputTypes with NullIntolerant { val func: Int => Any val funcName: String @@ -1968,6 +1978,7 @@ object DatePart { case "HOUR" | "H" | "HOURS" | "HR" | "HRS" => Hour(source) case "MINUTE" | "M" | "MIN" | "MINS" | "MINUTES" => Minute(source) case "SECOND" | "S" | "SEC" | "SECONDS" | "SECS" => SecondWithFraction(source) + case "EPOCH" => SecondsSinceEpoch(source) case _ => errorHandleFunc } @@ -2055,6 +2066,7 @@ case class DatePart(field: Expression, source: Expression, child: Expression) - "HOUR", ("H", "HOURS", "HR", "HRS") - The hour field (0 - 23) - "MINUTE", ("M", "MIN", "MINS", "MINUTES") - the minutes field (0 - 59) - "SECOND", ("S", "SEC", "SECONDS", "SECS") - the seconds field, including fractional parts + - "EPOCH" - the number of seconds since 1970-01-01 00:00:00-00 (can be negative) - Supported string values of `field` for interval(which consists of `months`, `days`, `microseconds`) are(case insensitive): - "YEAR", ("Y", "YEARS", "YR", "YRS") - the total `months` / 12 - "MONTH", ("MON", "MONS", "MONTHS") - the total `months` % 12 diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/DateTimeUtils.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/DateTimeUtils.scala index 3b974759bd6c..8b26879b32f4 100644 --- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/DateTimeUtils.scala +++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/util/DateTimeUtils.scala @@ -493,6 +493,13 @@ object DateTimeUtils { Decimal(getMicroseconds(micros, zoneId), 8, 6) } + /** + * Returns the number of seconds since 1970-01-01 00:00:00-00 (can be negative). + */ + def getSecondsAfterEpoch(micros: Long, zoneId: ZoneId): Double = { + micros.toDouble / MICROS_PER_SECOND + } + /** * Returns local seconds, including fractional parts, multiplied by 1000000. * diff --git a/sql/core/src/test/resources/sql-tests/inputs/extract.sql b/sql/core/src/test/resources/sql-tests/inputs/extract.sql index 0f1fd5bbcca0..fde4974e4120 100644 --- a/sql/core/src/test/resources/sql-tests/inputs/extract.sql +++ b/sql/core/src/test/resources/sql-tests/inputs/extract.sql @@ -50,6 +50,8 @@ select extract(sec from c), extract(sec from i) from t; select extract(seconds from c), extract(seconds from i) from t; select extract(secs from c), extract(secs from i) from t; +select extract(epoch from c) from t; + select extract(not_supported from c) from t; select extract(not_supported from i) from t; @@ -103,6 +105,8 @@ select date_part('sec', c), date_part('sec', i) from t; select date_part('seconds', c), date_part('seconds', i) from t; select date_part('secs', c), date_part('secs', i) from t; +select date_part('epoch', c) from t; + select date_part('not_supported', c) from t; select date_part(c, c) from t; select date_part(null, c) from t; diff --git a/sql/core/src/test/resources/sql-tests/results/extract.sql.out b/sql/core/src/test/resources/sql-tests/results/extract.sql.out index 9d3fe5d17faf..ce3133b62e21 100644 --- a/sql/core/src/test/resources/sql-tests/results/extract.sql.out +++ b/sql/core/src/test/resources/sql-tests/results/extract.sql.out @@ -1,5 +1,5 @@ -- Automatically generated by SQLQueryTestSuite --- Number of queries: 100 +-- Number of queries: 102 -- !query @@ -314,6 +314,14 @@ struct 9.123456 6.789000 +-- !query +select extract(epoch from c) from t +-- !query schema +struct +-- !query output +1.304690889123456E9 + + -- !query select extract(not_supported from c) from t -- !query schema @@ -636,6 +644,14 @@ struct 9.123456 6.789000 +-- !query +select date_part('epoch', c) from t +-- !query schema +struct +-- !query output +1.304690889123456E9 + + -- !query select date_part('not_supported', c) from t -- !query schema