掲題の件、JSON等にある日付フォーマットの文字列から、Timestamp形式に変換したかったのですが、どの書式だと変換できるのか良くわかってなかったので、実際に実行してみました。
初期化
初期化してから動かしてみます。
from awsglue.dynamicframe import DynamicFrame from awsglue.context import GlueContext glueContext = GlueContext(sc)
日付文字列
ISO8601を中心に少しずつ違うのを並べて準備してみました。
time_strings = sc.parallelize([ (1,"20060102"), (2,"2006-01-02"), (3,"2006/01/02"), (4,"2006-01-02 15:04:05"), (5,"2006-01-02 15:04:05.123"), (6,"2006-01-02 15:04:05.123456789"), (7,"2006-01-02T15:04:05"), (8,"2006-01-02T15:04:05Z0700"), (9,"2006-01-02T15:04:05Z070000"), (10,"2006-01-02T15:04:05-0700"), (11,"2006-01-02T15:04:05-070000"), (12,"2006-01-02T15:04:05-07"), (13,"2006-01-02T15:04:05-07:00"), (14,"2006-01-02T15:04:05.999Z"), (15,"2006-01-02T15:04:05.999-0700"), (16,"2006-01-02T15:04:05Z"), (17,"2006-01-02T15:04:05Z07"), (18,"2006-01-02T15:04:05Z07:00"), (19,"2006-01-02T15:04:05Z0700"), (20,"2006-01-02T15:04:05.999999999Z07:00"), ]).toDF(['id','time_string']) time_strings.printSchema()
root |-- id: long (nullable = true) |-- time_string: string (nullable = true)
Glueでマッピング
GlueのDynamicFrame使って直接 timestamp
型にマッピングしてみます。
time_strings_dyf = DynamicFrame.fromDF( dataframe = time_strings, glue_ctx = glueContext, name = '' ) time_parsed = time_strings_dyf.apply_mapping([ ('id','long','id','long'), ('time_string','string','time_string','string'), ('time_string','string','parsed_time','timestamp') ]) time_parsed.printSchema()
root |-- id: long |-- time_string: string |-- parsed_time: timestamp
結果
結果を出力してみます。
time_parsed.toDF().show(truncate=False)
いくつか失敗してnullになってしまいました。細かくできたりできないのがあります。
+---+-----------------------------------+--------------------------+ |id |time_string |parsed_time | +---+-----------------------------------+--------------------------+ |1 |20060102 |null | |2 |2006-01-02 |2006-01-02 00:00:00 | |3 |2006/01/02 |null | |4 |2006-01-02 15:04:05 |2006-01-02 15:04:05 | |5 |2006-01-02 15:04:05.123 |2006-01-02 15:04:05.123 | |6 |2006-01-02 15:04:05.123456789 |2006-01-02 15:04:05.123456| |7 |2006-01-02T15:04:05 |2006-01-02 15:04:05 | |8 |2006-01-02T15:04:05Z0700 |null | |9 |2006-01-02T15:04:05Z070000 |null | |10 |2006-01-02T15:04:05-0700 |null | |11 |2006-01-02T15:04:05-070000 |null | |12 |2006-01-02T15:04:05-07 |2006-01-02 22:04:05 | |13 |2006-01-02T15:04:05-07:00 |2006-01-02 22:04:05 | |14 |2006-01-02T15:04:05.999Z |2006-01-02 15:04:05.999 | |15 |2006-01-02T15:04:05.999-0700 |null | |16 |2006-01-02T15:04:05Z |2006-01-02 15:04:05 | |17 |2006-01-02T15:04:05Z07 |2006-01-02 08:04:05 | |18 |2006-01-02T15:04:05Z07:00 |2006-01-02 08:04:05 | |19 |2006-01-02T15:04:05Z0700 |null | |20 |2006-01-02T15:04:05.999999999Z07:00|2006-01-02 08:04:05.999999| +---+-----------------------------------+--------------------------+
DynamicFrame使わない方法も試してみました。TimestampType型にキャストしてみてます。
この方法では結果は一緒でした。特別なことはしてなさそうです。
from pyspark.sql.types import TimestampType time_strings.select( 'id', 'time_string', time_strings['time_string'].cast(TimestampType()).alias('parsed_time') ).show(truncate=False)
UnixTimeの変換
同様にUnixtimeも試してみました。10桁と13桁のものです。
unixtime_strings = sc.parallelize([ ("unixts", 1136181845), ("unixtsms", 1136181845999) ]).toDF(['id','time_long'])
こちらはGlueのマッピング使ったものと、Sparkでキャストしたものが結果が異なりました。
Glue
Glueのライブラリでは13桁ミリ秒の方が正しく変換できています。
unixtime_strings_dyf = DynamicFrame.fromDF( dataframe = unixtime_strings, glue_ctx = glueContext, name = '' ) parsed_unixtime = unixtime_strings_dyf.apply_mapping([ ('id','string','id','string'), ('time_long','long','time_long','long'), ('time_long','long','parsed_time','timestamp') ]) parsed_unixtime.toDF().show(truncate=False)
+--------+-------------+-----------------------+ |id |time_long |parsed_time | +--------+-------------+-----------------------+ |unixts |1136181845 |1970-01-14 03:36:21.845| |unixtsms|1136181845999|2006-01-02 06:04:05.999| +--------+-------------+-----------------------+
Spark
こちらは10桁の秒のUnixTimeが正しく変換できています。
from pyspark.sql.types import TimestampType from pyspark.sql.functions import from_unixtime unixtime_strings.select( 'id', 'time_long', unixtime_strings['time_long'].cast(TimestampType()).alias('parsed_time'), from_unixtime(unixtime_strings['time_long']).alias('parsed_time_by_functions') # これはString型 ).show(truncate=False)
+--------+-------------+-----------------------+------------------------+ |id |time_long |parsed_time |parsed_time_by_functions| +--------+-------------+-----------------------+------------------------+ |unixts |1136181845 |2006-01-02 06:04:05 |2006-01-02 06:04:05 | |unixtsms|1136181845999|37974-03-03 20:19:599.0|37974-03-03 20:19:59 | +--------+-------------+-----------------------+------------------------+
sparkのソースや、pysparkの情報見てみたら、以下のようにあるので、Glue側が別の処理をしているのかも。
Converts the number of seconds from unix epoch (1970-01-01 00:00:00 UTC) to a string representing the timestamp of that moment in the current system time zone in the given format. http://spark.apache.org/docs/2.2.1/api/python/_modules/pyspark/sql/functions.html#from_unixtime