15 min/d

ぼうずやのにっき

TimeKeeper.js (bouzuya/time-keeper-js) をつくった

TimeKeeper.js (bouzuya/time-keeper-js) をつくった。

TimeKeeper.js は simple な date-time library 。

次の特徴を持つ。

  • simple な api
    • milliseconds に対応しない
    • day of week に対応しない
    • ISO8601 の標準の形式 (2006-01-02T15:04:05-07:00) 以外の formatter に対応しない
    • invalid な状態 (NullObject) に対応しない
    • mutable な状態に対応しない
  • TypeScript (.d.ts) に対応する

極力 simple な api にしている。README の Example ですべての api だ。

import * as assert from 'assert';
import { now, parseISOString, parseUNIXTime } from 'time-keeper';

const dt1 = now();
const dt2 = parseUNIXTime(dt1.toUNIXTime());
assert(dt1.toString() === dt2.toString());

const dt3 = parseISOString('2016-06-17T23:28:40+09:00');
assert(dt3.get('year') === 2016);
assert(dt3.get('month') === 6);
assert(dt3.get('date') === 17);
assert(dt3.get('hour') === 23);
assert(dt3.get('minute') === 28);
assert(dt3.get('second') === 40);
assert(dt3.toTimeZoneOffsetString() === '+09:00');

const dt4 = dt3.inTimeZone('+00:00');
assert(dt3.toISOString() === '2016-06-17T23:28:40+09:00');
assert(dt4.toISOString() === '2016-06-17T14:28:40+00:00');

const dt5 = dt4.plus(2, 'day');
assert(dt4.toISOString() === '2016-06-17T14:28:40+00:00');
assert(dt5.toISOString() === '2016-06-19T14:28:40+09:00');

目的。

TimeKeeper.js の目的としては次の 2 つだ。

JavaScript 界隈では定番の date-time library である momentmoment はとても良く出来た library だ。しかし moment はいくつかの罠があり、ぼくのまわりでそれに起因する事故が起きている。例を挙げると、 mutable であること・通常の parse だと time-zone が local になる・invalid な状態を許容する・format() の指定の誤りなどだ。そこで機能を制限し、自分の想像の範囲で安全に動作する library をつくろうと考えた。

2016-06-16 に書いた beater 0.4.0 の検証を兼ねたかった。適度に小さい library が欲しかった。

実装。

TimeKeeper.js の実装は最近のぼくの標準である Node.js + TypeScript (+typings) を使っている。moment を wrap しただけのお手軽実装だ。先の目的どおりに test は beater (+ beater-cli) + power-assert 。手堅く慣れた tool を使いつつ、beater の検証を図った感じ。

あとは特徴として TypeScript の String Literal Types を使っている点を挙げたい。上記の Example には文字列で fieldunit を取る点がある。このあたりは momentformat() 指定のように誤爆すると思われるかもしれないが、実は TypeScript user なら型安全だ。 TypeScript の String Literal Types なので間違えることなく使える。

ほかには、実装の隠蔽および TypeScript の private constructor をつくれない制約を回避するために、 interface とそれを返す関数を export している。Java 界隈なら当たり前のように見かけるのだけど TypeScript ではどうなんだろう……。

感想。

beater 0.4.0 の使い勝手は上々。API は変更されているものの 0.3.0 とほとんど差を感じなかった。browser のほうは試せていないし、怪しいけれど……。

TimeKeeper.js については実用の中で洗練していきたい。