Vim Advent Calendar 2012 の242日目の記事です。#昨日の記事はtyruさんで、明日の記事はsyuiさんの予定です。
今日は8月6日ですね。さて問題です。「2013年8月6日からVim Advent Calendar 2012とVim Advent Calendar 2013が並走開始する日まで何日か」をVim scriptで計算してください。
大前提として、Vim Advent Calendar 2013は2013年12月1日に確実に開始するものとします。また、Vim Advent Calendar 2012は、http://atnd.org/events/33746 にかかれているように
> 通常の Advent Calendar とは違い、特に終了期日は設けないのでどんどん参加しましょう!
とあるので、当然2013年12月1日よりもあとも無限に継続されます。
Vitalのキラーモジュールの一つとも呼ばれているDateTimeモジュールを用います。なお、作者/メンテナはthincaさんです。
- Vital.DateTime
- doc: https://github.com/vim-jp/vital.vim/blob/master/doc/vital-date_time.txt
- spec: https://github.com/vim-jp/vital.vim/blob/master/spec/date_time.vim
- 実装: https://github.com/vim-jp/vital.vim/blob/master/autoload/vital/__latest__/DateTime.vim
- 作者による紹介記事 http://d.hatena.ne.jp/thinca/20120115/1326624337
今回は特にプラギンを作るわけではないので、Vim Advent Calendar 2012の記事「Vim script入門」 を参考に、vitalがプラギンとしてインストールされている前提で、vital#of('vital')
を直接使って手抜きしてしまいましょう。
まずDateTimeモジュールを利用するための、importします。
let s:V = vital#of('vital')
let s:D = s:V.import('DateTime')
変数目はい慣習に従い、モジュール名の先頭文字(大文字)一文字にしています。
つづいて、:h vital.datetime
を参考に、2013年8月6日を示すオブジェクトと、2013年12月1日を示すオブジェクトを作ります。
let s:today = s:D.from_format('2013-08-06', '%F')
let s:start2013 = s:D.from_format('2013-12-01', '%F')
おおっと、この突然登場した%F
とは一体何者でしょうか。
これは:h Vital.DateTime-format
を参考に利用しました。from_format()
関数は第一引数に生成したい日付を文字列で与え、第二引数にて、どのようにそれをパースするかを指定します。
The format is similar to |strftime()|.
There is a list of specifications of the format.
+---- Available for formatting
| +-- Available for parsing
| |
o o %% The '%' character.
o %a The abbreviated weekday name.
o %A The full weekday name.
o o %b The abbreviated month name.
o o %B The full month name.
o o %c Equivalent to "%F %T %z".
o o %C The century number (year/100) as a 2-digit integer.
o o %d The day of the month as a decimal number (range 01 to 31).
o o %D Equivalent to "%m/%d/%y".
o o %e Equivalent to "%_m/%_d/%_y".
o o %F Equivalent to "%Y-%m-%d".
o o %H The hour as a decimal number using a 24-hour clock(range 00 to 23).
o o %I The hour as a decimal number using a 12-hour clock(range 01 to 12).
o %j The day of the year as a decimal number (range 001 to 366).
o o %k Equivalent to "%_H".
o o %l Equivalent to "%_I".
o o %m The month as a decimal number (range 01 to 12).
o o %M The minute as a decimal number (range 00 to 59).
o o %n When formatting, a newline character.
When parsing, arbitrary whitespace.
o o %p Either "AM" or "PM" according to the given time value.
o o %P Like %p but in lowercase. NOTE: This doesn't work in MS Windows.
o o %r Equivalent to "%I:%M:%S %p".
o o %R Equivalent to "%H:%M".
o %s The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000.
o o %S The second as a decimal number (range 00 to 59).
o o %t When formatting, a tab character.
When parsing, arbitrary whitespace.
o o %u The day of the week as a decimal, range 1 to 7, Monday being 1.
o o %T Equivalent to "%H:%M:%S".
o %w The day of the week as a decimal, range 0 to 6, Sunday being 0.
o o %y The year as a decimal number without a century (range 00 to 99).
o o %Y The year as a decimal number including the century.
o o %z The +hhmm or -hhmm numeric timezone. The pattern which this uses
for parsing is same as the argument of |Vital.DateTime.timezone()|.
But, an empty string is treated as UTC.
o %* Any texts.
今回は非常に直感的な%F
を使用しました。かなりわかりやすい記述になりましたが、タイムゾーンがローカルタイムになるのが怖いところです。タイムゾーンをオブジェクト生成時から指定したいならば、%F
に時刻とタイムゾーンの両方の指定を同時に行う%c
を使うのがよさそうです。
let s:today = s:D.from_format('2013-08-06 00:00:00 0000', '%c')
let s:start2013 = s:D.from_format('2013-12-01 00:00:00 0000', '%c')
ちょっぴり記述が冗長になりましたが、安心感がグッと高まりました。
最後にこの2つの日の差を求めましょう。
let s:timedelta = s:start2013.delta(s:today)
delta()
はTimeDeltaオブジェクトを生成します (:h timedelta
)。
欲しいのはその日数なので、days()
しましょう。
echo s:timedelta.days() "=> 117
ついに結果を得ることができました! 117日後に並走する、という事実が判明しました。
まとめると以下のようになります。冗長な記述を一部単純化しています。
let s:V = vital#of('vital')
let s:D = s:V.import('DateTime')
echo s:D.from_format('2013-08-06 00:00:00 0000', '%c').
\ delta(s:D.from_format('2013-12-01 00:00:00 0000', '%c')).
\ days()