fixedpoint.jp


ケーススタディ: Calendar spans in pdf-devel (2008-05-19)

今回のケーススタディは先週 GNU PDF の開発メーリングリストで話題になったカレンダーの計算についてです。

開発者の1人 Aleksander が libgnupdf の Time Module の time span の扱いについて質問を投げました。ここでいう time span とは、ある日時から別の日時までの間隔のことです: http://lists.gnu.org/archive/html/pdf-devel/2008-05/msg00013.html

彼は年や月や日などの複数の単位をもつ形式で time span を扱うことに疑問を感じていたのです。この形式に従うと、例えば「1 month + 2 day」という time span が表現できます。このメールに対し project lead の Jose E. Marchesi がそういった単位で行うカレンダーの計算が有用であること、また技術的な提案を返します:

これに対し Aleksander の疑問が具体的な問題として述べられます; 年や月を単位にする形で time span が与えられた場合、ある日付にその time span を足した結果に予期せぬ曖昧さが生じるということです: http://lists.gnu.org/archive/html/pdf-devel/2008-05/msg00030.html

Well... don't really like it. This means that there are three different time origins for which the 
calendar time span gives the same result... isn't it?

29 January 2007 + (1 year + 1 month) = 29 February 2008
30 January 2007 + (1 year + 1 month) = 29 February 2008
31 January 2007 + (1 year + 1 month) = 29 February 2008

これに対し Stuart Jansen が良い解決策を出します; 既にこの問題を解決している Perl DateTime module がどうやっているか調べればよいというのです: http://lists.gnu.org/archive/html/pdf-devel/2008-05/msg00031.html

実際に Perl DateTime が採用している time span の足し算はうまく機能します: http://search.cpan.org/dist/DateTime/lib/DateTime.pm#Adding_a_Duration_to_a_Datetime

DateTime.pm always adds (or subtracts) days, then months, minutes, and then seconds and 
nanoseconds. If there are any boundary overflows, these are normalized at each step. For the days 
and months (the calendar) the local (not UTC) values are used. For minutes and seconds, the local 
values are used. This generally just works.

This means that adding one month and one day to February 28, 2003 will produce the date April 1, 
2003, not March 29, 2003.

このケーススタディの教訓として、

新しいライブラリを設計するときに直面する問題を解決するには、過去にうまく設計されたライブラリがどのように解決しているかを調べることが効果的である

ということができます。(こう書くと当たり前に思えますが ...)

ところで、この time span の足し算に関わる他のライブラリはどう対処しているのでしょうか?

Scheme には時刻や日付を扱うライブラリとして SRFI-19 があります。time span を表すために time duration オブジェクトが定義されています。そして time オブジェクトに対して time duration オブジェクトを足して time オブジェクトを得る add-duration という手続きが用意されています。

この手続きには上の問題は生じません。なぜなら、time duration オブジェクトは

のいずれかでしか得られず、これらは結局秒およびナノ秒の情報しか持っていないからです。add-duration での計算は与えられた時刻にこれらの秒およびナノ秒を足すことそのものです。

問題を回避できるのは嬉しいのですが、これは ISO 8601 の duration (年や月や日などの複数の単位を使える!)として指定する値を扱っているとは言えません。


© 2006-2023 fixedpoint.jp