@@ -276,9 +276,12 @@ case class DateFormatClass(left: Expression, right: Expression) extends BinaryEx
276276 * If the first parameter is a Date or Timestamp instead of String, we will ignore the
277277 * second parameter.
278278 */
279- case class UnixTimestamp (left : Expression , right : Expression )
279+ case class UnixTimestamp (timeExp : Expression , format : Expression )
280280 extends BinaryExpression with ExpectsInputTypes {
281281
282+ override def left : Expression = timeExp
283+ override def right : Expression = format
284+
282285 def this (time : Expression ) = {
283286 this (time, Literal (" yyyy-MM-dd HH:mm:ss" ))
284287 }
@@ -292,29 +295,66 @@ case class UnixTimestamp(left: Expression, right: Expression)
292295
293296 override def dataType : DataType = LongType
294297
295- lazy val constFormat : String = right.eval().asInstanceOf [UTF8String ].toString
296- override def nullSafeEval (time : Any , format : Any ): Any = {
297- left.dataType match {
298- case DateType =>
299- DateTimeUtils .daysToMillis(time.asInstanceOf [Int ]) / 1000L
300- case TimestampType =>
301- time.asInstanceOf [Long ] / 1000000L
302- case StringType if right.foldable =>
303- if (constFormat != null ) {
304- val sdf = new SimpleDateFormat (constFormat)
305- Try (sdf.parse(time.asInstanceOf [UTF8String ].toString).getTime / 1000L ).getOrElse(null )
306- } else {
307- null
308- }
309- case StringType =>
310- val formatString = format.asInstanceOf [UTF8String ].toString
311- val sdf = new SimpleDateFormat (formatString)
312- Try (sdf.parse(time.asInstanceOf [UTF8String ].toString).getTime / 1000L ).getOrElse(null )
298+ lazy val constFormat : UTF8String = right.eval().asInstanceOf [UTF8String ]
299+
300+ override def eval (input : InternalRow ): Any = {
301+ val t = left.eval(input)
302+ if (t == null ) {
303+ null
304+ } else {
305+ left.dataType match {
306+ case DateType =>
307+ DateTimeUtils .daysToMillis(t.asInstanceOf [Int ]) / 1000L
308+ case TimestampType =>
309+ t.asInstanceOf [Long ] / 1000000L
310+ case StringType if right.foldable =>
311+ if (constFormat != null ) {
312+ Try (new SimpleDateFormat (constFormat.toString).parse(
313+ t.asInstanceOf [UTF8String ].toString).getTime / 1000L ).getOrElse(null )
314+ } else {
315+ null
316+ }
317+ case StringType =>
318+ val f = format.eval(input)
319+ if (f == null ) {
320+ null
321+ } else {
322+ val formatString = f.asInstanceOf [UTF8String ].toString
323+ Try (new SimpleDateFormat (formatString).parse(
324+ t.asInstanceOf [UTF8String ].toString).getTime / 1000L ).getOrElse(null )
325+ }
326+ }
313327 }
314328 }
315329
316330 override def genCode (ctx : CodeGenContext , ev : GeneratedExpressionCode ): String = {
317331 left.dataType match {
332+ case StringType if right.foldable =>
333+ val sdf = classOf [SimpleDateFormat ].getName
334+ val fString = if (constFormat == null ) null else constFormat.toString
335+ val formatter = ctx.freshName(" formatter" )
336+ if (fString == null ) {
337+ s """
338+ boolean ${ev.isNull} = true;
339+ ${ctx.javaType(dataType)} ${ev.primitive} = ${ctx.defaultValue(dataType)};
340+ """
341+ } else {
342+ val eval1 = left.gen(ctx)
343+ s """
344+ ${eval1.code}
345+ boolean ${ev.isNull} = ${eval1.isNull};
346+ ${ctx.javaType(dataType)} ${ev.primitive} = ${ctx.defaultValue(dataType)};
347+ if (! ${ev.isNull}) {
348+ try {
349+ $sdf $formatter = new $sdf(" $fString");
350+ ${ev.primitive} =
351+ $formatter.parse( ${eval1.primitive}.toString()).getTime() / 1000L;
352+ } catch (java.lang.Throwable e) {
353+ ${ev.isNull} = true;
354+ }
355+ }
356+ """
357+ }
318358 case StringType =>
319359 val sdf = classOf [SimpleDateFormat ].getName
320360 nullSafeCodeGen(ctx, ev, (string, format) => {
@@ -328,14 +368,26 @@ case class UnixTimestamp(left: Expression, right: Expression)
328368 """
329369 })
330370 case TimestampType =>
331- defineCodeGen(ctx, ev, (timestamp, format) => {
332- s """ $timestamp / 1000000L """
333- })
371+ val eval1 = left.gen(ctx)
372+ s """
373+ ${eval1.code}
374+ boolean ${ev.isNull} = ${eval1.isNull};
375+ ${ctx.javaType(dataType)} ${ev.primitive} = ${ctx.defaultValue(dataType)};
376+ if (! ${ev.isNull}) {
377+ ${ev.primitive} = ${eval1.primitive} / 1000000L;
378+ }
379+ """
334380 case DateType =>
335381 val dtu = DateTimeUtils .getClass.getName.stripSuffix(" $" )
336- defineCodeGen(ctx, ev, (date, format) => {
337- s """ $dtu.daysToMillis( $date) / 1000L """
338- })
382+ val eval1 = left.gen(ctx)
383+ s """
384+ ${eval1.code}
385+ boolean ${ev.isNull} = ${eval1.isNull};
386+ ${ctx.javaType(dataType)} ${ev.primitive} = ${ctx.defaultValue(dataType)};
387+ if (! ${ev.isNull}) {
388+ ${ev.primitive} = $dtu.daysToMillis( ${eval1.primitive}) / 1000L;
389+ }
390+ """
339391 }
340392 }
341393}
@@ -345,9 +397,12 @@ case class UnixTimestamp(left: Expression, right: Expression)
345397 * representing the timestamp of that moment in the current system time zone in the given
346398 * format. If the format is missing, using format like "1970-01-01 00:00:00".
347399 */
348- case class FromUnixTime (left : Expression , right : Expression )
400+ case class FromUnixTime (sec : Expression , format : Expression )
349401 extends BinaryExpression with ImplicitCastInputTypes {
350402
403+ override def left : Expression = sec
404+ override def right : Expression = format
405+
351406 def this (unix : Expression ) = {
352407 this (unix, Literal (" yyyy-MM-dd HH:mm:ss" ))
353408 }
@@ -356,17 +411,68 @@ case class FromUnixTime(left: Expression, right: Expression)
356411
357412 override def inputTypes : Seq [AbstractDataType ] = Seq (LongType , StringType )
358413
359- override protected def nullSafeEval (time : Any , format : Any ): Any = {
360- val sdf = new SimpleDateFormat (format.toString)
361- UTF8String .fromString(sdf.format(new java.util.Date (time.asInstanceOf [Long ] * 1000L )))
414+ lazy val constFormat : UTF8String = right.eval().asInstanceOf [UTF8String ]
415+
416+ override def eval (input : InternalRow ): Any = {
417+ val time = left.eval(input)
418+ if (time == null ) {
419+ null
420+ } else {
421+ if (format.foldable) {
422+ if (constFormat == null ) {
423+ null
424+ } else {
425+ Try (UTF8String .fromString(new SimpleDateFormat (constFormat.toString).format(
426+ new java.util.Date (time.asInstanceOf [Long ] * 1000L )))).getOrElse(null )
427+ }
428+ } else {
429+ val f = format.eval(input)
430+ if (f == null ) {
431+ null
432+ } else {
433+ Try (UTF8String .fromString(new SimpleDateFormat (
434+ f.asInstanceOf [UTF8String ].toString).format(new java.util.Date (
435+ time.asInstanceOf [Long ] * 1000L )))).getOrElse(null )
436+ }
437+ }
438+ }
362439 }
363440
364441 override def genCode (ctx : CodeGenContext , ev : GeneratedExpressionCode ): String = {
365442 val sdf = classOf [SimpleDateFormat ].getName
366- defineCodeGen(ctx, ev, (seconds, format) => {
367- s """ UTF8String.fromString((new $sdf( $format.toString())).format(
368- new java.sql.Timestamp( $seconds * 1000L))) """ .stripMargin
369- })
443+ if (format.foldable) {
444+ if (constFormat == null ) {
445+ s """
446+ boolean ${ev.isNull} = true;
447+ ${ctx.javaType(dataType)} ${ev.primitive} = ${ctx.defaultValue(dataType)};
448+ """
449+ } else {
450+ val t = left.gen(ctx)
451+ s """
452+ ${t.code}
453+ boolean ${ev.isNull} = ${t.isNull};
454+ ${ctx.javaType(dataType)} ${ev.primitive} = ${ctx.defaultValue(dataType)};
455+ if (! ${ev.isNull}) {
456+ try {
457+ ${ev.primitive} = UTF8String.fromString(new $sdf(" ${constFormat.toString}").format(
458+ new java.sql.Timestamp( ${t.primitive} * 1000L)));
459+ } catch (java.lang.Throwable e) {
460+ ${ev.isNull} = true;
461+ }
462+ }
463+ """
464+ }
465+ } else {
466+ nullSafeCodeGen(ctx, ev, (seconds, f) => {
467+ s """
468+ try {
469+ ${ev.primitive} = UTF8String.fromString((new $sdf( $f.toString())).format(
470+ new java.sql.Timestamp( $seconds * 1000L)));
471+ } catch (java.lang.Throwable e) {
472+ ${ev.isNull} = true;
473+ } """ .stripMargin
474+ })
475+ }
370476 }
371477
372478}
0 commit comments