Pyspark:如何将带小数的小时数转换为hh:mm

时间:2020-05-27 06:36:24

标签: apache-spark-sql pyspark-dataframes

我有以下示例数据框,其中包含对象ID和总时数。十进制值将分钟转换为一小时的一部分。

# +----+----+--------+
# |col1|total_hours  |
# +----+-------------+
# |obj1| 48387.837   |
# |obj2| 45570.0201  |
# |obj3| 39339.669   |
# |obj4| 37673.235   |
# |obj5| 3576        |
# |obj6| 15287.9999  |
# +----+-------------+

我想以小时:分钟格式显示总时数。

所需的输出

# +----+----+--------+
# |col1|total_hours  |
# +----+-------------+
# |obj1| 48387:50    |
# |obj2| 45570:01    |
# |obj3| 39339:40    |
# |obj4| 37673:14    |
# |obj5| 3576:00     |
# |obj6| 15288:00    |
# +----+-------------+

在SQL中,我可以使用以下功能:

  hr = trunc(col1);
  minutes = round(hr -trunc(hr)* 0.6, 2);

  hours_minutes= trim(replace(to_char(hr + minutes ,'999999999990.90'),'.',':'));

如何在Pyspark中完成

2 个答案:

答案 0 :(得分:3)

鉴于简单的格式无法使用,因此这将需要字符串操作。 这是获取数字的模数,将其乘以60,同时格式化两者,然后进行级联:

df.withColumn('total_hours_str', 
   f.concat(f.regexp_replace(f.format_number(f.floor(df.total_hours), 0), ',', ''), 
            f.lit(':'),  
            f.lpad(f.format_number(df.total_hours%1*60, 0), 2, '0'))).show()

输出:

+----+-----------+---------------+
|col1|total_hours|total_hours_str|
+----+-----------+---------------+
|obj1|  48387.837|       48387:50|
|obj2| 45570.0201|       45570:01|
|obj3|  39339.669|       39339:40|
|obj4|  37673.235|       37673:14|
|obj5|     3576.0|        3576:00|
+----+-----------+---------------+

编辑:
由于小数部分的值最终会四舍五入为整整一个小时,因此建议您在处理该列之前先四舍五入:

df.withColumn('rounded_total_hours', f.round(df['total_hours'],2))\
  .withColumn('total_hours_str', 
      f.concat(f.regexp_replace(f.format_number(f.floor(f.col('rounded_total_hours')), 0), ',', ''), 
               f.lit(':'),  
               f.lpad(f.format_number(f.col('rounded_total_hours')%1*60, 0), 2, '0'))).show()

哪个会产生:

+----+-----------+-------------------+---------------+
|col1|total_hours|rounded_total_hours|total_hours_str|
+----+-----------+-------------------+---------------+
|obj1|  48387.837|           48387.84|       48387:50|
|obj2| 45570.0201|           45570.02|       45570:01|
|obj3|  39339.669|           39339.67|       39339:40|
|obj4|  37673.235|           37673.24|       37673:14|
|obj5|     3576.0|             3576.0|        3576:00|
|obj6| 15287.9999|            15288.0|       15288:00|
+----+-----------+-------------------+---------------+

答案 1 :(得分:0)

如果所需的数据类型是字符串,则可以使用字符串concat完成。

步骤:

  1. 通过创建将total_hours强制转换为 IntegerType()
  2. 通过从total_hours中减去该值来提取小时数。
  3. 将该小数乘以60得到分钟数
  4. 使用:分隔符广播到字符串和concat。

代码:

from pyspark.sql.types import IntegerType
from pyspark.sql.functions import concat_ws

df = df.withColumn('total_hour_int', df['total_hours'].cast(IntegerType())
df = df.withColumn('hours_remainder', df['total_hours']-df['total_hour_int'])
df = df.withColumn('minutes', df['hours_remainder']*60)
df = df.withColumn('minutes_full', df['minutes'].cast(IntegerType())
df = df.withColumn('total_hours_string', concat_ws(':', df['total_hour_int'], df['minutes_full'])
相关问题