2
0

More than 1 year has passed since last update.

Go のような日時フォーマットを Ruby で使えるようにする gem「GoTime」

Posted at

 Rubyist の皆さま、日々 Time#strftime 使ってますか?

 Rails プログラマの場合 直接 Time#strftime を使う機会は少ないと思いますが、設定ファイル上などで strftime 用のフォーマット文字列1 を書いたことがあるのではないかと思います。

 ですので当然 strftime 用のフォーマット文字列など、何も見なくてもスラスラ書ける方が多いのではないでしょうか。

 私は見ないと書けませんけどね!

 だって何?このフォーマット文字列。48個もあるんですけど???こんなの覚えられると思ってんの?いやもちろん全部覚える必要はなくてよく使うものだけ覚えていればいいし そもそも必要なときに調べればいいんですけど、でもとっさに "%a %b %e %H:%M:%S %Y" なんて文字列を見たときに、どんな表示になるかわかります?

 あと『%P』……ってよォ~~~ am / pm になるってのは わかる……… スゲーよくわかる pm には p があるからな… だが『%p』が AM / PM になるのはどういう事だああ~~~~~っ!? なんで大文字小文字が逆なのかっつーのよ―――――――ッ!ナメやがって この規則ゥ超イラつくぜぇ~~~ッ!! どういう事だ!どういう事だよッ!クソッ! %P %p ってどういう事だッ!ナメやがって クソッ!クソッ!

 …なお strftime は Ruby 特有のメソッドではなく他のプログラミング言語にも大抵あるので別に Ruby が悪いわけではありません。

 ですが後発言語である Go では、strftime の代わりに別のアプローチを採っています。

Goの日時表記
t := time.Now()
fmt.Printf("%s", t.Format("Mon, 02 Jan 2006 15:04:05"))

 簡単に言えば、「『2006年1月2日(月)午後3時4分5秒』という日時をどうやって表す?」という書き方をします。『2006年1月2日(月)午後3時4分5秒』というのはアメリカ式の日時表記をした時に 1, 2, 3, ... と数値が順番通りになる日時2なので日本人にとっては覚えにくいのですが、これさえ覚えてしまえば直感的に書くことができ、書かれたフォーマット文字列を見たときにも どのような日時表示になるのかわかりやすくていいと思います。

 検索すると Go のこのやり方を「気持ちわるい」とか「違和感がある」とか書いている人も多いのですが、私としては良いやり方だと思っています。

 というわけで、Ruby でも Go のような日時フォーマットを使えるようにした gem を作りました。

GoTime

基本的な使い方

インストール方法等は省略します。

require "go_time"
time = Time.utc(2012, 3, 4, 5, 6, 7)
GoTime.format(time, "01/02 03:04:05PM '06 -0700")
#                => "03/04 05:06:07AM '12 +0000"

のように、GoTime.format を使って Time オブジェクト3を Go の日時フォーマットに従って変換することができます。

 あるいは using GoTime することで Time オブジェクトを拡張し、Time#format という形で使うこともできます。

require "go_time"
using GoTime
time = Time.utc(2012, 3, 4, 5, 6, 7, 80000)
time.format("2006/01/02 15:04:05.000")
#        => "2012/03/04 05:06:07.080"

 さらに派手にやりたいのであれば、require "go_time/strftime" することで、Time#strftime で strftime フォーマットだけでなく Go フォーマットも使えるようになります。4

require "go_time/strftime"
time = Time.utc(2012, 3, 4, 5, 6, 7, 80000)
time.strftime("Mon Jan _2 15:04:05 2006")
#          => "Sun Mar  4 17:06:07 2012"

 また、gotime コマンドがインストールされ、Go の日時フォーマットを入力すると strftime フォーマットに変換したものを表示してくれます。

$ gotime 2006/01/02 15:04:05.000
%Y/%m/%d %H:%M:%S.%3N

 引数無しで起動すると対話的に利用できます。Go では対応しているけれど Time#strftime では対応していない表記があった場合には、ちゃんとそのことを伝えてくれます。

$ gotime
> 2006/01/02
=> %Y/%m/%d
> 2006/01/02 Z0700
unsupported syntax "Z0700"
> exit

「この gem を本番環境に使う気はないけど、strftime フォーマットが覚えられない…」という方は、gotime コマンドで strftime 文字列を生成してはいかがでしょうか。

拡張機能

 さらにせっかくなので、Go で使える表記だけでなく、さらに様々な言語での日時表現が使えるようにする拡張機能を用意しました。

require "go_time/ext/ja" # Japanese
time = Time.utc(2019, 5, 6, 7, 8, 9)
GoTime.format(time, "平成十八年(二〇〇六年)一月二日(火) 午後三時四分五秒")
#                  => "令和元年(二〇一九年)五月六日(月) 午前七時八分九秒"
GoTime.format(time, "㍻十八年 睦月")
#                  => "㋿元年 皐月"
GoTime.format(time, "H18 01/02 PM03:04:05")
#                  => "R1 05/06 AM07:08:09"

 今のところ日本語のみですが、このように元号や漢数字、全角数字などに対応しています。

 一点注意が必要なのは、曜日です。Go の本来のリファレンスタイム 2006/01/02 は月曜日なのですが、「月」だと「1月」等の表記に誤反応するため、「火」を曜日表記として認識するようにしています。

 他の言語にも対応させたいなぁと思っていますが、あいにく言語知識が無いので、さまざまな言語の知識がある方のプルリクエストをお待ちしております。


  1. Rails の場合、正確には TimeWithZone#strftime だと思いますが。 

  2. 参考:Goのtimeパッケージのリファレンスタイム(2006年1月2日)は何の日? 

  3. Time だけでなく、 DateTimeWithZone などでも大丈夫です。 

  4. これを使えば Rails 等でコードを書き換えなくても Go のフォーマットが使えるようになるのではないかと思いますが(未確認)、影響が大きすぎるのでむやみに使わないほうがいいと思います。 

2
0
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
2
0