Форматы временных меток и часовые пояса в Spark (scala API) - PullRequest
0 голосов
/ 01 сентября 2018

******* ОБНОВЛЕНИЕ ********

Как предложено в комментариях, я исключил несущественную часть кода:

Мои требования:

  1. Укажите количество миллисекунд до 3
  2. Преобразовать строку в метку времени и сохранить значение в UTC

Создать фрейм данных:

val df = Seq("2018-09-02T05:05:03.456Z","2018-09-02T04:08:32.1Z","2018-09-02T05:05:45.65Z").toDF("Timestamp")

Здесь результаты с использованием искровой оболочки:

enter image description here

************ ОБНОВЛЕНИЕ КОНЦА *********************************

У меня приятная головная боль, когда я пытаюсь разобраться с часовыми поясами и форматами отметок времени в Spark, используя scala.

Это упрощение моего сценария для объяснения моей проблемы:

 import org.apache.spark.sql.functions._

 val jsonRDD  = sc.wholeTextFiles("file:///data/home2/phernandez/vpp/Test_Message.json")

 val jsonDF =  spark.read.json(jsonRDD.map(f => f._2))

Это результирующая схема:

  root
 |-- MeasuredValues: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- MeasuredValue: double (nullable = true)
 |    |    |-- Status: long (nullable = true)
 |    |    |-- Timestamp: string (nullable = true)

Затем я просто выбираю поле Timestamp следующим образом

jsonDF.select(explode($"MeasuredValues").as("Values")).select($"Values.Timestamp").show(5,false)

Timestamp with different milliseconds length

Первое, что я хочу исправить, - это количество миллисекунд каждой метки времени и унифицируйте его до трех.

Я применил date_format следующим образом

jsonDF.select(explode($"MeasuredValues").as("Values")).select(date_format($"Values.Timestamp","yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")).show(5,false)

Milliseconds unified but time zone change

Формат в миллисекундах был исправлен, но метка времени конвертируется из UTC в местное время.

Чтобы решить эту проблему, я применил to_utc_timestamp вместе с моим местным часовым поясом.

jsonDF.select(explode($"MeasuredValues").as("Values")).select(to_utc_timestamp(date_format($"Values.Timestamp","yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"),"Europe/Berlin").as("Timestamp")).show(5,false)

to_utc_timestamp output

Еще хуже, значение UTC не возвращается, а формат в миллисекундах теряется.

Есть идеи, как с этим бороться? Я буду признателен за это 10

BR. Пол

1 Ответ

0 голосов
/ 02 сентября 2018

Причиной проблемы является строка формата времени, используемая для преобразования:

yyyy-MM-dd'T'HH:mm:ss.SSS'Z'

Как видите, Z находится внутри одинарных кавычек, что означает, что он не интерпретируется как маркер смещения зоны, а только как символ, подобный T в середине.

Таким образом, строка формата должна быть изменена на

yyyy-MM-dd'T'HH:mm:ss.SSSX

, где X - шаблон стандартного формата даты и времени Java (Z - значение смещения для 0).

Теперь исходные данные можно преобразовать в метки времени UTC:

val srcDF = Seq(
  ("2018-04-10T13:30:34.45Z"),
  ("2018-04-10T13:45:55.4Z"),
  ("2018-04-10T14:00:00.234Z"),
  ("2018-04-10T14:15:04.34Z"),
  ("2018-04-10T14:30:23.45Z")
).toDF("Timestamp")

val convertedDF = srcDF.select(to_utc_timestamp(date_format($"Timestamp", "yyyy-MM-dd'T'HH:mm:ss.SSSX"), "Europe/Berlin").as("converted"))

convertedDF.printSchema()
convertedDF.show(false)

/**
root
|-- converted: timestamp (nullable = true)

+-----------------------+
|converted              |
+-----------------------+
|2018-04-10 13:30:34.45 |
|2018-04-10 13:45:55.4  |
|2018-04-10 14:00:00.234|
|2018-04-10 14:15:04.34 |
|2018-04-10 14:30:23.45 |
+-----------------------+
*/

Если вам нужно преобразовать временные метки обратно в строки и нормализовать значения, чтобы иметь 3 конечных нуля, должен быть еще один вызов date_format, аналогичный тому, который вы уже применили в вопросе.

...