-
Notifications
You must be signed in to change notification settings - Fork 28.4k
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
[SPARK-8199][SPARK-8184][SPARK-8183][SPARK-8182][SPARK-8181][SPARK-8180][SPARK-8179][SPARK-8177][SPARK-8178][SPARK-9115][SQL] date functions #6981
Changes from 1 commit
d0e2f99
5ebb235
4d8049b
638596f
849fb41
c739788
b680db6
a5ea120
02efc5d
356df78
3bfac90
5fe74e1
a8edebd
f120415
eb6760d
5a105d9
7bc9d93
d9f8ac3
6f5d95c
f3e7a9f
7d9f0eb
10e4ad1
ccb723c
c42b444
ad17e96
f775f39
1a436c9
4fb66da
740af0e
1358cdc
ec87c69
0852655
1b2e540
b382267
d6aa14e
e223bc0
56c4a92
d01b977
2259299
523542d
0ad6db8
746b80a
cdfae27
fb98ba0
3c6ae2e
70238e0
ea6c110
4afc09c
6e0c78f
5983dcc
256c357
3e095ba
bb567b6
f7b4c8c
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 |
---|---|---|
@@ -0,0 +1,229 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.apache.spark.sql.catalyst.expressions | ||
|
||
import java.sql.Date | ||
import java.text.SimpleDateFormat | ||
|
||
import org.apache.spark.sql.catalyst.expressions.codegen.{GeneratedExpressionCode, CodeGenContext} | ||
import org.apache.spark.sql.catalyst.util.DateTimeUtils | ||
import org.apache.spark.sql.types._ | ||
import org.apache.spark.unsafe.types.UTF8String | ||
|
||
case class DateFormat(left: Expression, right: Expression) | ||
extends BinaryExpression with ExpectsInputTypes { | ||
|
||
override def dataType: DataType = StringType | ||
|
||
override def expectedChildTypes: Seq[DataType] = Seq(TimestampType, StringType) | ||
|
||
override def foldable: Boolean = left.foldable && right.foldable | ||
|
||
override def nullable: Boolean = true | ||
|
||
override def eval(input: InternalRow): Any = { | ||
val valueLeft = left.eval(input) | ||
if (valueLeft == null) { | ||
null | ||
} else { | ||
val valueRight = right.eval(input) | ||
if (valueRight == null) { | ||
null | ||
} else { | ||
val sdf = new SimpleDateFormat(valueRight.asInstanceOf[UTF8String].toString) | ||
left.dataType match { | ||
case TimestampType => | ||
UTF8String.fromString(sdf.format(new Date(valueLeft.asInstanceOf[Long] / 10000))) | ||
case DateType => | ||
UTF8String.fromString(sdf.format(DateTimeUtils.toJavaDate(valueLeft.asInstanceOf[Int]))) | ||
case StringType => | ||
UTF8String.fromString( | ||
sdf.format(DateTimeUtils.stringToTime(valueLeft.asInstanceOf[UTF8String].toString))) | ||
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. just 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. NAVER - http://www.naver.com/sujkh@naver.com 님께 보내신 메일 <Re: [spark] [SPARK-8199][SPARK-8184][SPARK-8183][SPARK-8182][SPARK-8181][SPARK-8180][SPARK-8179][SPARK-8177][SPARK-8178][SQL] date functions (#6981)> 이 다음과 같은 이유로 전송 실패했습니다. 받는 사람이 회원님의 메일을 수신차단 하였습니다. |
||
} | ||
} | ||
} | ||
} | ||
|
||
override def toString: String = s"DateFormat($left, $right)" | ||
|
||
override protected def genCode(ctx: CodeGenContext, ev: GeneratedExpressionCode): String = { | ||
val sdf = "java.text.SimpleDateFormat" | ||
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.
|
||
val utf8 = "org.apache.spark.unsafe.types.UTF8String" | ||
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.
|
||
val dtUtils = "org.apache.spark.sql.catalyst.util.DateTimeUtils" | ||
|
||
val eval1 = left.gen(ctx) | ||
val eval2 = right.gen(ctx) | ||
|
||
val calc = left.dataType match { | ||
case TimestampType => | ||
s"""$utf8.fromString(sdf.format(new java.sql.Date(${eval1.primitive} / 10000)));""" | ||
case DateType => | ||
s"""$utf8.fromString( | ||
sdf.format($dtUtils.toJavaDate(${eval1.primitive})));""" | ||
case StringType => | ||
s""" | ||
$utf8.fromString(sdf.format(new java.sql.Date($dtUtils.stringToTime(${eval1.primitive}.toString()).getTime()))); | ||
""" | ||
} | ||
|
||
s""" | ||
${eval1.code} | ||
boolean ${ev.isNull} = ${eval1.isNull}; | ||
${ctx.javaType(dataType)} ${ev.primitive} = ${ctx.defaultValue(dataType)}; | ||
if (!${ev.isNull}) { | ||
${eval2.code} | ||
if (!${eval2.isNull}) { | ||
$sdf sdf = new $sdf(${eval2.primitive}.toString()); | ||
${ev.primitive} = $calc | ||
} else { | ||
${ev.isNull} = true; | ||
} | ||
} | ||
""" | ||
} | ||
} | ||
|
||
case class Year(child: Expression) extends UnaryExpression with ExpectsInputTypes { | ||
|
||
override def dataType: DataType = IntegerType | ||
|
||
override def expectedChildTypes: Seq[DataType] = Seq(DateType, StringType, TimestampType) | ||
|
||
override def foldable: Boolean = child.foldable | ||
|
||
override def nullable: Boolean = true | ||
|
||
override def eval(input: InternalRow): Any = { | ||
DateFormat(child, Literal("y")).eval(input) match { | ||
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. Is it okay to call Is there a way to call |
||
case null => null | ||
case x: UTF8String => x.toString.toInt | ||
} | ||
} | ||
|
||
} | ||
|
||
case class Month(child: Expression) extends UnaryExpression with ExpectsInputTypes { | ||
|
||
override def dataType: DataType = IntegerType | ||
|
||
override def expectedChildTypes: Seq[DataType] = Seq(DateType, StringType, TimestampType) | ||
|
||
override def foldable: Boolean = child.foldable | ||
|
||
override def nullable: Boolean = true | ||
|
||
override def eval(input: InternalRow): Any = { | ||
DateFormat(child, Literal("M")).eval(input) match { | ||
case null => null | ||
case x: UTF8String => x.toString.toInt | ||
} | ||
} | ||
} | ||
|
||
case class Day(child: Expression) extends UnaryExpression with ExpectsInputTypes { | ||
|
||
override def dataType: DataType = IntegerType | ||
|
||
override def expectedChildTypes: Seq[DataType] = Seq(DateType, StringType, TimestampType) | ||
|
||
override def foldable: Boolean = child.foldable | ||
|
||
override def nullable: Boolean = true | ||
|
||
override def eval(input: InternalRow): Any = { | ||
DateFormat(child, Literal("d")).eval(input) match { | ||
case null => null | ||
case x: UTF8String => x.toString.toInt | ||
} | ||
} | ||
|
||
} | ||
|
||
case class Hour(child: Expression) extends UnaryExpression with ExpectsInputTypes { | ||
|
||
override def dataType: DataType = IntegerType | ||
|
||
override def expectedChildTypes: Seq[DataType] = Seq(DateType, StringType, TimestampType) | ||
|
||
override def foldable: Boolean = child.foldable | ||
|
||
override def nullable: Boolean = true | ||
|
||
override def eval(input: InternalRow): Any = { | ||
DateFormat(child, Literal("H")).eval(input) match { | ||
case null => null | ||
case x: UTF8String => x.toString.toInt | ||
} | ||
} | ||
} | ||
|
||
case class Minute(child: Expression) extends UnaryExpression with ExpectsInputTypes { | ||
|
||
override def dataType: DataType = IntegerType | ||
|
||
override def expectedChildTypes: Seq[DataType] = Seq(DateType, StringType, TimestampType) | ||
|
||
override def foldable: Boolean = child.foldable | ||
|
||
override def nullable: Boolean = true | ||
|
||
override def eval(input: InternalRow): Any = { | ||
DateFormat(child, Literal("m")).eval(input) match { | ||
case null => null | ||
case x: UTF8String => x.toString.toInt | ||
} | ||
} | ||
} | ||
|
||
case class Second(child: Expression) extends UnaryExpression with ExpectsInputTypes { | ||
|
||
override def dataType: DataType = IntegerType | ||
|
||
override def expectedChildTypes: Seq[DataType] = Seq(DateType, StringType, TimestampType) | ||
|
||
override def foldable: Boolean = child.foldable | ||
|
||
override def nullable: Boolean = true | ||
|
||
override def eval(input: InternalRow): Any = { | ||
DateFormat(child, Literal("s")).eval(input) match { | ||
case null => null | ||
case x: UTF8String => x.toString.toInt | ||
} | ||
} | ||
} | ||
|
||
case class WeekOfYear(child: Expression) extends UnaryExpression with ExpectsInputTypes { | ||
|
||
override def dataType: DataType = IntegerType | ||
|
||
override def expectedChildTypes: Seq[DataType] = Seq(DateType, StringType, TimestampType) | ||
|
||
override def foldable: Boolean = child.foldable | ||
|
||
override def nullable: Boolean = true | ||
|
||
override def eval(input: InternalRow): Any = { | ||
DateFormat(child, Literal("w")).eval(input) match { | ||
case null => null | ||
case x: UTF8String => x.toString.toInt | ||
} | ||
} | ||
|
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.apache.spark.sql.catalyst.expressions | ||
|
||
import java.sql.{Timestamp, Date} | ||
import java.text.SimpleDateFormat | ||
|
||
import org.apache.spark.SparkFunSuite | ||
|
||
class DateTimeFunctionsSuite extends SparkFunSuite with ExpressionEvalHelper { | ||
|
||
val sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss") | ||
val d = new Date(sdf.parse("2015/04/08 13:10:15").getTime) | ||
val ts = new Timestamp(sdf.parse("2013/04/08 13:10:15").getTime) | ||
|
||
test("DateFormat") { | ||
checkEvaluation(DateFormat(Literal(d), Literal("y")), "2015") | ||
checkEvaluation(DateFormat(Literal(d.toString), Literal("y")), "2015") | ||
checkEvaluation(DateFormat(Literal(ts), Literal("y")), "2013") | ||
} | ||
|
||
test("Year") { | ||
checkEvaluation(Year(Literal(d)), 2015) | ||
checkEvaluation(Year(Literal(d.toString)), 2015) | ||
checkEvaluation(Year(Literal(ts)), 2013) | ||
} | ||
|
||
test("Month") { | ||
checkEvaluation(Month(Literal(d)), 4) | ||
checkEvaluation(Month(Literal(d.toString)), 4) | ||
checkEvaluation(Month(Literal(ts)), 4) | ||
} | ||
|
||
test("Day") { | ||
checkEvaluation(Day(Literal(d)), 8) | ||
checkEvaluation(Day(Literal(d.toString)), 8) | ||
checkEvaluation(Day(Literal(ts)), 8) | ||
} | ||
|
||
test("Hour") { | ||
checkEvaluation(Hour(Literal(d)), 0) | ||
checkEvaluation(Hour(Literal(d.toString)), 0) | ||
checkEvaluation(Hour(Literal(ts)), 13) | ||
} | ||
|
||
test("Minute") { | ||
checkEvaluation(Minute(Literal(d)), 0) | ||
checkEvaluation(Minute(Literal(d.toString)), 0) | ||
checkEvaluation(Minute(Literal(ts)), 10) | ||
} | ||
|
||
test("Seconds") { | ||
checkEvaluation(Second(Literal(d)), 0) | ||
checkEvaluation(Second(Literal(d.toString)), 0) | ||
checkEvaluation(Second(Literal(ts)), 15) | ||
} | ||
|
||
test("WeekOfYear") { | ||
checkEvaluation(WeekOfYear(Literal(d)), 15) | ||
checkEvaluation(WeekOfYear(Literal(d.toString)), 15) | ||
checkEvaluation(WeekOfYear(Literal(ts)), 15) | ||
} | ||
|
||
} |
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.
@rxin In Jira you mentioned there should be an alias. Can I just add
expression[Day]("day_of_month")
?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.
yes
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.
btw please sort the expressions alphabetically