Как конвертировать строковую дату в желаемый формат даты в pyspark

#date #pyspark #apache-spark-sql #date-format

Вопрос:

У меня есть колонка с датами, где есть несколько записей mm-dd-yy, dd-mm-yy, yy-mm-dd .

 df = sc.parallelize([['12-21-2021'],
                     ['04-23-2021'],
                     ['22-03-24'],
                     ['12/03/20']]).toDF(["Date"])

df.show()
 ---------- 
|      Date|
 ---------- 
|12-21-2021|
|04-23-2021|
|  22-03-24|
|  12/03/20|
 ---------- 
 

Теперь я хочу преобразовать строку в формат даты. Но, как вы можете видеть, результаты для последних двух записей, хотя и получили правильный формат, но столбец результатов принимает неправильный формат. Как мне сделать так, чтобы он принял правильный формат?

  from pyspark.sql import functions as F
    from pyspark.sql.functions import col, unix_timestamp, to_date
    from pyspark.sql.functions import date_format
    spark.sql("set spark.sql.legacy.timeParserPolicy=LEGACY")
    sdf = df.withColumn("yyyy/MM/dd", F.to_date(F.unix_timestamp(df.Date,'yyyy/MM/dd').cast('timestamp'))) 
      .withColumn("yyyy-MM-dd", F.to_date(F.unix_timestamp(df.Date,'yyyy-MM-dd').cast('timestamp'))) 
      .withColumn("MM/dd/yyyy", F.to_date(F.unix_timestamp(df.Date,'MM/dd/yyyy').cast('timestamp'))) 
      .withColumn("MM-dd-yyyy", F.to_date(F.unix_timestamp(df.Date,'MM-dd-yyyy').cast('timestamp'))) 
      .withColumn("dd/MM/yy", F.to_date(F.unix_timestamp(df.Date,'dd/MM/yy').cast('timestamp'))) 
      .withColumn("dd-MM-yy", F.to_date(F.unix_timestamp(df.Date,'dd-MM-yy').cast('timestamp'))) 
      .withColumn("result", F.coalesce("yyyy/MM/dd", "yyyy-MM-dd", "MM/dd/yyyy", "MM-dd-yyyy",'dd/MM/yy','dd-MM-yy')) 
    display(sdf)

Date      yyyy/MM/dd    yyyy-MM-dd  MM/dd/yyyy  MM-dd-yyyy  dd/MM/yy    dd-MM-yy     result
12-21-2021  null          null        null      2021-12-21   null        null        2021-12-21
04-23-2021  null          null        null      2021-04-23   null        null        2021-04-23
22-03-24    null        0022-03-24    null       null        null     2024-03-22     0022-03-24
12/03/20    0012-03-20    null     0020-12-03    null      2020-03-12    null        0012-03-20
 

Комментарии:

1. Изменить .withColumn("result", F.coalesce("yyyy/MM/dd", "yyyy-MM-dd", "MM/dd/yyyy", "MM-dd-yyyy",'dd/MM/yy','dd-MM-yy')) на .withColumn("result", F.coalesce('dd/MM/yy','dd-MM-yy',"yyyy/MM/dd", "yyyy-MM-dd", "MM/dd/yyyy", "MM-dd-yyyy"))

2. @User12345 Я попробовал с помощью coalsece, но это не сработало

Ответ №1:

Я протестировал решение, которое работает для меня, надеюсь, оно сработает и для вас.
Некоторые моменты : замена » / » на » — » позволит иметь только 2 разных варианта; но все равно будут неоднозначные значения, поэтому вам нужно будет выбрать заказ для вашего объединения (я не вижу способа определить, является ли дата в формате dd/ММ или MM/dd с некоторыми цифрами). Интересно, не возникнут ли ваши проблемы из-за того, что вы используете cast()
Я позволяю промежуточным форматам видеть конкретный результат, но в моем случае объединение работает.

 from pyspark.sql import functions as F, types as T

def TEST_convert_dates(ds_with_dates):
    spark.sql("set spark.sql.legacy.timeParserPolicy=LEGACY")
    df = ds_with_dates
        .withColumn('Date', F.regexp_replace('Date', '/', '-')) 
        .withColumn('Date_format1', F.to_date(F.col('Date'), 'MM-dd-yy').cast(T.DateType())) 
        .withColumn('Date_format2', F.to_date(F.col('Date'), 'dd-MM-yy').cast(T.DateType())) 
        .withColumn('Date_formated', F.coalesce(
            F.to_date(F.col('Date'), 'MM-dd-yy').cast(T.DateType()),
            F.to_date(F.col('Date'), 'dd-MM-yy').cast(T.DateType())
        ))
    return df
 

Вот результат:

 Date           format 1       format 2         Result  
12-21-2021     2021-12-21        null        2021-12-21  
04-23-2021     2021-04-23        null        2021-04-23  
22-03-24         null        2024-03-22      2024-03-22  
12/03/20       2020-12-03    2020-03-12      2020-12-03