Time::Piece に関するとりとめのないコト

1. `Time::Piece->strptime()` で返されるオブジェクトは GMT
2. `Time::Piece->strptime()` では1899年以前の日付は解釈できない
3. `gmtime->strftime('%Z')` は，オブジェクトが GMT であるにもかかわらず，`localtime` のタイムゾーン名を返す (`%z` も同様) ⇒ **追記** そのうち治りそう (2015-04-10)
4. `Time::Piece` のオブジェクトは，自身が `localtime` か `gmtime` であるかのフラグを持っている。だがタイムゾーンはもっていない。(`#tzoffset` は呼び出される度に算出する)

## `Time::Piece->strptime()` で返される値は GMT

```perl
use Time::Piece;

Time::Piece->strptime('2013-11-03 12:34:56', '%Y-%m-%d %H:%M:%S')->strftime;
# => 日, 03 11月 2013 12:34:56 UTC
```

これは `%z` 等でタイムゾーンを解釈させても，かわらない。

```perl
Time::Piece->strptime('2013-11-03 +0900', '%Y-%m-%d %z')->strftime;
# => 土, 02 11月 2013 15:00:00 UTC
```

## `Time::Piece->strptime()` では1899年以前の日付は解釈できない

```perl
Time::Piece->strptime('1868-10-23', '%Y-%m-%d');
# => Error parsing time at ...
```

どうしてこうなるのかは [Time::Piece の Parse.xs の _strptime()](https://metacpan.org/source/RJBS/Time-Piece-1.23/Piece.xs#L861) でも読んでください。

なお `Time::Piece` オブジェクトが1899年以前を表象できないわけではない。

```perl
use Time::Piece;
use Time::Local;

$t = Time::Local::timelocal(0,0,0, 23, 10-1, 1868);
# => -3193291139

localtime($t)->strftime;
# => 金, 23 10月 1868 00:00:00 JST
```

`Time::Local` は `Time::Local` で西暦999年以前を設定できないという点もあるのだけれど。そのへんは perldoc でもみてください。

## `gmtime->strftime('%Z')` は，オブジェクトが GMT であるにもかかわらず，`localtime` のタイムゾーン名を返す (`%z` も同様)

```perl
localtime->strftime('%z %Z');
# => +0900 JST
gmtime->strftime('%z %Z');
# => +0900 JST
```

これはバグだと思うので，一応 Pull Request はだしてある。

**追記** (2015-04-10) 1.29_03 で取り込まれたので 1.30 以降では治るかな？ https://github.com/rjbs/Time-Piece/commit/ecc37f3ec3b03a917076f474d3c4c64640384b01

ちなみに C の `strftime()` はきちんと `localtime` と `gmtime` で `%z` の出力をだしわける。

```c
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
    char buf[1024];
    time_t t = time(NULL);

    strftime(buf, 1024, "%z; %Z; %c\n", localtime(&t));
    puts(buf);  /* => +0900; JST; Sun Nov  3 17:42:42 2013 */

    strftime(buf, 1024, "%z; %Z; %c\n", gmtime(&t));
    puts(buf);  /* => +0000; GMT; Sun Nov  3 08:42:42 2013 */

    return 0;
}
```

`Time::Piece#strftime` の出力がおかしい原因としては Perl のソースの `Util.c` で定義されている `init_tm()` が `localtime` で得られる結果をコピーしており，`Time::Piece#strftime` ではその `init_tm()` を使って作成した構造体を C の `strftime()` にわたしているからである。
なので Pull Request はわりと adhoc な解決策になっている。

## `Time::Piece` のオブジェクトは，自身が `localtime` か `gmtime` であるかのフラグを持っている。だがタイムゾーンはもっていない。(`#tzoffset` は呼び出される度に算出する)

フラグ (`c_islocal`) については以下の通り。

```perl
use Time::Piece;
use Data::Dumper;

say Data::Dumper->new([ scalar localtime ])
        ->Indent(1)->Terse(1)->Useqq(1)->Dump();
# => bless( [
#   33,                 # c_sec
#   9,                  # c_min
#   18,                 # c_hour
#   3,                  # c_mday
#   10,                 # c_mon
#   113,                # c_year
#   0,                  # c_wday
#   306,                # c_yday
#   0,                  # c_isdst
#   "1383469773",       # c_epoch
#   1                   # c_islocal
# ], 'Time::Piece' )
```

いくつかの `Time::Piece` のメソッドは，このフラグをみて挙動をかえている。

`Time::Piece::c_islocal` 定数を使って，このフラグにアクセスすることができる (が，推奨されない，と思う)。

```perl
use Time::Piece;

my $lt = localtime;
$lt->[Time::Piece::c_islocal];  # => 1
my $gt = gmtime;
$gt->[Time::Piece::c_islocal];  # => 0
```

ちなみに，BSD や glibc の `struct tm` は，`islocal` のようなフラグのかわりに，`UTC` からのオフセットとタイムゾーンの文字列を保持している。`Time::Piece` もそのようになっていたら便利だったのに……

```c
/* time.h from GNU C Library */
/* ...... snip snip snip ...... */

struct tm
{
  int tm_sec;                   /* Seconds.     [0-60] (1 leap second) */
  int tm_min;                   /* Minutes.     [0-59] */
  int tm_hour;                  /* Hours.       [0-23] */
  int tm_mday;                  /* Day.         [1-31] */
  int tm_mon;                   /* Month.       [0-11] */
  int tm_year;                  /* Year - 1900.  */
  int tm_wday;                  /* Day of week. [0-6] */
  int tm_yday;                  /* Days in year.[0-365] */
  int tm_isdst;                 /* DST.         [-1/0/1]*/

#ifdef  __USE_BSD
  long int tm_gmtoff;           /* Seconds east of UTC.  */
  __const char *tm_zone;        /* Timezone abbreviation.  */
#else
  long int __tm_gmtoff;         /* Seconds east of UTC.  */
  __const char *__tm_zone;      /* Timezone abbreviation.  */
#endif
};

/* ...... snip snip snip ...... */
```

`Time::Piece` では，`#tzoffset` (`GMT` の場合は常に 0) の呼び出しごとに `GMT` との差分を算出している。つまり，`Time::Piece` オブジェクトが生成された時点の `TZ` ではなく，`#tzoffset` を呼び出した時点での `TZ` をもとに差分を算出するので，(状況によっては) 注意が必要である。

タイムゾーン，オフセットを保持していないので，(複数箇所のタイムゾーンの時刻オブジェクトを利用するケースにおいて) そのようなものを内包する日時コンテナオブジェクトとして扱ったりシリアライズに使ったりするには不適当である。

(もちろん，実質 local time しか扱わないアプリケーションにおいては，十分な要件をみたしている)