webentwicklung-frage-antwort-db.com.de

Konvertieren Sie das Datum von String in das Datumsformat in Dataframes

Ich versuche, eine Spalte im String-Format in das Date-Format zu konvertieren, indem Sie die to_date-Funktion verwenden, deren Nullwerte jedoch zurückgegeben werden.

df.createOrReplaceTempView("incidents")
spark.sql("select Date from incidents").show()

+----------+
|      Date|
+----------+
|08/26/2016|
|08/26/2016|
|08/26/2016|
|06/14/2016|

spark.sql("select to_date(Date) from incidents").show()

+---------------------------+
|to_date(CAST(Date AS DATE))|
 +---------------------------+
|                       null|
|                       null|
|                       null|
|                       null|

Die Date-Spalte enthält das String-Format:

 |-- Date: string (nullable = true)
24
Ishan Kumar

Verwenden Sie to_date mit Java SimpleDateFormat .

TO_DATE(CAST(UNIX_TIMESTAMP(date, 'MM/dd/yyyy') AS TIMESTAMP))

Beispiel:

spark.sql("""
  SELECT TO_DATE(CAST(UNIX_TIMESTAMP('08/26/2016', 'MM/dd/yyyy') AS TIMESTAMP)) AS newdate"""
).show()

+----------+
|        dt|
+----------+
|2016-08-26|
+----------+
28
user6022341

Ich habe das gleiche Problem ohne die temporäre Tabelle/Ansicht und mit Dataframe-Funktionen gelöst.

Natürlich habe ich festgestellt, dass nur ein Format mit dieser Lösung funktioniert, und das ist yyyy-MM-DD.

Zum Beispiel:

val df = sc.parallelize(Seq("2016-08-26")).toDF("Id")
val df2 = df.withColumn("Timestamp", (col("Id").cast("timestamp")))
val df3 = df2.withColumn("Date", (col("Id").cast("date")))

df3.printSchema

root
 |-- Id: string (nullable = true)
 |-- Timestamp: timestamp (nullable = true)
 |-- Date: date (nullable = true)

df3.show

+----------+--------------------+----------+
|        Id|           Timestamp|      Date|
+----------+--------------------+----------+
|2016-08-26|2016-08-26 00:00:...|2016-08-26|
+----------+--------------------+----------+

Der Zeitstempel hat natürlich 00:00:00.0 als Zeitwert.

25
V. Samma

Da Ihr Hauptziel darin bestand, den Typ einer Spalte in einem DataFrame von String in Timestamp zu konvertieren, denke ich, dass dieser Ansatz besser wäre.

import org.Apache.spark.sql.functions.{to_date, to_timestamp}
val modifiedDF = DF.withColumn("Date", to_date($"Date", "MM/dd/yyyy"))

Sie können auch to_timestamp (ich denke, dass es von Spark 2.x verfügbar ist) verwenden, wenn Sie einen feinkörnigen Zeitstempel benötigen.

12

sie können diese Abfrage auch machen ...!

sqlContext.sql("""
select from_unixtime(unix_timestamp('08/26/2016', 'MM/dd/yyyy'), 'yyyy:MM:dd') as new_format
""").show()

 enter image description here

5
Curycu

Sie können auch das Datumsformat übergeben

df.withColumn("Date",to_date(unix_timestamp(df.col("your_date_column"), "your_date_format").cast("timestamp")))

Zum Beispiel

import org.Apache.spark.sql.functions._
val df = sc.parallelize(Seq("06 Jul 2018")).toDF("dateCol")
df.withColumn("Date",to_date(unix_timestamp(df.col("dateCol"), "dd MMM yyyy").cast("timestamp")))
1
Amit Dubey

dateID ist die Spalte int enthält das Datum im Int-Format

spark.sql("SELECT from_unixtime(unix_timestamp(cast(dateid as varchar(10)), 'yyyymmdd'), 'yyyy-mm-dd') from XYZ").show(50, false)
1
Rajiv Singh

Die oben von Sai Kiriti Badam vorgeschlagene Lösung hat für mich funktioniert. 

Ich verwende Azure Databricks zum Lesen von Daten, die von einem EventHub erfasst wurden. Diese enthält eine Zeichenfolgenspalte namens EnqueuedTimeUtc mit dem folgenden Format ...

07.12.2014 12:54:13 PM

Ich benutze ein Python-Notebook und verwende Folgendes:.

import pyspark.sql.functions as func

sports_messages = sports_df.withColumn("EnqueuedTimestamp", func.to_timestamp("EnqueuedTimeUtc", "MM/dd/yyyy hh:mm:ss aaa"))

... um eine neue Spalte EnqueuedTimestamp vom Typ "Zeitstempel" mit Daten im folgenden Format zu erstellen ...

2018-12-07 12:54:13

0
Simon Peacock

Ich persönlich habe einige Fehler bei der Verwendung von unix_timestamp-basierten Datumskonvertierungen von TT-MMM-JJJJ-Format in JJJJ-MM-TT unter Verwendung von spark 1.6) festgestellt, diese können sich jedoch auf neuere Versionen erstrecken Erklären Sie, wie Sie das Problem mit Java.time lösen können, das in allen Versionen von spark funktionieren sollte:

Ich habe dabei Fehler gesehen:

from_unixtime(unix_timestamp(StockMarketClosingDate, 'dd-MMM-yyyy'), 'yyyy-MM-dd') as FormattedDate

Unten finden Sie Code zur Veranschaulichung des Fehlers und meine Lösung zur Behebung des Fehlers. Zuerst las ich Börsendaten in einem gängigen Standard-Dateiformat ein:

    import sys.process._
    import org.Apache.spark.sql.SQLContext
    import org.Apache.spark.sql.functions.udf
    import org.Apache.spark.sql.types.{StructType, StructField, StringType, IntegerType, DateType}
    import sqlContext.implicits._

    val EODSchema = StructType(Array(
        StructField("Symbol"                , StringType, true),     //$1       
        StructField("Date"                  , StringType, true),     //$2       
        StructField("Open"                  , StringType, true),     //$3       
        StructField("High"                  , StringType, true),     //$4
        StructField("Low"                   , StringType, true),     //$5
        StructField("Close"                 , StringType, true),     //$6
        StructField("Volume"                , StringType, true)      //$7
        ))

    val textFileName = "/user/feeds/eoddata/INDEX/INDEX_19*.csv"

    // below is code to read using later versions of spark
    //val eoddata = spark.read.format("csv").option("sep", ",").schema(EODSchema).option("header", "true").load(textFileName)


    // here is code to read using 1.6, via, "com.databricks:spark-csv_2.10:1.2.0"

    val eoddata = sqlContext.read
                               .format("com.databricks.spark.csv")
                               .option("header", "true")                               // Use first line of all files as header
                               .option("delimiter", ",")                               //.option("dateFormat", "dd-MMM-yyyy") failed to work
                               .schema(EODSchema)
                               .load(textFileName)

    eoddata.registerTempTable("eoddata")

Und hier sind die Datumskonvertierungen mit Problemen:

%sql 
-- notice there are errors around the turn of the year
Select 
    e.Date as StringDate
,   cast(from_unixtime(unix_timestamp(e.Date, "dd-MMM-yyyy"), 'YYYY-MM-dd') as Date)  as ProperDate
,   e.Close
from eoddata e
where e.Symbol = 'SPX.IDX'
order by cast(from_unixtime(unix_timestamp(e.Date, "dd-MMM-yyyy"), 'YYYY-MM-dd') as Date)
limit 1000

Ein in Zeppelin erstelltes Diagramm zeigt Spitzen, die Fehler sind.

Errors in date conversion seen as spikes

und hier ist die Überprüfung, die die Datumsumwandlungsfehler zeigt:

// shows the unix_timestamp conversion approach can create errors
val result =  sqlContext.sql("""
Select errors.* from
(
    Select 
    t.*
    , substring(t.OriginalStringDate, 8, 11) as String_Year_yyyy 
    , substring(t.ConvertedCloseDate, 0, 4)  as Converted_Date_Year_yyyy
    from
    (        Select
                Symbol
            ,   cast(from_unixtime(unix_timestamp(e.Date, "dd-MMM-yyyy"), 'YYYY-MM-dd') as Date)  as ConvertedCloseDate
            ,   e.Date as OriginalStringDate
            ,   Close
            from eoddata e
            where e.Symbol = 'SPX.IDX'
    ) t 
) errors
where String_Year_yyyy <> Converted_Date_Year_yyyy
""")


//df.withColumn("tx_date", to_date(unix_timestamp($"date", "M/dd/yyyy").cast("timestamp")))


result.registerTempTable("SPX")
result.cache()
result.show(100)
result: org.Apache.spark.sql.DataFrame = [Symbol: string, ConvertedCloseDate: date, OriginalStringDate: string, Close: string, String_Year_yyyy: string, Converted_Date_Year_yyyy: string]
res53: result.type = [Symbol: string, ConvertedCloseDate: date, OriginalStringDate: string, Close: string, String_Year_yyyy: string, Converted_Date_Year_yyyy: string]
+-------+------------------+------------------+-------+----------------+------------------------+
| Symbol|ConvertedCloseDate|OriginalStringDate|  Close|String_Year_yyyy|Converted_Date_Year_yyyy|
+-------+------------------+------------------+-------+----------------+------------------------+
|SPX.IDX|        1997-12-30|       30-Dec-1996| 753.85|            1996|                    1997|
|SPX.IDX|        1997-12-31|       31-Dec-1996| 740.74|            1996|                    1997|
|SPX.IDX|        1998-12-29|       29-Dec-1997| 953.36|            1997|                    1998|
|SPX.IDX|        1998-12-30|       30-Dec-1997| 970.84|            1997|                    1998|
|SPX.IDX|        1998-12-31|       31-Dec-1997| 970.43|            1997|                    1998|
|SPX.IDX|        1998-01-01|       01-Jan-1999|1229.23|            1999|                    1998|
+-------+------------------+------------------+-------+----------------+------------------------+
FINISHED   

Nach diesem Ergebnis habe ich mit einer UDF wie dieser zu Java.time-Konvertierungen gewechselt, was bei mir funktioniert hat:

// now we will create a UDF that uses the very Nice Java.time library to properly convert the silly stockmarket dates
// start by importing the specific Java.time libraries that superceded the joda.time ones
import Java.time.LocalDate
import Java.time.format.DateTimeFormatter

// now define a specific data conversion function we want

def fromEODDate (YourStringDate: String): String = {

    val formatter = DateTimeFormatter.ofPattern("dd-MMM-yyyy")
    var   retDate = LocalDate.parse(YourStringDate, formatter)

    // this should return a proper yyyy-MM-dd date from the silly dd-MMM-yyyy formats
    // now we format this true local date with a formatter to the desired yyyy-MM-dd format

    val retStringDate = retDate.format(DateTimeFormatter.ISO_LOCAL_DATE)
    return(retStringDate)
}

Jetzt registriere ich es als Funktion für die Verwendung in SQL:

sqlContext.udf.register("fromEODDate", fromEODDate(_:String))

überprüfen Sie die Ergebnisse und führen Sie den Test erneut aus:

val results = sqlContext.sql("""
    Select
        e.Symbol    as Symbol
    ,   e.Date      as OrigStringDate
    ,   Cast(fromEODDate(e.Date) as Date) as ConvertedDate
    ,   e.Open
    ,   e.High
    ,   e.Low
    ,   e.Close
    from eoddata e
    order by Cast(fromEODDate(e.Date) as Date)
""")

results.printSchema()
results.cache()
results.registerTempTable("results")
results.show(10)
results: org.Apache.spark.sql.DataFrame = [Symbol: string, OrigStringDate: string, ConvertedDate: date, Open: string, High: string, Low: string, Close: string]
root
 |-- Symbol: string (nullable = true)
 |-- OrigStringDate: string (nullable = true)
 |-- ConvertedDate: date (nullable = true)
 |-- Open: string (nullable = true)
 |-- High: string (nullable = true)
 |-- Low: string (nullable = true)
 |-- Close: string (nullable = true)
res79: results.type = [Symbol: string, OrigStringDate: string, ConvertedDate: date, Open: string, High: string, Low: string, Close: string]
+--------+--------------+-------------+-------+-------+-------+-------+
|  Symbol|OrigStringDate|ConvertedDate|   Open|   High|    Low|  Close|
+--------+--------------+-------------+-------+-------+-------+-------+
|ADVA.IDX|   01-Jan-1996|   1996-01-01|    364|    364|    364|    364|
|ADVN.IDX|   01-Jan-1996|   1996-01-01|   1527|   1527|   1527|   1527|
|ADVQ.IDX|   01-Jan-1996|   1996-01-01|   1283|   1283|   1283|   1283|
|BANK.IDX|   01-Jan-1996|   1996-01-01|1009.41|1009.41|1009.41|1009.41|
| BKX.IDX|   01-Jan-1996|   1996-01-01|  39.39|  39.39|  39.39|  39.39|
|COMP.IDX|   01-Jan-1996|   1996-01-01|1052.13|1052.13|1052.13|1052.13|
| CPR.IDX|   01-Jan-1996|   1996-01-01|  1.261|  1.261|  1.261|  1.261|
|DECA.IDX|   01-Jan-1996|   1996-01-01|    205|    205|    205|    205|
|DECN.IDX|   01-Jan-1996|   1996-01-01|    825|    825|    825|    825|
|DECQ.IDX|   01-Jan-1996|   1996-01-01|    754|    754|    754|    754|
+--------+--------------+-------------+-------+-------+-------+-------+
only showing top 10 rows

das sieht in Ordnung aus, und ich führe mein Diagramm erneut aus, um festzustellen, ob Fehler/Spitzen vorliegen:

enter image description here

Wie Sie sehen, gibt es keine Spitzen oder Fehler mehr. Ich verwende jetzt eine UDF, wie ich gezeigt habe, um meine Datumsformat-Transformationen auf ein Standard-JJJJ-MM-TT-Format anzuwenden, und habe seitdem keine falschen Fehler mehr gehabt. :-)

0
Minkymorgan