1+ /*
2+ * Licensed to the Apache Software Foundation (ASF) under one or more
3+ * contributor license agreements. See the NOTICE file distributed with
4+ * this work for additional information regarding copyright ownership.
5+ * The ASF licenses this file to You under the Apache License, Version 2.0
6+ * (the "License"); you may not use this file except in compliance with
7+ * the License. You may obtain a copy of the License at
8+ *
9+ * http://www.apache.org/licenses/LICENSE-2.0
10+ *
11+ * Unless required by applicable law or agreed to in writing, software
12+ * distributed under the License is distributed on an "AS IS" BASIS,
13+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+ * See the License for the specific language governing permissions and
15+ * limitations under the License.
16+ */
17+
18+ package org .apache .spark .sql .catalyst .expressions
19+
20+ import java .sql .Date
21+ import java .text .SimpleDateFormat
22+
23+ import org .apache .spark .sql .catalyst .expressions .codegen .{GeneratedExpressionCode , CodeGenContext }
24+ import org .apache .spark .sql .catalyst .util .DateTimeUtils
25+ import org .apache .spark .sql .types ._
26+ import org .apache .spark .unsafe .types .UTF8String
27+
28+ case class DateFormat (left : Expression , right : Expression )
29+ extends BinaryExpression with ExpectsInputTypes {
30+
31+ override def dataType : DataType = StringType
32+
33+ override def expectedChildTypes : Seq [DataType ] = Seq (TimestampType , StringType )
34+
35+ override def foldable : Boolean = left.foldable && right.foldable
36+
37+ override def nullable : Boolean = true
38+
39+ override def eval (input : InternalRow ): Any = {
40+ val valueLeft = left.eval(input)
41+ if (valueLeft == null ) {
42+ null
43+ } else {
44+ val valueRight = right.eval(input)
45+ if (valueRight == null ) {
46+ null
47+ } else {
48+ val sdf = new SimpleDateFormat (valueRight.asInstanceOf [UTF8String ].toString)
49+ left.dataType match {
50+ case TimestampType =>
51+ UTF8String .fromString(sdf.format(new Date (valueLeft.asInstanceOf [Long ] / 10000 )))
52+ case DateType =>
53+ UTF8String .fromString(sdf.format(DateTimeUtils .toJavaDate(valueLeft.asInstanceOf [Int ])))
54+ case StringType =>
55+ UTF8String .fromString(
56+ sdf.format(DateTimeUtils .stringToTime(valueLeft.asInstanceOf [UTF8String ].toString)))
57+ }
58+ }
59+ }
60+ }
61+
62+ override def toString : String = s " DateFormat( $left, $right) "
63+
64+ override protected def genCode (ctx : CodeGenContext , ev : GeneratedExpressionCode ): String = {
65+ val sdf = " java.text.SimpleDateFormat"
66+ val utf8 = " org.apache.spark.unsafe.types.UTF8String"
67+ val dtUtils = " org.apache.spark.sql.catalyst.util.DateTimeUtils"
68+
69+ val eval1 = left.gen(ctx)
70+ val eval2 = right.gen(ctx)
71+
72+ val calc = left.dataType match {
73+ case TimestampType =>
74+ s """ $utf8.fromString(sdf.format(new java.sql.Date( ${eval1.primitive} / 10000))); """
75+ case DateType =>
76+ s """ $utf8.fromString(
77+ sdf.format( $dtUtils.toJavaDate( ${eval1.primitive}))); """
78+ case StringType =>
79+ s """
80+ $utf8.fromString(sdf.format(new java.sql.Date( $dtUtils.stringToTime( ${eval1.primitive}.toString()).getTime())));
81+ """
82+ }
83+
84+ s """
85+ ${eval1.code}
86+ boolean ${ev.isNull} = ${eval1.isNull};
87+ ${ctx.javaType(dataType)} ${ev.primitive} = ${ctx.defaultValue(dataType)};
88+ if (! ${ev.isNull}) {
89+ ${eval2.code}
90+ if (! ${eval2.isNull}) {
91+ $sdf sdf = new $sdf( ${eval2.primitive}.toString());
92+ ${ev.primitive} = $calc
93+ } else {
94+ ${ev.isNull} = true;
95+ }
96+ }
97+ """
98+ }
99+ }
100+
101+ case class Year (child : Expression ) extends UnaryExpression with ExpectsInputTypes {
102+
103+ override def dataType : DataType = IntegerType
104+
105+ override def expectedChildTypes : Seq [DataType ] = Seq (DateType , StringType , TimestampType )
106+
107+ override def foldable : Boolean = child.foldable
108+
109+ override def nullable : Boolean = true
110+
111+ override def eval (input : InternalRow ): Any = {
112+ DateFormat (child, Literal (" y" )).eval(input) match {
113+ case null => null
114+ case x : UTF8String => x.toString.toInt
115+ }
116+ }
117+
118+ }
119+
120+ case class Month (child : Expression ) extends UnaryExpression with ExpectsInputTypes {
121+
122+ override def dataType : DataType = IntegerType
123+
124+ override def expectedChildTypes : Seq [DataType ] = Seq (DateType , StringType , TimestampType )
125+
126+ override def foldable : Boolean = child.foldable
127+
128+ override def nullable : Boolean = true
129+
130+ override def eval (input : InternalRow ): Any = {
131+ DateFormat (child, Literal (" M" )).eval(input) match {
132+ case null => null
133+ case x : UTF8String => x.toString.toInt
134+ }
135+ }
136+ }
137+
138+ case class Day (child : Expression ) extends UnaryExpression with ExpectsInputTypes {
139+
140+ override def dataType : DataType = IntegerType
141+
142+ override def expectedChildTypes : Seq [DataType ] = Seq (DateType , StringType , TimestampType )
143+
144+ override def foldable : Boolean = child.foldable
145+
146+ override def nullable : Boolean = true
147+
148+ override def eval (input : InternalRow ): Any = {
149+ DateFormat (child, Literal (" d" )).eval(input) match {
150+ case null => null
151+ case x : UTF8String => x.toString.toInt
152+ }
153+ }
154+
155+ }
156+
157+ case class Hour (child : Expression ) extends UnaryExpression with ExpectsInputTypes {
158+
159+ override def dataType : DataType = IntegerType
160+
161+ override def expectedChildTypes : Seq [DataType ] = Seq (DateType , StringType , TimestampType )
162+
163+ override def foldable : Boolean = child.foldable
164+
165+ override def nullable : Boolean = true
166+
167+ override def eval (input : InternalRow ): Any = {
168+ DateFormat (child, Literal (" H" )).eval(input) match {
169+ case null => null
170+ case x : UTF8String => x.toString.toInt
171+ }
172+ }
173+ }
174+
175+ case class Minute (child : Expression ) extends UnaryExpression with ExpectsInputTypes {
176+
177+ override def dataType : DataType = IntegerType
178+
179+ override def expectedChildTypes : Seq [DataType ] = Seq (DateType , StringType , TimestampType )
180+
181+ override def foldable : Boolean = child.foldable
182+
183+ override def nullable : Boolean = true
184+
185+ override def eval (input : InternalRow ): Any = {
186+ DateFormat (child, Literal (" m" )).eval(input) match {
187+ case null => null
188+ case x : UTF8String => x.toString.toInt
189+ }
190+ }
191+ }
192+
193+ case class Second (child : Expression ) extends UnaryExpression with ExpectsInputTypes {
194+
195+ override def dataType : DataType = IntegerType
196+
197+ override def expectedChildTypes : Seq [DataType ] = Seq (DateType , StringType , TimestampType )
198+
199+ override def foldable : Boolean = child.foldable
200+
201+ override def nullable : Boolean = true
202+
203+ override def eval (input : InternalRow ): Any = {
204+ DateFormat (child, Literal (" s" )).eval(input) match {
205+ case null => null
206+ case x : UTF8String => x.toString.toInt
207+ }
208+ }
209+ }
210+
211+ case class WeekOfYear (child : Expression ) extends UnaryExpression with ExpectsInputTypes {
212+
213+ override def dataType : DataType = IntegerType
214+
215+ override def expectedChildTypes : Seq [DataType ] = Seq (DateType , StringType , TimestampType )
216+
217+ override def foldable : Boolean = child.foldable
218+
219+ override def nullable : Boolean = true
220+
221+ override def eval (input : InternalRow ): Any = {
222+ DateFormat (child, Literal (" w" )).eval(input) match {
223+ case null => null
224+ case x : UTF8String => x.toString.toInt
225+ }
226+ }
227+
228+
229+ }
0 commit comments