銀の光と碧い空

クラウドなインフラとC#なアプリ開発の狭間にいるエンジニアの日々

Amazon Redshift への COPY コマンドで ISO 8601形式の時刻表記は完全にはサポートされていませんでした

Amazon RedShift にS3に上げたファイルからレコードをロードするときは、COPYコマンドが使えます。COPYコマンドにはいくつかのオプションがあるのですが、ファイルに記述されているJSONの中の日時文字列のフォーマットを設定するオプションがあります。 SLABのCustomSinkとして作成したS3SinkでS3にファイルをアップロードしていますが、このとき JSON.NET をデフォルトの設定で使っているため、DateTime型の値は TimeZone情報を含むISO 8601形式として文字列にフォーマットされます。

"2014-08-03T01:23:45.000000+09:00"

このようなフォーマットの日時文字列をCOPYコマンドでロードするには、timeformat オプションを auto にして自動認識を使用するとほとんどのパターンでうまくいきます。

COPY table FROM s3://hoge/hoge
JSON as s3://hoge/hoge.json_path
TIMEFORMAT AS 'auto'
GZIP;

自動認識についてのドキュメントはこちら。

DATEFORMAT と TIMEFORMAT で自動認識を使用する - Amazon Redshift

ISO 8601形式は上のドキュメントに書かれてはいませんが、ほとんどの場合うまくいきます。 が、ほとんどとある通り、あるパターンではロードに失敗してしまいます。具体的にはこんなケースです。

2014-08-03T01:23:45.9999997+09:00       

つまり、秒未満の値が .999999n (5≦n≦9) と四捨五入すると秒が1つくりあがるパターンです。ほとんどの場合うまくいっても、小数とはいえ特定のパターンでロードできないと困るので、ちゃんとドキュメントでサポートが明記されているパターンにしましょう、というお話でした。

なお、今回の場合 JSON.NET でJSONを生成しているので、 DateTimeConverterBase を継承したカスタムコンバーターを作成し、JsonConvert#SerializeObject メソッドの引数に渡してあげると、指定した形式で DateTime型の値がフォーマットされます。

Json.NET - Documentation - Table of Content