Как преобразовать строку в дату в столбце с разными форматами даты - PullRequest
0 голосов
/ 14 мая 2018

У меня есть столбец в моем Spark DataFrame, open_date со значениями строкового типа, как показано ниже, которые представляют собой два различных формата yyyymmdd и yyyymm

+---------+
|open_date|
+---------+
| 19500102| 
|   195001| 
+---------+

, и мой ожидаемый результат равен

+----------+
| open_date|
+----------+
|1950-01-02|
|1950-01-01|
+----------+

Я попытался преобразовать эту строку в формат даты, используя pyspark.sql.functions.substr, pyspark.sql.functions.split и pyspark.sql.functions.regex_extract.Имея ограниченные знания об этом, ни один из них не преуспел.

Как преобразовать строку в тип даты в столбце с различными форматами?

Ответы [ 2 ]

0 голосов
/ 14 мая 2018

Обновление 2019-06-24

Вы можете попробовать каждый из допустимых форматов даты и использовать pyspark.sql.functions.coalesce, чтобы вернуть первый ненулевой результат.

import pyspark.sql.functions as f

def date_from_string(date_str, fmt):
    try:
        # For spark version 2.2 and above, to_date takes in a second argument
        return f.to_date(date_str, fmt).cast("date")
    except TypeError:
        # For spark version 2.1 and below, you'll have to do it this way
        return f.from_unixtime(f.unix_timestamp(date_str, fmt)).cast("date")

possible_date_formats = ["yyyyMMdd", "yyyyMM"]

df = df.withColumn(
    "open_date",
    f.coalesce(*[date_from_string("open_date", fmt) for fmt in possible_date_formats])
)

df.show()
#+----------+
#| open_date|
#+----------+
#|1950-01-02|
#|1950-01-01|
#+----------+

Оригинальный ответ

Если вы гарантированно будете иметь только строки длиной 6 или 8 символов, простейшей вещью будетдобавьте "01" в конец коротких строк, чтобы указать первое число месяца.

Вот пример использования pyspark.sql.functions.length() и pyspark.sql.functions.concat():

import pyspark.sql.functions as f

df = df.withColumn(
    'open_date',
    f.when(
        f.length(f.col('open_date')) == 6,
        f.concat(f.col('open_date'), "01")
    ).otherwise(f.col('open_date'))
)
df.show()
#+---------+
#|open_date|
#+---------+
#| 19500102| 
#| 19500101| 
#+---------+

Затем используйте методы, описанные в thisсообщение (перефразировано ниже) для преобразования в дату.

Для Spark 2.1 и ниже :

df = df.withColumn('open_date', f.from_unixtime(f.unix_timestamp('open_date', 'yyyyMMdd')))

Для Spark 2.2 +

df = df.withColumn('open_date', f.to_date('open_date', 'yyyyMMdd'))
0 голосов
/ 14 мая 2018

Вы можете требовать наличия yyyy и mm, но сделать dd необязательным.Разбейте каждого на свою группу захвата: filter, если отсутствует dd, затем join, используя '-' разделители.

>>> import re
>>> s = '19500102 195001'
>>> ['-'.join(filter(None, i)) for i in re.findall(r'(\d{4})(\d{2})(\d{2})?', s)]
['1950-01-02', '1950-01']
...