背景
Rails6.0のリリースノートを眺めていたら以下の記述を見つけました。
マイグレーションのタイムスタンプにデフォルトでprecision: 6を指定
cf. Ruby on Rails 6.0 リリースノート - Railsガイド
PRを読むと以下のように書かれています。
I guess the precision is for MySQL 5.6+, since datetime with no precision means unlimited precision for PostgreSQL and SQLite.
If we want explicit precision for the timestamps, I'll create new PR as new migration default in Active Record.
Yes, I think the precision is for MySQL. Well, if we could make it omit the precision on Postgres/SQLite and only add it on MySQL if the server supports it, that seems ideal to me.
// deepl翻訳
精度がないdatetimeはPostgreSQLやSQLiteでは無制限の精度を意味するので、精度はMySQL5.6+用かな。
タイムスタンプに明示的な精度が欲しい場合は、Active Recordの新しいマイグレーションのデフォルトとして新しいPRを作成しようと思います。
はい、精度はMySQL用だと思います。まあ、Postgres/SQLiteで精度を省略して、サーバがサポートしている場合のみMySQLで精度を追加するようにすれば、私には理想的な気がします。
### 該当PR
* [Allow using Action Mailbox on MySQL 5\.5 by kamipo · Pull Request \#34956 · rails/rails](https://github.com/rails/rails/pull/34956)
* [Fix default value for mysql time types with specified precision by nkondratyev · Pull Request \#33280 · rails/rails](https://github.com/rails/rails/pull/33280)
※ 具体的な動作は以下の記事で紹介されてました。
cf. [Rails6 のちょい足しな新機能を試す65(timestamps precision編) \- Qiita](https://qiita.com/suketa/items/bb5005c6ac77f8c368cb)
DBの仕様に関する問題の解決に見えましたが、いまいち理解ができていないので調査しました。
## 調査内容
### MySQL
「MySQL マイクロ秒」でググって見つけたリファレンスを読んだところ、以下の記述がありました。
> MySQL 5.6.4 以降では、マイクロ秒 (6 桁) までの精度を持つ TIME、DATETIME、および TIMESTAMP 値の小数秒に対応できるようになりました。
cf. [MySQL :: MySQL 5\.6 リファレンスマニュアル :: 11\.1\.2 日付と時間型の概要](https://dev.mysql.com/doc/refman/5.6/ja/date-and-time-type-overview.html)
なるほど、`5.6.4`でマイクロ秒まで持てるようになったんですね。
念の為5.6.3以前について調べる。
> fspは無指定の場合0となります。これは既存のものとの互換性のためです。
cf. [MySQL 5\.6\.4でマイクロ秒までサポート\(TIME, DATETIME, TIMESTAMP\) \| キムラデービーブログ](http://blog.kimuradb.com/?eid=877275)
こちらを読むに、5.6.3以前では秒未満は切り捨てだったようですね。
なお`MySQL5.6.4`のリリースは**2011/12/20**でした。9年前!
cf. [MySQL :: MySQL 5\.6 Release Notes :: Changes in MySQL 5\.6\.4 \(2011\-12\-20, Milestone 7\)](https://dev.mysql.com/doc/relnotes/mysql/5.6/en/news-5-6-4.html)
改めてPRを見ましたが、今回の変更は「デフォルト値を追加」でしたね。
ある程度の時間が経ち、デフォルトにしても問題ないという判断での追加だったんだな〜と認識しました。
### PostgreSQL
次にPostgreSQLのリファレンスを見る。
> 日付/時刻データ型
time、timestampおよびintervalは秒フィールドに保有されている小数点以下の桁数を指定するオプションの精度値であるpを受け付けます。 デフォルトでは、明示的な精度に対する限界はありません。 pの許容範囲はtimestamp型とinterval型の場合は0から6です。
> 注意: timestampの値が8バイト整数(現在のデフォルト)で格納されていれば、すべての値についてμ秒精度が有効です。 timestampの値が倍精度浮動小数点数(将来のサポートが保証されないコンパイル時のオプション)で格納されていると、有効な精度は6より小さいかもしれません。
cf. [日付/時刻データ型](https://www.postgresql.jp/document/9.1/html/datatype-datetime.html)
なるほど、PRのコメント内容も踏まえると、
* PostgreSQLでは6桁(マイクロ秒)まで保持していた
* MySQL5.6.3以前ではできなかった
とことでしょうか。
なお、Rails(ActiveRecord)が対応するMySQLのバージョンは以下のように変わったそうです。
> Rails5.2まではActiveRecordがサポートするMySQLのバージョンは5.1.10以降でしたが、Rails6.0からは5.5.8以降に引き上げられました。
cf. [Rails6\.0のMySQLに関する変更点まとめ \- Qiita](https://qiita.com/taiteam/items/cb927d26e3601e75054b)
## まとめ
* PostgreSQLなど、timestamp型で小数点以下までサポートするものが多く、そちらに合わせたかった
* timestamp型の小数点以下の桁数を指定する時、Rails5.2以前では任意で指定する必要があった
* Rails6でMySQLの対応バージョンが引き上げられたのもあってか、デフォルトで指定するように変更された
* RDBMS間の仕様の差が少なくなった
という理解をしました。