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

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

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

[^timewithzone]: Rails の場合、正確には `TimeWithZone#strftime` だと思いますが。

- 参考：[【初心者向け・動画付き】Railsで日時をフォーマットするときはstrftimeよりも、lメソッドを使おう](https://qiita.com/jnchito/items/831654253fb8a958ec25)

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

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

　だって何？この[フォーマット文字列](https://docs.ruby-lang.org/ja/latest/method/Time/i/strftime.html)。48個もあるんですけど？？？こんなの覚えられると思ってんの？いやもちろん全部覚える必要はなくてよく使うものだけ覚えていればいいし そもそも必要なときに調べればいいんですけど、でもとっさに `"%a %b %e %H:%M:%S %Y"` なんて文字列を見たときに、どんな表示になるかわかります？

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

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

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

```go: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, ... と数値が順番通りになる日時[^go]なので日本人にとっては覚えにくいのですが、これさえ覚えてしまえば直感的に書くことができ、書かれたフォーマット文字列を見たときにも どのような日時表示になるのかわかりやすくていいと思います。

[^go]: 参考：[Goのtimeパッケージのリファレンスタイム（2006年1月2日）は何の日？](https://qiita.com/ruiu/items/5936b4c3bd6eb487c182)

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

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

# GoTime

- [GoTime - formats Time like Golang](https://github.com/nodai2hitc/go_time)

## 基本的な使い方

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

```ruby
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` オブジェクト[^date]を Go の日時フォーマットに従って変換することができます。

[^date]: `Time` だけでなく、 `Date` や `TimeWithZone` などでも大丈夫です。

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

```ruby
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 フォーマットも使えるようになります。[^strftime]

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

```ruby
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 で使える表記だけでなく、さらに様々な言語での日時表現が使えるようにする拡張機能を用意しました。

```ruby
require "go_time/ext/ja" # Japanese
time = Time.utc(2019, 5, 6, 7, 8, 9)
GoTime.format(time, "平成十八年（二〇〇六年）一月二日(火) 午後三時四分五秒")
#                  => "令和元年（二〇一九年）五月六日(月) 午前七時八分九秒"
GoTime.format(time, "㍻十八年 睦月")
#                  => "㋿元年 皐月"
GoTime.format(time, "Ｈ１８ ０１/０２ ＰＭ０３：０４：０５")
#                  => "Ｒ１ ０５/０６ ＡＭ０７：０８：０９"
```

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

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

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