Skip to content

Instantly share code, notes, and snippets.

@ujihisa
Created August 7, 2013 03:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ujihisa/6170912 to your computer and use it in GitHub Desktop.
Save ujihisa/6170912 to your computer and use it in GitHub Desktop.
Vim Advent Calendar 2012 http://atnd.org/events/33746

Vim Advent Calendar 2012 ujihisa 18 (249日目)

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

Vitalのキラーモジュールの一つとも呼ばれているDateTimeモジュールを用います。なお、作者/メンテナはthincaさんです。

準備

今回は特にプラギンを作るわけではないので、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()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment