-
Notifications
You must be signed in to change notification settings - Fork 29.3k
[SPARK-20639][SQL] Add single argument support for to_timestamp in SQL with documentation improvement #17901
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
45bf353
f8921f4
b2d3b0a
497a229
b6f867c
fc02460
b038927
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -144,12 +144,6 @@ def _(): | |
| 'measured in radians.', | ||
| } | ||
|
|
||
| _functions_2_2 = { | ||
| 'to_date': 'Converts a string date into a DateType using the (optionally) specified format.', | ||
| 'to_timestamp': 'Converts a string timestamp into a timestamp type using the ' + | ||
| '(optionally) specified format.', | ||
| } | ||
|
|
||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems not used.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually, instead of deleting this we should keep it and we should add this is for doc tag
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in fact, we might need this as a standalone fix for 2.2
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Up to my knowledge, these were for defining single argumented function that takes a column conveniently but we are defining them below already and both look taking additional format argument. Finally both look having the annotatioms correctly. Let me double check and address this comment if possible.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually, that's right - we don't need them - not sure if these are left behind from before |
||
| # math functions that take two arguments as input | ||
| _binary_mathfunctions = { | ||
| 'atan2': 'Returns the angle theta from the conversion of rectangular coordinates (x, y) to' + | ||
|
|
@@ -987,9 +981,10 @@ def months_between(date1, date2): | |
| def to_date(col, format=None): | ||
| """Converts a :class:`Column` of :class:`pyspark.sql.types.StringType` or | ||
| :class:`pyspark.sql.types.TimestampType` into :class:`pyspark.sql.types.DateType` | ||
| using the optionally specified format. Default format is 'yyyy-MM-dd'. | ||
| Specify formats according to | ||
| using the optionally specified format. Specify formats according to | ||
| `SimpleDateFormats <http://docs.oracle.com/javase/tutorial/i18n/format/simpleDateFormat.html>`_. | ||
| By default, it follows casting rules to :class:`pyspark.sql.types.DateType` if the format | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto, not sure if it's clear to python user with |
||
| is omitted (equivalent with ``col.cast("date")``). | ||
|
|
||
| >>> df = spark.createDataFrame([('1997-02-28 10:30:00',)], ['t']) | ||
| >>> df.select(to_date(df.t).alias('date')).collect() | ||
|
|
@@ -1011,9 +1006,10 @@ def to_date(col, format=None): | |
| def to_timestamp(col, format=None): | ||
| """Converts a :class:`Column` of :class:`pyspark.sql.types.StringType` or | ||
| :class:`pyspark.sql.types.TimestampType` into :class:`pyspark.sql.types.DateType` | ||
| using the optionally specified format. Default format is 'yyyy-MM-dd HH:mm:ss'. Specify | ||
| formats according to | ||
| using the optionally specified format. Specify formats according to | ||
| `SimpleDateFormats <http://docs.oracle.com/javase/tutorial/i18n/format/simpleDateFormat.html>`_. | ||
| By default, it follows casting rules to :class:`pyspark.sql.types.TimestampType` if the format | ||
| is omitted (equivalent with ``col.cast("timestamp")``). | ||
|
|
||
| >>> df = spark.createDataFrame([('1997-02-28 10:30:00',)], ['t']) | ||
| >>> df.select(to_timestamp(df.t).alias('dt')).collect() | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1146,44 +1146,21 @@ case class ToUTCTimestamp(left: Expression, right: Expression) | |
| } | ||
|
|
||
| /** | ||
| * Returns the date part of a timestamp or string. | ||
| * Parses a column to a date based on the given format. | ||
| */ | ||
| @ExpressionDescription( | ||
| usage = "_FUNC_(expr) - Extracts the date part of the date or timestamp expression `expr`.", | ||
| usage = """ | ||
| _FUNC_(date_str[, fmt]) - Parses the `date_str` expression with the `fmt` expression to | ||
| a date. Returns null with invalid input. By default, it follows casting rules to a date if | ||
| the `fmt` is omitted. | ||
| """, | ||
| extended = """ | ||
| Examples: | ||
| > SELECT _FUNC_('2009-07-30 04:17:52'); | ||
| 2009-07-30 | ||
| """) | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems not used. |
||
| case class ToDate(child: Expression) extends UnaryExpression with ImplicitCastInputTypes { | ||
|
|
||
| // Implicit casting of spark will accept string in both date and timestamp format, as | ||
| // well as TimestampType. | ||
| override def inputTypes: Seq[AbstractDataType] = Seq(DateType) | ||
|
|
||
| override def dataType: DataType = DateType | ||
|
|
||
| override def eval(input: InternalRow): Any = child.eval(input) | ||
|
|
||
| override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = { | ||
| defineCodeGen(ctx, ev, d => d) | ||
| } | ||
|
|
||
| override def prettyName: String = "to_date" | ||
| } | ||
|
|
||
| /** | ||
| * Parses a column to a date based on the given format. | ||
| */ | ||
| // scalastyle:off line.size.limit | ||
| @ExpressionDescription( | ||
| usage = "_FUNC_(date_str, fmt) - Parses the `left` expression with the `fmt` expression. Returns null with invalid input.", | ||
| extended = """ | ||
| Examples: | ||
| > SELECT _FUNC_('2016-12-31', 'yyyy-MM-dd'); | ||
| 2016-12-31 | ||
| """) | ||
| // scalastyle:on line.size.limit | ||
| case class ParseToDate(left: Expression, format: Option[Expression], child: Expression) | ||
| extends RuntimeReplaceable { | ||
|
|
||
|
|
@@ -1194,13 +1171,13 @@ case class ParseToDate(left: Expression, format: Option[Expression], child: Expr | |
|
|
||
| def this(left: Expression) = { | ||
| // backwards compatability | ||
| this(left, Option(null), ToDate(left)) | ||
| this(left, None, Cast(left, DateType)) | ||
| } | ||
|
|
||
| override def flatArguments: Iterator[Any] = Iterator(left, format) | ||
| override def sql: String = { | ||
| if (format.isDefined) { | ||
| s"$prettyName(${left.sql}, ${format.get.sql}" | ||
| s"$prettyName(${left.sql}, ${format.get.sql})" | ||
| } else { | ||
| s"$prettyName(${left.sql})" | ||
| } | ||
|
|
@@ -1212,24 +1189,36 @@ case class ParseToDate(left: Expression, format: Option[Expression], child: Expr | |
| /** | ||
| * Parses a column to a timestamp based on the supplied format. | ||
| */ | ||
| // scalastyle:off line.size.limit | ||
| @ExpressionDescription( | ||
| usage = "_FUNC_(timestamp, fmt) - Parses the `left` expression with the `format` expression to a timestamp. Returns null with invalid input.", | ||
| usage = """ | ||
| _FUNC_(timestamp[, fmt]) - Parses the `timestamp` expression with the `fmt` expression to | ||
| a timestamp. Returns null with invalid input. By default, it follows casting rules to | ||
| a timestamp if the `fmt` is omitted. | ||
| """, | ||
| extended = """ | ||
| Examples: | ||
| > SELECT _FUNC_('2016-12-31 00:12:00'); | ||
| 2016-12-31 00:12:00 | ||
| > SELECT _FUNC_('2016-12-31', 'yyyy-MM-dd'); | ||
| 2016-12-31 00:00:00.0 | ||
| 2016-12-31 00:00:00 | ||
| """) | ||
| // scalastyle:on line.size.limit | ||
| case class ParseToTimestamp(left: Expression, format: Expression, child: Expression) | ||
| case class ParseToTimestamp(left: Expression, format: Option[Expression], child: Expression) | ||
| extends RuntimeReplaceable { | ||
|
|
||
| def this(left: Expression, format: Expression) = { | ||
| this(left, format, Cast(UnixTimestamp(left, format), TimestampType)) | ||
| this(left, Option(format), Cast(UnixTimestamp(left, format), TimestampType)) | ||
| } | ||
|
|
||
| def this(left: Expression) = this(left, None, Cast(left, TimestampType)) | ||
|
|
||
| override def flatArguments: Iterator[Any] = Iterator(left, format) | ||
| override def sql: String = s"$prettyName(${left.sql}, ${format.sql})" | ||
| override def sql: String = { | ||
| if (format.isDefined) { | ||
| s"$prettyName(${left.sql}, ${format.get.sql})" | ||
| } else { | ||
| s"$prettyName(${left.sql})" | ||
| } | ||
| } | ||
|
|
||
| override def prettyName: String = "to_timestamp" | ||
| override def dataType: DataType = TimestampType | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2683,13 +2683,12 @@ object functions { | |
| def unix_timestamp(s: Column, p: String): Column = withExpr { UnixTimestamp(s.expr, Literal(p)) } | ||
|
|
||
| /** | ||
| * Convert time string to a Unix timestamp (in seconds). | ||
| * Uses the pattern "yyyy-MM-dd HH:mm:ss" and will return null on failure. | ||
| * Convert time string to a Unix timestamp (in seconds) by casting rules to `TimestampType`. | ||
| * @group datetime_funcs | ||
| * @since 2.2.0 | ||
| */ | ||
| def to_timestamp(s: Column): Column = withExpr { | ||
| new ParseToTimestamp(s.expr, Literal("yyyy-MM-dd HH:mm:ss")) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. here we change the default value of the format string to be locale sensitive(same as
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @rxin and @cloud-fan, I would rather take out the change here if this holds off this PR. This is essentially orthogonal with this PR. |
||
| new ParseToTimestamp(s.expr) | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -2704,15 +2703,15 @@ object functions { | |
| } | ||
|
|
||
| /** | ||
| * Converts the column into DateType. | ||
| * Converts the column into `DateType` by casting rules to `DateType`. | ||
| * | ||
| * @group datetime_funcs | ||
| * @since 1.5.0 | ||
| */ | ||
| def to_date(e: Column): Column = withExpr { ToDate(e.expr) } | ||
| def to_date(e: Column): Column = withExpr { new ParseToDate(e.expr) } | ||
|
|
||
| /** | ||
| * Converts the column into a DateType with a specified format | ||
| * Converts the column into a `DateType` with a specified format | ||
| * (see [http://docs.oracle.com/javase/tutorial/i18n/format/simpleDateFormat.html]) | ||
| * return null if fail. | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@felixcheung, I added an example here. Would this be enough?