海外ロケーションと日付フォーマット dd/MM/yyyy

先日、ヨーロッパからの案件でXamarin Androidの開発をしていたときのこと。SQLServerへの日付型のデータで更新エラーが発生するという連絡をクライアントから受けたのですが、こちらでは何度やっても正常に動く。開発環境はすべてEnglish(UK)のOSでそろえているので言語環境も違いはないはず。違うのはロケーション、つまりタイムゾーンだけ。

詳細に調査したところ、System.Data.SqlClientを使ってSQLServerから日付データを取得するとき、AndroidOSが自動判別したタイムゾーンに応じて日付フォーマットが変化することが分かりました。どおりで日本だとエラーにならないわけです。

SQLServerで日付型のデータを保存するとき、既定では、

English(UK) : dd/MM/yyyy  -- 保存NG
English(US) : MM/dd/yyyy  -- 保存OK
Japanese    : yyyy/MM/dd  -- 保存OK

となっています。なので、以下のようなDateTime型カラムを更新するSQLはエラーになります。

--エラーになる
INSERT INTO T_TEST (InputDate) VALUES ('30/06/2022') 

「out-of-range value」というエラーを吐き出して、30月6日なんて日付はだめだよと怒られます。グローバルなアプリを開発する際は文化の違いを意識して作らなければいけませんね。対策は、DMYオプションを宣言して、

--エラーにならない
SET DATEFORMAT DMY
INSERT INTO T_TEST (InputDate) VALUES ('30/06/2022')

としてSQLServer側に欧州フォーマットでの処理をお願いするか、プログラム側で常にyyyy/MM/ddにフォーマット変換してからSQLServerに渡すことを習慣づけるかのどちらかですね。

面倒でも後者の方がバグは発生しにくいかもしれません。