Issue #9794 has been updated by Akira Tanaka.


tadayoshi funaba wrote:
> 
> 問題があるとかでなく、別のものなってるという事です。
> たとえば、可能性としては、UTCで書いた日付を地方時にという事も出来るという事ですよね。
> 今回 %s だけですが。

ちゃんと定義すればそういうことも可能なんじゃないかと思います。
年月日時分秒が2つ出てくるのでわかりにくいとは思いますが。

> 俺は今、日本にいてUTCの時刻を扱っているとします。
> それを例えば以下のように記述する事にします。
> 与えられた時刻はUTCだけど、それを +09:00 で参照する事にします。
> 
> 2001-02-03T04:05:06 UTC (+0900)
> 
> 一般的でないので、
> `DateTime.parse('2001-02-03T04:05:06 UTC').new_offset('+0900')`
> といったような操作で説明する事になります。

後で出てくる時間軸の話でいえば、
ISO 8601 でいえば 2001-02-03T04:05:06Z という名前をもつ時間軸上の点に
2001-02-03T04:05:06 UTC (+0900) という名前をつけるということですよね。

そして、その名前を DateTime に変換する場合には
DateTime.parse('2001-02-03T04:05:06 UTC').new_offset('+0900') で生成されるオブジェクトに対応させるということですよね。

> 今現在このような記述は ruby ではないですが、'%s %z' の件で求められているのは、俺からするとこういうものを含む、これまで扱っていたものとは別のものだと感じています。

時間軸上の点に名前をつけて、それを DateTime オブジェクトに対応させるというレベルでいえば、
とくにこれまで扱っていたものと違いがあるようには思えません。

> 俺が日付と言ってるのはそういう時刻も含まれてます。
> この日付というのはある規則に基づいて時間軸上に振られた名前のようなものだと思っています。空間に置き換えるとマイルストーンのようなものです。
> 実際にはもっと不完全な日付もあって、それも日付です。
> 文脈やその他の情報から特定できる場合もあるし、出来ない事もあります。

なるほど。
時間軸上の点に名前があるというわけですね。
この考え方は私の考え方と一致します。

「名前のようなもの」という表現についてはちょっと確信が持てないのですが、
日付というのは名前も含んでいるものだと推測しました。
まちがっていたら指摘してください。

私は時間軸上の点を時刻と呼んでいます。
名前については、(昨日書いたものを読み直すと) 点を名前に変換する規則を時刻の形式とか表現方法と呼んでいます。

時間軸上の点の具体例として Unix Epoch についていえば、たくさんの表現 (名前) を持つわけですよね。
例えば以下が考えられると思います。
* ISO 8601 で Z を使えば 1970-01-01T00:00:00Z
* ISO 8601 で +09:00 を使えば 1970-01-01T09:00:00+09:00
* ISO 8601 で -08:00 を使えば 1969-12-31T16:00:00-08:00
* RFC 2822 で +0000 を使えば Thu, 01 Jan 1970 00:00:00 +0000
* RFC 2822 で +0900 を使えば Thu, 01 Jan 1970 09:00:00 +0900
* RFC 2822 で -0800 を使えば Wed, 31 Dec 1969 16:00:00 -0800
* Unix Epoch からの秒数でいえば 0
* ユリウス日でいえば 2440587.5

これらを Time や DateTime オブジェクトとして表現すれば、
どれも == メソッドの意味で等しいオブジェクトになるわけですが、
他のメソッドの挙動はこれらの中でも異なるかもしれません。

例えば、
1970-01-01T00:00:00Z を Time オブジェクトにして hour メソッドを呼び出せば 0 になり、
1970-01-01T09:00:00+09:00 を Time オブジェクトにして hour メソッドを呼び出せば 9 になる、
という挙動はおかしくはありません。

また、
1970-01-01T00:00:00Z を Time オブジェクトにして utc_offset メソッドを呼び出せば 0 になり、
1970-01-01T09:00:00+09:00 を Time オブジェクトにして utc_offset メソッドを呼び出せば 32400 になる、
という挙動はおかしくはありません。

オブジェクトを生成するときにはそのような異なり方も決定する必要があります。
この異なり方というのは Time については UTC, OSに設定された地方時、固定時差、のどれかを選び、
固定時差の場合にはさらに時差 (UTC からの時差) の値を選ぶ、ということです。
この選択肢は Time が現在提供しているものがそうだという話で、過去には固定時差はありませんでしたし、
未来にはまた変わるかもしれません。

DateTime には異なり方について DateTime なりの選択肢があるでしょう。

ここで、Unix Epoch からの秒数やユリウス日はこの異なり方の選択肢をどう選ぶべきか自明ではありません。
たとえば、ユリウス日の 2440587.5 を Time オブジェクトにして hour メソッドを呼び出したとき、
結果はどうなるべきでしょうか。0 か、12 か、あるいは他の値でしょうか。
少なくとも自明でないのは確かだと思います。

逆にいえば、どう選ぶかという規則はアプリケーションを書く人がわかって指定する限り
比較的自由に作っても問題ないんじゃないでしょうか。

%s %z は、Time オブジェクトにしたときに、
入力に含まれている時差を utc_offset メソッドが返してくれるように選ぶという話で、
まぁいいんじゃないの、と思うわけです。

> > > 時差に特別な意味があると思えば地方時で記述すればいいと思います。
> > 
> > どこの地方時かというのが問題で、OS に設定された地方時じゃなくて、
> > UTC からの時差が固定されている人工的な地方時を選んだほうが、
> > 与えられた時差をそのまま記録できる、という話だと理解しています。
> 
> ちょっと意味が判りませんでした。

%s %z で Time オブジェクトを生成するときに、
入力に含まれている時差を utc_offset メソッドで取り出せるようにするために、
固定時差を選ぶという意味です。

> %s がそもそも不完全と思えるので、なぜこんなに拘るのはわかりません。
> 
> %s を空間に置き換えてみると、これでマイルストーンは置けず、ただ距離が示されているだけ、距離の定義がわかない状態ではないですか。

時間軸には Unix Epoch (1970-01-01T00:00:00Z) という原点を定義して、
そこからの相対距離ですから、時間軸上の点を同定するのに問題はないと思います。
閏秒の話を無視すれば、ですが。

ユリウス日だって時間軸に紀元前4713年1月1日という原点を定義して、
そこからの相対距離ですから、たいした違いはないでしょう。

閏秒の話を無視すれば、問題なく定義されていると思います。

> あと、ついでなので、田中さんが固定時差と言ってるものも万能でない事は確認しておきたいです。
> 
> 与えられた自明の地方時も有用で、時差ではなくタイムゾーン=時間帯の情報は
> 単なる時差以上の情報を含んでいます。
> 
> 夏時間など実際に我々が参照している時系と形式は重要じゃないですか。

はい。それは承知しています。

タイムゾーンはひとつの時差ではなく時差の時系列変化ですよね。
(あと JST などの略称も入っていますが)

Time オブジェクトを固定時差で生成した場合、Time#+ などでその時刻から違う時刻を求めた場合に
正しいタイムゾーンを使った場合と固定時差の違いが出てきます。
とくに夏時間がある場合には違いが発生しやすいはずです。

ただ、タイムゾーンを正しく扱うにはタイムゾーンデータベースを扱わないといけないので、
これはこれで保守などの問題が出てきます。

その問題を避けつつ、使いやすくしたい、という努力には意味があると思っています。

> そういう意味も含めて、%s 偏重の流れに違和感を感じます。

べつに %s を偏重といわれるほど勧めたいとは思っていません。
私としては閏秒の問題が大きいと思います。



----------------------------------------
Bug #9794: DateTime.strptime() doesn't work correctly for '%s %z'
https://bugs.ruby-lang.org/issues/9794#change-46493

* Author: Felipe Contreras
* Status: Rejected
* Priority: Low
* Assignee: tadayoshi funaba
* Category: ext
* Target version: 
* ruby -v: 2.1.1p76
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN
----------------------------------------
Time.strptime() works correctly:

    Time.strptime('0 +0100', '%s %z').strftime('%s %z')
    => "0 +0100"

But DateTime.strptime() doesn't:

    DateTime.strptime('0 +0100', '%s %z').strftime('%s %z')
    => "0 +0000"

In Rubinious it does work correctly:

    DateTime.strptime('0 +0100', '%s %z').strftime('%s %z')
    => "0 +0100"

This make the RubySL date space fail:

    DateTime#strptime parses seconds and timezone correctly FAILED
    Expected "1970-01-01T00:00:00+00:00"
     to equal "1970-01-01T01:00:00+01:00"

In addition, both C and perl preserver the offset correctly when doing '%s %z'.

So it's very clear DateTime.strptime() has to be fixed.

Patch attached.

---Files--------------------------------
0001-datetime-fix-strptime-s-z.patch (1.94 KB)


-- 
https://bugs.ruby-lang.org/