ZoneDateTimeにいろいろメソッドを生やしたいわけです。
Qiitaに書いたけど、ブログにも書いとく
ZoneDateTimeからいろいろ取り出したい
まあ、色々ありますよね。
- 年月日以外のフィールドを0で切り捨てたいとか
- 各フィールドをハイフン区切りで文字列にしたいとか
- 年月だけyyyyMMのフォーマットで欲しいとか
うちはMySQLで年月日でパーティションを切っている(20190101, 20190102とか)ので、yyyyMMddフォーマットでInt型で取り出したいケースが頻繁にある。
そういう場合、こういうコードを書くことになる
val now = ZonedDateTime.now() //とりあえず現在時刻 val formatter = DateTimeFormatter.ofPattern("yyyyMMdd") val yyyyMMdd = now.format(formatter).toInt
DateTimeFormatterのインスタンスはスレッドセーフなので、定数に定義しとけばいい。
以下のような感じで
object Formatters { val yyyyMMddFormatter = DateTimeFormatter.ofPattern("yyyyMMdd") }
そしたら次のように実質1行でかける
import Formatters._ //mainとかは省略 val now = ZonedDateTime.now() //とりあえず現在時刻 val yyyyMMdd = now.format(yyyyMMddFormatter).toInt
now.format(yyyyMMddFormatter).toInt
どうでしょう?まだめんどくさくないですか?
私は実務で本当によくこのフォーマットを使うので、これを何回も書くのはダルいです。
ZoneDateTimeが持つ情報で完結しているわけなので、ZoneDateTimeのインスタンスメソッドとして生えててほしい!!!!!
(カプセル化的な観点でもね)
(私は「メソッドを生やす」という表現をよく使いますが、みなさんはどのようにいいますか?)
implicit classで拡張してしまう
implicit classについてはググって。早い話が既存クラスを拡張する仕組みです。
Scala 2.10からしか使えないので注意 (implicit conversion使えば同じことできるけど
今回のケースだと、ZoneDateTimeをラッパークラスに自動変換するものだと思ってもらえばいいはず。
次のようなクラスを作ります。
implicit class RichZoneDateTime(val self: ZoneDateTime) extends AnyVal { private val yyyyMMddFormatter = DateTimeFormatter.ofPattern("yyyyMMdd") def yyyyMMdd: Int = { self.format(yyyyMMddFormatter).toInt } }
コンストラクタ引数のselfの型は拡張したいクラスにする(今回はZoneDateTime)
クラス名は拡張元のクラス名の頭にRichとプレフィックスをつけるのが定番(だと思う
上記クラスをスコープ内に入れた状態だと、以下のコードが実行可能になる
val now = ZoneDateTime.now()
now.yyyyMMdd
実行時に、yyyyMMddメソッドを叩いたときに、暗黙的にRichZoneDateTimeに変換されてる(はず
頻繁に使う変換処理とか、文字列フォーマット処理とかをimplicit classに生やすとスッキリする。
まとめ
implicit classで最強のオレオレZoneDateTimeを作ろう!!!