@@ -35,7 +35,7 @@ import org.apache.spark.sql.catalyst.util.TimeFormatter
3535import org .apache .spark .sql .catalyst .util .TypeUtils .ordinalNumber
3636import org .apache .spark .sql .errors .{QueryCompilationErrors , QueryExecutionErrors }
3737import org .apache .spark .sql .internal .types .StringTypeWithCollation
38- import org .apache .spark .sql .types .{AbstractDataType , AnyTimeType , ByteType , DataType , DayTimeIntervalType , Decimal , DecimalType , DoubleType , FloatType , IntegerType , IntegralType , LongType , NumericType , ObjectType , TimeType }
38+ import org .apache .spark .sql .types .{AbstractDataType , AnyTimeType , ByteType , DataType , DayTimeIntervalType , Decimal , DecimalType , DoubleType , FloatType , IntegerType , IntegralType , LongType , NumericType , ObjectType , StringType , TimeType }
3939import org .apache .spark .sql .types .DayTimeIntervalType .{HOUR , SECOND }
4040import org .apache .spark .unsafe .types .UTF8String
4141
@@ -1036,3 +1036,82 @@ case class TimeToMicros(child: Expression)
10361036 override protected def withNewChildInternal (newChild : Expression ): TimeToMicros =
10371037 copy(child = newChild)
10381038}
1039+
1040+ // scalastyle:off line.size.limit
1041+ @ ExpressionDescription (
1042+ usage = " _FUNC_(time, format) - Converts a time to a value of string in the format specified by the date format given by the second argument." ,
1043+ arguments = """
1044+ Arguments:
1045+ * time - A time value to be converted to string.
1046+ * format - Time format pattern to follow. See <a href="https://spark.apache.org/docs/latest/sql-ref-datetime-pattern.html">Datetime Patterns</a> for valid
1047+ time format patterns. Note: Only time-related patterns (H, h, m, s, S, a) are meaningful for TIME values.
1048+ """ ,
1049+ examples = """
1050+ Examples:
1051+ > SELECT _FUNC_(TIME'14:30:45', 'HH:mm:ss');
1052+ 14:30:45
1053+ > SELECT _FUNC_(TIME'14:30:45', 'hh:mm:ss a');
1054+ 02:30:45 PM
1055+ > SELECT _FUNC_(TIME'14:30:45.123456', 'HH:mm:ss.SSSSSS');
1056+ 14:30:45.123456
1057+ > SELECT _FUNC_(TIME'09:05:00', 'h:mm a');
1058+ 9:05 AM
1059+ """ ,
1060+ group = " datetime_funcs" ,
1061+ since = " 4.2.0" )
1062+ // scalastyle:on line.size.limit
1063+ case class TimeFormat (left : Expression , right : Expression )
1064+ extends BinaryExpression
1065+ with ImplicitCastInputTypes {
1066+
1067+ override def nullIntolerant : Boolean = true
1068+
1069+ override def inputTypes : Seq [AbstractDataType ] =
1070+ Seq (AnyTimeType , StringTypeWithCollation (supportsTrimCollation = true ))
1071+
1072+ override def dataType : DataType = StringType
1073+
1074+ // Cache the formatter if the format string is a foldable expression
1075+ @ transient private lazy val formatterOption : Option [TimeFormatter ] =
1076+ if (right.foldable) {
1077+ Option (right.eval()).map { format =>
1078+ TimeFormatter (format.toString, TimeFormatter .defaultLocale, isParsing = false )
1079+ }
1080+ } else {
1081+ None
1082+ }
1083+
1084+ override protected def nullSafeEval (time : Any , format : Any ): Any = {
1085+ val nanos = time.asInstanceOf [Long ]
1086+ val formatter = formatterOption.getOrElse {
1087+ TimeFormatter (format.toString, TimeFormatter .defaultLocale, isParsing = false )
1088+ }
1089+ UTF8String .fromString(formatter.format(nanos))
1090+ }
1091+
1092+ override def doGenCode (ctx : CodegenContext , ev : ExprCode ): ExprCode = {
1093+ formatterOption.map { tf =>
1094+ val timeFormatter = ctx.addReferenceObj(" timeFormatter" , tf)
1095+ defineCodeGen(ctx, ev, (time, _) => {
1096+ s """ UTF8String.fromString( $timeFormatter.format( $time)) """
1097+ })
1098+ }.getOrElse {
1099+ val tfClass = TimeFormatter .getClass.getName.stripSuffix(" $" )
1100+ val locale = ctx.addReferenceObj(
1101+ " locale" , TimeFormatter .defaultLocale, classOf [Locale ].getName)
1102+ defineCodeGen(ctx, ev, (time, format) => {
1103+ s """ |UTF8String.fromString( $tfClass$$ .MODULE $$ .apply(
1104+ | $format.toString(),
1105+ | $locale,
1106+ | false)
1107+ |.format( $time)) """ .stripMargin
1108+ })
1109+ }
1110+ }
1111+
1112+ override def prettyName : String = " time_format"
1113+
1114+ override protected def withNewChildrenInternal (
1115+ newLeft : Expression , newRight : Expression ): TimeFormat =
1116+ copy(left = newLeft, right = newRight)
1117+ }
0 commit comments