LoginSignup
12
3

More than 5 years have passed since last update.

data/timestamp型関数の仕様変更二題

Last updated at Posted at 2017-12-15

はじめに

にゃーん
この記事は、PostgreSQL 10全部ぬこ Advent Calendar 2017 の16日目のエントリです。
今日は軽めのネタで。

make_date()

PostgreSQLにはmake_date()というSQL関数がある。

postgres=# \df make_date 
List of functions
-[ RECORD 1 ]-------+-----------------------------------------
Schema              | pg_catalog
Name                | make_date
Result data type    | date
Argument data types | year integer, month integer, day integer
Type                | normal

第1引数に整数で年、第2引数に整数で月、第3引数に整数で日を与えるとdate型を生成してくれるという関数だ。

PostgreSQL 9.6まで

PostgreSQL 9.6までは、年には正の整数しか指定できなかった。

postgres=# SELECT make_date(2017, 12, 16);
 make_date  
------------
 2017-12-16
(1 row)

年に負数や0を指定すると、範囲外というエラーになる。

postgres=# SELECT make_date(-1, 12, 16);
ERROR:  date field value out of range: -1-12-16
postgres=# SELECT make_date(0, 12, 16);
ERROR:  date field value out of range: 0-12-16

PostgreSQL 10から

「なんでmake_date()で紀元前の年が生成できねえんじゃ、ゴルァ!」と古代史に関するデータベースを作ろうとしてエラーになったから改造した・・・かどうかは不明だが、PostgreSQL 10からはmake_date()に、年に負の整数値を指定可能になった。負の整数値を与えた場合には(デフォルトのロケールだと)"BC"表記がつくようだ。

postgres=# SELECT make_date(-1, 12, 16);
   make_date   
---------------
 0001-12-16 BC
(1 row)

ただし、0については、PostgreSQL 10でもエラーになる。西暦0年は存在しないからだ。

postgres=# SELECT make_date(0, 12, 16);
ERROR:  date field value out of range: 0-12-16

おまけ

make_date()に与える年の正整数の上限っていくつなのか?というと、それはdate型の上限によって制限されている。date型は5,874,897年までは入力可能っぽい。太陽系が滅亡するまでの数十億年というスケールの年入力には使えないけど、数百万年程度の期間であれば使用には十分だろう。

space_solar_system.png

to_timestamp()とto_date()

これらの関数は文字どおり、テキストで表現されたタイムスタンプや日時をtimestamp型やdate型に変更してくれるものだ。

PostgreSQL 9.6まで

しかし、この関数、意外とチェックがぬるかったりしていた。
例えば、12月32日なんて記述を許容してしまう。

postgres=# SELECT to_date('2017-12-32','YYYY-MM-DD');
  to_date   
------------
 2018-01-01
(1 row)

postgres=# SELECT to_timestamp('2017-12-32 00:00:00', 'YYYY-MM-DD');
      to_timestamp      
------------------------
 2018-01-01 00:00:00+09
(1 row)

誤った閏日を指定しても、3/1にマッピングしてしまう。

postgres=# SELECT to_date('2018-02-29','YYYY-MM-DD');
  to_date   
------------
 2018-03-01
(1 row)

PostgreSQL 10から

to_date(), to_timestamp()の日付の範囲チェックを厳密にするようになった。

postgres=# SELECT to_date('2017-12-32','YYYY-MM-DD');
ERROR:  date/time field value out of range: "2017-12-32"
postgres=# SELECT to_timestamp('2017-12-32 00:00:00', 'YYYY-MM-DD');
ERROR:  date/time field value out of range: "2017-12-32 00:00:00"

閏日もきちんとチェックするようだ。

postgres=# SELECT to_date('2018-02-29','YYYY-MM-DD');
ERROR:  date/time field value out of range: "2018-02-29"
postgres=# SELECT to_date('2020-02-29','YYYY-MM-DD');
  to_date   
------------
 2020-02-29
(1 row)

おわりに

  • make_date()で紀元前の年入力が可能になった。
  • to_date()とto_timestamp()で暦上、誤った指定を厳密にチェックするようになった。

参考:該当するリリースノート

本エントリに関連するPostgreSQL 10リリースノートの記載です。

E.2.3.6. Functions

  • Allow make_date() to interpret negative years as BC years (Álvaro Herrera)
  • Make to_timestamp() and to_date() reject out-of-range input fields (Artur Zakirov)
12
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
3