Для этого в Spark нет встроенной функции, но это можно сделать без UDF. Вы можете просто рассчитать его, используя операции деления и по модулю, чтобы получить разные части (дни, часы, ...), и объединить, чтобы получить желаемое форматирование.
Для Spark 2.4+ вы можете использовать более высокий порядок функция zip_with
и array_join
. Сначала создайте столбец parts
, который содержит количество дней, часов, минут и секунд из столбца Seconds
. Затем зафиксируйте его с помощью буквального массива единиц array('d', 'hr', 'min', 'sec')
, чтобы объединить каждую деталь с ее единицей и, наконец, объединить все элементы с разделителем запятыми.
duration_parts = [(86400, 7), (3600, 24), (60, 60), (1, 60)]
exp = "zip_with(parts, array('d', 'hr', 'min', 'sec'), (x, y) -> IF(x > 0, concat(x, y), null))"
df.withColumn("parts", array(*[(floor(col("Seconds") / d)) % m for d, m in duration_parts]))\
.withColumn("duration", array_join(expr(exp), ", "))\
.drop("parts")\
.show(truncate=False)
#+--------------------------------------------+-------+---------------------+
#|Name |Seconds|duration |
#+--------------------------------------------+-------+---------------------+
#|Analizar mapa de comparacion de presupuestos|1209 |20min, 9sec |
#|Crear mapa de comparacion de presupuestos |12155 |3hr, 22min, 35sec |
#|Entregar servicios de bienes |91049 |1d, 1hr, 17min, 29sec|
#+--------------------------------------------+-------+---------------------+
Другой способ - использовать concat
и добавить выражение when
, если вы не хотите, чтобы части были равны 0:
df.withColumn("duration", concat(
floor(col("Seconds") / 86400), lit("d, "),
floor(col("Seconds") % 86400 / 3600), lit("hr, "),
floor((col("Seconds") % 86400) % 3600 / 60), lit("min, "),
floor(((col("Seconds") % 86400) % 3600) % 60), lit("sec "),
)).show(truncate=False)