Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gengliangwang If you would like to be compatible to PostgreSQL, you need to take the removed implementation:

/**
   * Returns the number of seconds with fractional part in microsecond precision
   * since 1970-01-01 00:00:00 local time.
   */
  def getEpoch(timestamp: SQLTimestamp, zoneId: ZoneId): Decimal = {
    val offset = SECONDS.toMicros(
      zoneId.getRules.getOffset(microsToInstant(timestamp)).getTotalSeconds)
    val sinceEpoch = timestamp + offset
    Decimal(sinceEpoch, 20, 6)
  }

PostgreSQL takes seconds since the local epoch 1970-01-01 00:00:00-00 but your implementation calculates seconds since 1970-01-01 00:00:00-00Z (in UTC time zone).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1, thanks for pointing it out 👍

}

/**
* Returns local seconds, including fractional parts, multiplied by 1000000.
*
Expand Down
4 changes: 4 additions & 0 deletions sql/core/src/test/resources/sql-tests/inputs/extract.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
18 changes: 17 additions & 1 deletion sql/core/src/test/resources/sql-tests/results/extract.sql.out
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-- Automatically generated by SQLQueryTestSuite
-- Number of queries: 100
-- Number of queries: 102


-- !query
Expand Down Expand Up @@ -314,6 +314,14 @@ struct<extract(secs FROM c):decimal(8,6),extract(secs FROM i):decimal(8,6)>
9.123456 6.789000


-- !query
select extract(epoch from c) from t
-- !query schema
struct<extract(epoch FROM c):double>
-- !query output
1.304690889123456E9


-- !query
select extract(not_supported from c) from t
-- !query schema
Expand Down Expand Up @@ -636,6 +644,14 @@ struct<date_part(secs, c):decimal(8,6),date_part(secs, i):decimal(8,6)>
9.123456 6.789000


-- !query
select date_part('epoch', c) from t
-- !query schema
struct<date_part(epoch, c):double>
-- !query output
1.304690889123456E9


-- !query
select date_part('not_supported', c) from t
-- !query schema
Expand Down