Forum: Ruby-core DateTime.strptime() doesn't work correctly for '%s %z'

B11f10c4cd9d53970e7be20caa43f940?d=identicon&s=25 unknown (Guest)
on 2014-05-03 15:01
(Received via mailing list)
Issue #9794 has been updated by Akira Tanaka.


tadayoshi funaba wrote:
>
> 伝わらないのでちょっと別の話をします。
>
> Date.today.ctime #=> "Sat May  3 00:00:00 2014"
>
> これは普通の日付ですよね。

はい。

> これの Sat を Fri 書き換えると間違った日付です。

はい。
"Fri May  3 00:00:00 2014" に書き換えると確かに間違っています。

> たしか、php のライブラリだったと思うけど、こういうのを入力すると
> 2014-05-02 とか 2014-05-09 なんかが返ってくるものがありました。
> これはもう日付というよりコマンド言語みたいなもんですよね。

曜日と年月日は独立ではないので、
片方を設定するともう一方も変化してしまう破壊的操作の列で設定を行うことをコマンド言語と表現しているのですよね。
これはわかります。

> 田中さんの説明からも '%s %z' はそういう部類という事だと思います。

曜日と年月日とは異なり、%s と %z は独立なので問題ないと思います。
ここで独立というのは直交しているという意味で、片方を変えてももう一方は変わりません。

Time.at(s).getlocal(z) から to_i メソッドで s を取り出せますし、
Time.at(s).getlocal(z).utc_offset で z を取り出せます。
つまり Time オブジェクトは s と z を両方そのまま中に持っています。

曜日と年月日は独立でないので両方を指定すると正しくない日付を表現できてしまいますが、
%s (1970-01-01T00:00:00Z からの秒数) と %z (UTC からの時差) は独立で、
両方を任意に指定しても正しくない日付にはなりません。
つまり、曜日と年月日のような問題は起きません。

> 俺は strptime でも parse でもそういうのは避けてました。
> とくに strptime ではやったらいけないと思ってます。

上記に書いたように、"%s %z" がそういうの(曜日と年月日のようなもの)だとは思いません。

> 田中さんは日付それ自体を見てないんじゃないでしょうか。
> 逆転してると思いますが、日付オブジェクトの外部表現が日付だと思ってるのでは。

日付それ自体といわれてもふなばさんがいう日付というものががわかりません。
すでに書いたように、私は日付と言われると、時分秒が含まれていない情報のように感じられます。
Time や DateTime はそうではないので、そういう情報ではないのと思うのですが、では何かというのはわかりません。

Time や DateTime がなにを示しているかとか、そういうレベルの認識が食い違っているという気はするので、
日付とはなにかとか、そういうことをもうすこし詳しく述べていただけると、理解が可能になるのかもしれません。

> 時差に特別な意味があると思えば地方時で記述すればいいと思います。

どこの地方時かというのが問題で、OS に設定された地方時じゃなくて、
UTC からの時差が固定されている人工的な地方時を選んだほうが、
与えられた時差をそのまま記録できる、という話だと理解しています。

> ていうか今しがた知ったという感じですが。
> とくかくバグだから直せって話しか聞いた覚えがありません。

検索してみると、最初に述べているのは ruby-core:57503 かなぁ。
最近だと ruby-talk:414950 の冒頭でしょうか。



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

* 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)
This topic is locked and can not be replied to.