[SPARK-28656][SQL] Support millennium, century and decade at extract()

## What changes were proposed in this pull request?

In the PR, I propose new expressions `Millennium`, `Century` and `Decade`, and support additional parameters of `extract()` for feature parity with PostgreSQL (https://www.postgresql.org/docs/11/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT):

1. `millennium` - the current millennium for given date (or a timestamp implicitly casted to a date). For example, years in the 1900s are in the second millennium. The third millennium started _January 1, 2001_.
2. `century` - the current millennium for given date (or timestamp). The first century starts at 0001-01-01 AD.
3. `decade` - the current decade for given date (or timestamp). Actually, this is the year field divided by 10.

Here are examples:
```sql
spark-sql> SELECT EXTRACT(MILLENNIUM FROM DATE '1981-01-19');
2
spark-sql> SELECT EXTRACT(CENTURY FROM DATE '1981-01-19');
20
spark-sql> SELECT EXTRACT(DECADE FROM DATE '1981-01-19');
198
```

## How was this patch tested?

Added new tests to `DateExpressionsSuite` and uncommented existing tests in `pgSQL/date.sql`.

Closes #25388 from MaxGekk/extract-ext2.

Authored-by: Maxim Gekk <max.gekk@gmail.com>
Signed-off-by: Dongjoon Hyun <dhyun@apple.com>
This commit is contained in:
Maxim Gekk 2019-08-09 11:18:50 -07:00 committed by Dongjoon Hyun
parent 8b08e14de7
commit 924d794a6f
6 changed files with 399 additions and 81 deletions

View file

@ -1828,3 +1828,51 @@ case class MakeTimestamp(
override def prettyName: String = "make_timestamp"
}
case class Millennium(child: Expression) extends UnaryExpression with ImplicitCastInputTypes {
override def inputTypes: Seq[AbstractDataType] = Seq(DateType)
override def dataType: DataType = IntegerType
override protected def nullSafeEval(date: Any): Any = {
DateTimeUtils.getMillennium(date.asInstanceOf[Int])
}
override protected def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = {
val dtu = DateTimeUtils.getClass.getName.stripSuffix("$")
defineCodeGen(ctx, ev, c => s"$dtu.getMillennium($c)")
}
}
case class Century(child: Expression) extends UnaryExpression with ImplicitCastInputTypes {
override def inputTypes: Seq[AbstractDataType] = Seq(DateType)
override def dataType: DataType = IntegerType
override protected def nullSafeEval(date: Any): Any = {
DateTimeUtils.getCentury(date.asInstanceOf[Int])
}
override protected def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = {
val dtu = DateTimeUtils.getClass.getName.stripSuffix("$")
defineCodeGen(ctx, ev, c => s"$dtu.getCentury($c)")
}
}
case class Decade(child: Expression) extends UnaryExpression with ImplicitCastInputTypes {
override def inputTypes: Seq[AbstractDataType] = Seq(DateType)
override def dataType: DataType = IntegerType
override protected def nullSafeEval(date: Any): Any = {
DateTimeUtils.getDecade(date.asInstanceOf[Int])
}
override protected def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = {
val dtu = DateTimeUtils.getClass.getName.stripSuffix("$")
defineCodeGen(ctx, ev, c => s"$dtu.getDecade($c)")
}
}

View file

@ -1396,6 +1396,12 @@ class AstBuilder(conf: SQLConf) extends SqlBaseBaseVisitor[AnyRef] with Logging
*/
override def visitExtract(ctx: ExtractContext): Expression = withOrigin(ctx) {
ctx.field.getText.toUpperCase(Locale.ROOT) match {
case "MILLENNIUM" =>
Millennium(expression(ctx.source))
case "CENTURY" =>
Century(expression(ctx.source))
case "DECADE" =>
Decade(expression(ctx.source))
case "YEAR" =>
Year(expression(ctx.source))
case "QUARTER" =>

View file

@ -19,7 +19,7 @@ package org.apache.spark.sql.catalyst.util
import java.sql.{Date, Timestamp}
import java.time._
import java.time.temporal.{ChronoUnit, IsoFields}
import java.time.temporal.{ChronoField, ChronoUnit, IsoFields}
import java.util.{Locale, TimeZone}
import java.util.concurrent.TimeUnit._
@ -463,6 +463,24 @@ object DateTimeUtils {
LocalDate.ofEpochDay(date).getDayOfYear
}
private def extractFromYear(date: SQLDate, divider: Int): Int = {
val localDate = daysToLocalDate(date)
val yearOfEra = localDate.get(ChronoField.YEAR_OF_ERA)
var result = yearOfEra / divider
if ((yearOfEra % divider) != 0 || yearOfEra <= 1) result += 1
if (localDate.get(ChronoField.ERA) == 0) result = -result
result
}
/** Returns the millennium for the given date. The date is expressed in days since 1.1.1970. */
def getMillennium(date: SQLDate): Int = extractFromYear(date, 1000)
/** Returns the century for the given date. The date is expressed in days since 1.1.1970. */
def getCentury(date: SQLDate): Int = extractFromYear(date, 100)
/** Returns the decade for the given date. The date is expressed in days since 1.1.1970. */
def getDecade(date: SQLDate): Int = Math.floorDiv(getYear(date), 10)
/**
* Returns the year value for the given date. The date is expressed in days
* since 1.1.1970.

View file

@ -968,4 +968,42 @@ class DateExpressionsSuite extends SparkFunSuite with ExpressionEvalHelper {
checkEvaluation(makeTimestampExpr, Timestamp.valueOf("2019-07-01 00:00:00"))
checkEvaluation(makeTimestampExpr.copy(sec = Literal(60.5)), null)
}
test("millennium") {
val date = MakeDate(Literal(2019), Literal(1), Literal(1))
checkEvaluation(Millennium(date), 3)
checkEvaluation(Millennium(date.copy(year = Literal(2001))), 3)
checkEvaluation(Millennium(date.copy(year = Literal(2000))), 2)
checkEvaluation(Millennium(date.copy(year = Literal(1001), day = Literal(28))), 2)
checkEvaluation(Millennium(date.copy(year = Literal(1))), 1)
checkEvaluation(Millennium(date.copy(year = Literal(-1))), -1)
checkEvaluation(Millennium(date.copy(year = Literal(-100), month = Literal(12))), -1)
checkEvaluation(Millennium(date.copy(year = Literal(-2019))), -3)
}
test("century") {
val date = MakeDate(Literal(2019), Literal(1), Literal(1))
checkEvaluation(Century(date), 21)
checkEvaluation(Century(date.copy(year = Literal(2001))), 21)
checkEvaluation(Century(date.copy(year = Literal(2000))), 20)
checkEvaluation(Century(date.copy(year = Literal(1001), day = Literal(28))), 11)
checkEvaluation(Century(date.copy(year = Literal(1))), 1)
checkEvaluation(Century(date.copy(year = Literal(-1))), -1)
checkEvaluation(Century(date.copy(year = Literal(-100), month = Literal(12))), -2)
checkEvaluation(Century(date.copy(year = Literal(-2019))), -21)
}
test("decade") {
val date = MakeDate(Literal(2019), Literal(8), Literal(8))
checkEvaluation(Decade(date), 201)
checkEvaluation(Decade(date.copy(year = Literal(2011))), 201)
checkEvaluation(Decade(date.copy(year = Literal(2010))), 201)
checkEvaluation(Decade(date.copy(year = Literal(2009))), 200)
checkEvaluation(Decade(date.copy(year = Literal(10))), 1)
checkEvaluation(Decade(date.copy(year = Literal(1))), 0)
checkEvaluation(Decade(date.copy(year = Literal(-1))), -1)
checkEvaluation(Decade(date.copy(year = Literal(-10))), -1)
checkEvaluation(Decade(date.copy(year = Literal(-11))), -2)
checkEvaluation(Decade(date.copy(year = Literal(-2019))), -202)
}
}

View file

@ -234,44 +234,44 @@ SELECT f1 - date '2000-01-01' AS `Days From 2K` FROM DATE_TBL;
-- SELECT EXTRACT(EPOCH FROM TIMESTAMPTZ '1970-01-01+00'); -- 0
--
-- century
--
-- SELECT EXTRACT(CENTURY FROM DATE '0101-12-31 BC'); -- -2
-- SELECT EXTRACT(CENTURY FROM DATE '0100-12-31 BC'); -- -1
-- SELECT EXTRACT(CENTURY FROM DATE '0001-12-31 BC'); -- -1
-- SELECT EXTRACT(CENTURY FROM DATE '0001-01-01'); -- 1
-- SELECT EXTRACT(CENTURY FROM DATE '0001-01-01 AD'); -- 1
-- SELECT EXTRACT(CENTURY FROM DATE '1900-12-31'); -- 19
-- SELECT EXTRACT(CENTURY FROM DATE '1901-01-01'); -- 20
-- SELECT EXTRACT(CENTURY FROM DATE '2000-12-31'); -- 20
-- SELECT EXTRACT(CENTURY FROM DATE '2001-01-01'); -- 21
-- SELECT EXTRACT(CENTURY FROM CURRENT_DATE)>=21 AS True; -- true
--
SELECT EXTRACT(CENTURY FROM TO_DATE('0101-12-31 BC', 'yyyy-MM-dd G'));
SELECT EXTRACT(CENTURY FROM TO_DATE('0100-12-31 BC', 'yyyy-MM-dd G'));
SELECT EXTRACT(CENTURY FROM TO_DATE('0001-12-31 BC', 'yyyy-MM-dd G'));
SELECT EXTRACT(CENTURY FROM DATE '0001-01-01');
SELECT EXTRACT(CENTURY FROM DATE '0001-01-01 AD');
SELECT EXTRACT(CENTURY FROM DATE '1900-12-31');
SELECT EXTRACT(CENTURY FROM DATE '1901-01-01');
SELECT EXTRACT(CENTURY FROM DATE '2000-12-31');
SELECT EXTRACT(CENTURY FROM DATE '2001-01-01');
SELECT EXTRACT(CENTURY FROM CURRENT_DATE)>=21 AS True;
-- millennium
--
-- SELECT EXTRACT(MILLENNIUM FROM DATE '0001-12-31 BC'); -- -1
-- SELECT EXTRACT(MILLENNIUM FROM DATE '0001-01-01 AD'); -- 1
-- SELECT EXTRACT(MILLENNIUM FROM DATE '1000-12-31'); -- 1
-- SELECT EXTRACT(MILLENNIUM FROM DATE '1001-01-01'); -- 2
-- SELECT EXTRACT(MILLENNIUM FROM DATE '2000-12-31'); -- 2
-- SELECT EXTRACT(MILLENNIUM FROM DATE '2001-01-01'); -- 3
SELECT EXTRACT(MILLENNIUM FROM TO_DATE('0001-12-31 BC', 'yyyy-MM-dd G'));
SELECT EXTRACT(MILLENNIUM FROM DATE '0001-01-01 AD');
SELECT EXTRACT(MILLENNIUM FROM DATE '1000-12-31');
SELECT EXTRACT(MILLENNIUM FROM DATE '1001-01-01');
SELECT EXTRACT(MILLENNIUM FROM DATE '2000-12-31');
SELECT EXTRACT(MILLENNIUM FROM DATE '2001-01-01');
-- next test to be fixed on the turn of the next millennium;-)
-- SELECT EXTRACT(MILLENNIUM FROM CURRENT_DATE); -- 3
--
SELECT EXTRACT(MILLENNIUM FROM CURRENT_DATE);
-- decade
--
-- SELECT EXTRACT(DECADE FROM DATE '1994-12-25'); -- 199
-- SELECT EXTRACT(DECADE FROM DATE '0010-01-01'); -- 1
-- SELECT EXTRACT(DECADE FROM DATE '0009-12-31'); -- 0
-- SELECT EXTRACT(DECADE FROM DATE '0001-01-01 BC'); -- 0
-- SELECT EXTRACT(DECADE FROM DATE '0002-12-31 BC'); -- -1
-- SELECT EXTRACT(DECADE FROM DATE '0011-01-01 BC'); -- -1
-- SELECT EXTRACT(DECADE FROM DATE '0012-12-31 BC'); -- -2
--
SELECT EXTRACT(DECADE FROM DATE '1994-12-25');
SELECT EXTRACT(DECADE FROM DATE '0010-01-01');
SELECT EXTRACT(DECADE FROM DATE '0009-12-31');
SELECT EXTRACT(DECADE FROM TO_DATE('0001-01-01 BC', 'yyyy-MM-dd G'));
SELECT EXTRACT(DECADE FROM TO_DATE('0002-12-31 BC', 'yyyy-MM-dd G'));
SELECT EXTRACT(DECADE FROM TO_DATE('0011-01-01 BC', 'yyyy-MM-dd G'));
SELECT EXTRACT(DECADE FROM TO_DATE('0012-12-31 BC', 'yyyy-MM-dd G'));
-- some other types:
--
-- on a timestamp.
-- SELECT EXTRACT(CENTURY FROM NOW())>=21 AS True; -- true
-- SELECT EXTRACT(CENTURY FROM TIMESTAMP '1970-03-20 04:30:00.00000'); -- 20
SELECT EXTRACT(CENTURY FROM NOW())>=21 AS True;
SELECT EXTRACT(CENTURY FROM TIMESTAMP '1970-03-20 04:30:00.00000');
-- on an interval
-- SELECT EXTRACT(CENTURY FROM INTERVAL '100 y'); -- 1
-- SELECT EXTRACT(CENTURY FROM INTERVAL '99 y'); -- 0

View file

@ -1,5 +1,5 @@
-- Automatically generated by SQLQueryTestSuite
-- Number of queries: 63
-- Number of queries: 89
-- !query 0
@ -502,128 +502,336 @@ struct<Days From 2K:int>
-- !query 47
SELECT DATE_TRUNC('MILLENNIUM', TIMESTAMP '1970-03-20 04:30:00.00000')
SELECT EXTRACT(CENTURY FROM TO_DATE('0101-12-31 BC', 'yyyy-MM-dd G'))
-- !query 47 schema
struct<date_trunc(MILLENNIUM, TIMESTAMP('1970-03-20 04:30:00')):timestamp>
struct<century(to_date('0101-12-31 BC', 'yyyy-MM-dd G')):int>
-- !query 47 output
1001-01-01 00:07:02
-2
-- !query 48
SELECT DATE_TRUNC('MILLENNIUM', DATE '1970-03-20')
SELECT EXTRACT(CENTURY FROM TO_DATE('0100-12-31 BC', 'yyyy-MM-dd G'))
-- !query 48 schema
struct<date_trunc(MILLENNIUM, CAST(DATE '1970-03-20' AS TIMESTAMP)):timestamp>
struct<century(to_date('0100-12-31 BC', 'yyyy-MM-dd G')):int>
-- !query 48 output
1001-01-01 00:07:02
-1
-- !query 49
SELECT DATE_TRUNC('CENTURY', TIMESTAMP '1970-03-20 04:30:00.00000')
SELECT EXTRACT(CENTURY FROM TO_DATE('0001-12-31 BC', 'yyyy-MM-dd G'))
-- !query 49 schema
struct<date_trunc(CENTURY, TIMESTAMP('1970-03-20 04:30:00')):timestamp>
struct<century(to_date('0001-12-31 BC', 'yyyy-MM-dd G')):int>
-- !query 49 output
1901-01-01 00:00:00
-1
-- !query 50
SELECT DATE_TRUNC('CENTURY', DATE '1970-03-20')
SELECT EXTRACT(CENTURY FROM DATE '0001-01-01')
-- !query 50 schema
struct<date_trunc(CENTURY, CAST(DATE '1970-03-20' AS TIMESTAMP)):timestamp>
struct<century(DATE '0001-01-01'):int>
-- !query 50 output
1901-01-01 00:00:00
1
-- !query 51
SELECT DATE_TRUNC('CENTURY', DATE '2004-08-10')
SELECT EXTRACT(CENTURY FROM DATE '0001-01-01 AD')
-- !query 51 schema
struct<date_trunc(CENTURY, CAST(DATE '2004-08-10' AS TIMESTAMP)):timestamp>
struct<century(DATE '0001-01-01'):int>
-- !query 51 output
2001-01-01 00:00:00
1
-- !query 52
SELECT DATE_TRUNC('CENTURY', DATE '0002-02-04')
SELECT EXTRACT(CENTURY FROM DATE '1900-12-31')
-- !query 52 schema
struct<date_trunc(CENTURY, CAST(DATE '0002-02-04' AS TIMESTAMP)):timestamp>
struct<century(DATE '1900-12-31'):int>
-- !query 52 output
0001-01-01 00:07:02
19
-- !query 53
SELECT DATE_TRUNC('CENTURY', TO_DATE('0055-08-10 BC', 'yyyy-MM-dd G'))
SELECT EXTRACT(CENTURY FROM DATE '1901-01-01')
-- !query 53 schema
struct<date_trunc(CENTURY, CAST(to_date('0055-08-10 BC', 'yyyy-MM-dd G') AS TIMESTAMP)):timestamp>
struct<century(DATE '1901-01-01'):int>
-- !query 53 output
-0099-01-01 00:07:02
20
-- !query 54
SELECT DATE_TRUNC('DECADE', DATE '1993-12-25')
SELECT EXTRACT(CENTURY FROM DATE '2000-12-31')
-- !query 54 schema
struct<date_trunc(DECADE, CAST(DATE '1993-12-25' AS TIMESTAMP)):timestamp>
struct<century(DATE '2000-12-31'):int>
-- !query 54 output
1990-01-01 00:00:00
20
-- !query 55
SELECT DATE_TRUNC('DECADE', DATE '0004-12-25')
SELECT EXTRACT(CENTURY FROM DATE '2001-01-01')
-- !query 55 schema
struct<date_trunc(DECADE, CAST(DATE '0004-12-25' AS TIMESTAMP)):timestamp>
struct<century(DATE '2001-01-01'):int>
-- !query 55 output
0000-01-01 00:07:02
21
-- !query 56
SELECT DATE_TRUNC('DECADE', TO_DATE('0002-12-31 BC', 'yyyy-MM-dd G'))
SELECT EXTRACT(CENTURY FROM CURRENT_DATE)>=21 AS True
-- !query 56 schema
struct<date_trunc(DECADE, CAST(to_date('0002-12-31 BC', 'yyyy-MM-dd G') AS TIMESTAMP)):timestamp>
struct<True:boolean>
-- !query 56 output
-0010-01-01 00:07:02
true
-- !query 57
select make_date(2013, 7, 15)
SELECT EXTRACT(MILLENNIUM FROM TO_DATE('0001-12-31 BC', 'yyyy-MM-dd G'))
-- !query 57 schema
struct<make_date(2013, 7, 15):date>
struct<millennium(to_date('0001-12-31 BC', 'yyyy-MM-dd G')):int>
-- !query 57 output
2013-07-15
-1
-- !query 58
select make_date(-44, 3, 15)
SELECT EXTRACT(MILLENNIUM FROM DATE '0001-01-01 AD')
-- !query 58 schema
struct<make_date(-44, 3, 15):date>
struct<millennium(DATE '0001-01-01'):int>
-- !query 58 output
-0044-03-15
1
-- !query 59
select make_date(2013, 2, 30)
SELECT EXTRACT(MILLENNIUM FROM DATE '1000-12-31')
-- !query 59 schema
struct<make_date(2013, 2, 30):date>
struct<millennium(DATE '1000-12-31'):int>
-- !query 59 output
NULL
1
-- !query 60
select make_date(2013, 13, 1)
SELECT EXTRACT(MILLENNIUM FROM DATE '1001-01-01')
-- !query 60 schema
struct<make_date(2013, 13, 1):date>
struct<millennium(DATE '1001-01-01'):int>
-- !query 60 output
NULL
2
-- !query 61
select make_date(2013, 11, -1)
SELECT EXTRACT(MILLENNIUM FROM DATE '2000-12-31')
-- !query 61 schema
struct<make_date(2013, 11, -1):date>
struct<millennium(DATE '2000-12-31'):int>
-- !query 61 output
NULL
2
-- !query 62
DROP TABLE DATE_TBL
SELECT EXTRACT(MILLENNIUM FROM DATE '2001-01-01')
-- !query 62 schema
struct<>
struct<millennium(DATE '2001-01-01'):int>
-- !query 62 output
3
-- !query 63
SELECT EXTRACT(MILLENNIUM FROM CURRENT_DATE)
-- !query 63 schema
struct<millennium(current_date()):int>
-- !query 63 output
3
-- !query 64
SELECT EXTRACT(DECADE FROM DATE '1994-12-25')
-- !query 64 schema
struct<decade(DATE '1994-12-25'):int>
-- !query 64 output
199
-- !query 65
SELECT EXTRACT(DECADE FROM DATE '0010-01-01')
-- !query 65 schema
struct<decade(DATE '0010-01-01'):int>
-- !query 65 output
1
-- !query 66
SELECT EXTRACT(DECADE FROM DATE '0009-12-31')
-- !query 66 schema
struct<decade(DATE '0009-12-31'):int>
-- !query 66 output
0
-- !query 67
SELECT EXTRACT(DECADE FROM TO_DATE('0001-01-01 BC', 'yyyy-MM-dd G'))
-- !query 67 schema
struct<decade(to_date('0001-01-01 BC', 'yyyy-MM-dd G')):int>
-- !query 67 output
0
-- !query 68
SELECT EXTRACT(DECADE FROM TO_DATE('0002-12-31 BC', 'yyyy-MM-dd G'))
-- !query 68 schema
struct<decade(to_date('0002-12-31 BC', 'yyyy-MM-dd G')):int>
-- !query 68 output
-1
-- !query 69
SELECT EXTRACT(DECADE FROM TO_DATE('0011-01-01 BC', 'yyyy-MM-dd G'))
-- !query 69 schema
struct<decade(to_date('0011-01-01 BC', 'yyyy-MM-dd G')):int>
-- !query 69 output
-1
-- !query 70
SELECT EXTRACT(DECADE FROM TO_DATE('0012-12-31 BC', 'yyyy-MM-dd G'))
-- !query 70 schema
struct<decade(to_date('0012-12-31 BC', 'yyyy-MM-dd G')):int>
-- !query 70 output
-2
-- !query 71
SELECT EXTRACT(CENTURY FROM NOW())>=21 AS True
-- !query 71 schema
struct<True:boolean>
-- !query 71 output
true
-- !query 72
SELECT EXTRACT(CENTURY FROM TIMESTAMP '1970-03-20 04:30:00.00000')
-- !query 72 schema
struct<century(CAST(TIMESTAMP('1970-03-20 04:30:00') AS DATE)):int>
-- !query 72 output
20
-- !query 73
SELECT DATE_TRUNC('MILLENNIUM', TIMESTAMP '1970-03-20 04:30:00.00000')
-- !query 73 schema
struct<date_trunc(MILLENNIUM, TIMESTAMP('1970-03-20 04:30:00')):timestamp>
-- !query 73 output
1001-01-01 00:07:02
-- !query 74
SELECT DATE_TRUNC('MILLENNIUM', DATE '1970-03-20')
-- !query 74 schema
struct<date_trunc(MILLENNIUM, CAST(DATE '1970-03-20' AS TIMESTAMP)):timestamp>
-- !query 74 output
1001-01-01 00:07:02
-- !query 75
SELECT DATE_TRUNC('CENTURY', TIMESTAMP '1970-03-20 04:30:00.00000')
-- !query 75 schema
struct<date_trunc(CENTURY, TIMESTAMP('1970-03-20 04:30:00')):timestamp>
-- !query 75 output
1901-01-01 00:00:00
-- !query 76
SELECT DATE_TRUNC('CENTURY', DATE '1970-03-20')
-- !query 76 schema
struct<date_trunc(CENTURY, CAST(DATE '1970-03-20' AS TIMESTAMP)):timestamp>
-- !query 76 output
1901-01-01 00:00:00
-- !query 77
SELECT DATE_TRUNC('CENTURY', DATE '2004-08-10')
-- !query 77 schema
struct<date_trunc(CENTURY, CAST(DATE '2004-08-10' AS TIMESTAMP)):timestamp>
-- !query 77 output
2001-01-01 00:00:00
-- !query 78
SELECT DATE_TRUNC('CENTURY', DATE '0002-02-04')
-- !query 78 schema
struct<date_trunc(CENTURY, CAST(DATE '0002-02-04' AS TIMESTAMP)):timestamp>
-- !query 78 output
0001-01-01 00:07:02
-- !query 79
SELECT DATE_TRUNC('CENTURY', TO_DATE('0055-08-10 BC', 'yyyy-MM-dd G'))
-- !query 79 schema
struct<date_trunc(CENTURY, CAST(to_date('0055-08-10 BC', 'yyyy-MM-dd G') AS TIMESTAMP)):timestamp>
-- !query 79 output
-0099-01-01 00:07:02
-- !query 80
SELECT DATE_TRUNC('DECADE', DATE '1993-12-25')
-- !query 80 schema
struct<date_trunc(DECADE, CAST(DATE '1993-12-25' AS TIMESTAMP)):timestamp>
-- !query 80 output
1990-01-01 00:00:00
-- !query 81
SELECT DATE_TRUNC('DECADE', DATE '0004-12-25')
-- !query 81 schema
struct<date_trunc(DECADE, CAST(DATE '0004-12-25' AS TIMESTAMP)):timestamp>
-- !query 81 output
0000-01-01 00:07:02
-- !query 82
SELECT DATE_TRUNC('DECADE', TO_DATE('0002-12-31 BC', 'yyyy-MM-dd G'))
-- !query 82 schema
struct<date_trunc(DECADE, CAST(to_date('0002-12-31 BC', 'yyyy-MM-dd G') AS TIMESTAMP)):timestamp>
-- !query 82 output
-0010-01-01 00:07:02
-- !query 83
select make_date(2013, 7, 15)
-- !query 83 schema
struct<make_date(2013, 7, 15):date>
-- !query 83 output
2013-07-15
-- !query 84
select make_date(-44, 3, 15)
-- !query 84 schema
struct<make_date(-44, 3, 15):date>
-- !query 84 output
-0044-03-15
-- !query 85
select make_date(2013, 2, 30)
-- !query 85 schema
struct<make_date(2013, 2, 30):date>
-- !query 85 output
NULL
-- !query 86
select make_date(2013, 13, 1)
-- !query 86 schema
struct<make_date(2013, 13, 1):date>
-- !query 86 output
NULL
-- !query 87
select make_date(2013, 11, -1)
-- !query 87 schema
struct<make_date(2013, 11, -1):date>
-- !query 87 output
NULL
-- !query 88
DROP TABLE DATE_TBL
-- !query 88 schema
struct<>
-- !query 88 output