Feature #9794

DateTime.strptime() doesn't work correctly for '%s %z'

Added by Felipe Contreras 10 months ago. Updated 6 months ago.

[ruby-core:62286]
Status:Closed
Priority:Low
Assignee:tadayoshi funaba

Description

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.

0001-datetime-fix-strptime-s-z.patch Magnifier - Fix (1.94 KB) Felipe Contreras, 05/02/2014 10:20 AM


Related issues

Related to Ruby trunk - Bug #7445: strptime('%s %z') doesn't work Rejected 11/27/2012

History

#1 Updated by tadayoshi funaba 10 months ago

  • Category changed from core to ext
  • Status changed from Open to Assigned
  • Assignee set to tadayoshi funaba
  • Priority changed from Normal to Low

#2 Updated by tadayoshi funaba 10 months ago

  • Related to Bug #7445: strptime('%s %z') doesn't work added

#3 Updated by tadayoshi funaba 10 months ago

  • Status changed from Assigned to Rejected

identical to 7445.

#4 Updated by Felipe Contreras 10 months ago

Tadayoshi you are so fucking ridiculous it's not even funny.

You reject a perfectly sensible patch that EVERYBODY agrees with for NO REASON AT ALL WHATSOEVER? At the very list give a reason.

I'm amazed that anybody would make you a maintainer of anything. It's because of attitudes like this that I'm not surprised that the Ruby language has trouble competing with languages like Python; you just have a nonsensical culture.

I am still waiting for A REASON.

#5 Updated by tadayoshi funaba 10 months ago

何回も言うけどCで自分の意図どおりに扱えてるっていうあんたの主張は間違ってる。
ある実装では構文的に解析出来てるかもしれないけど、意味を解釈する事は仕様上無理なんだよ。どう解釈しても。
あんたは都合よく仕様の話と実装の話をつなげて自分の主張にしてるだけなの。
俺はそれなりに妥当な解釈で拡張してるわけでバグだから直せと頭ごなしに言われる筋合いはない。

time に従えって言いたいのかもしれないけど、現状はこんなんなんだけど

Time.strptime('0 -0900', '%s %z')
#=> 1969-12-31 15:00:00 -0900

Time.strptime('2001 -0900', '%Y %z')
#=> 2001-01-01 18:00:00 +0900

判るかな?
なんでこんな事になったのか知らないけど、DateTime はこれに従えない。
もう来るな。

#6 Updated by Felipe Contreras 10 months ago

English. This is an international project, isn't it?

Time.strptime('2001 -0900', '%Y %z')

This is clearly a red herring. If you want to fix '%Y %z', go ahead, that's no reason not to fix '%s %z'.

#7 Updated by Eric Hodel 10 months ago

Felipe, your extreme rudeness has no place here.

The rejection reason is described in #7445 as linked.

Not every committer is proficient in English so Japanese is just fine.

I don't suspect you'll get a reason.

#8 Updated by Ryan Davis 10 months ago

  • Status changed from Rejected to Feedback

Felipe's rudeness, while not acceptable, is borne out of frustration. I suspect that frustration exists on both sides of this argument. Setting that aside for a moment, and evaluating only the facts stated (and not the tone) in [[[https://bugs.ruby-lang.org/issues/7445#note-16]]] , it seems to me that this is a valid bug. The doco on DateTime.strptime even reference the manpage for the C function, which states:

The resulting values will be relative to the local time zone. Thus, it can be considered the reverse operation of strftime(3).

Yet it doesn't act like the C function (or 4 other related implementations!) in this particular edge case.

I've reviewed (but not tested) Charlie Somerville's patch and it looks good to me. I'd like to see this escalated to a neutral 3rd party (matz? ko1?) that can evaluate Charlie's code and weigh it against tadf's Japanese argument. Regardless of any final outcome, adding an English explanation would help to ease the tension and close this issue for good.

#9 Updated by Felipe Contreras 10 months ago

Ryan Davis wrote:

I'd like to see this escalated to a neutral 3rd party (matz? ko1?) that can evaluate Charlie's code and weigh it against tadf's Japanese argument. Regardless of any final outcome, adding an English explanation would help to ease the tension and close this issue for good.

matz replied on the mailing list, but I don't think the arguments are valid, and I've replied with my counter-arguments:

http://article.gmane.org/gmane.comp.lang.ruby.general/371471

Feel free to weight in, but I think this issue is as clear as day if you read that.

#10 Updated by tadayoshi funaba 10 months ago

言語の問題もあるんだろうけど、俺が英語に堪能でも Felipe Contreras に俺の考えを解らせるのは無理じゃないかという気がする。

誤解のないよう少し補足しておくと、strcut tm で %s や %z を表現できない、という直接的な問題でもない。
C の時刻関数群はオブジェクト指向では書かれてないけど、データや関数の集合によってどんなモノを表現しているのか
考えないと理解できない。C の時刻関数には、まず、地方時 (あるいは局所時) と世界時の区別しかなく、
基本的に地方時は与えられるもので自分では選べない。選べないという事は、strptime に与えて仮に形式的に受けつけたとしても
仕様に従えば、mktime (自明の地方時) や gmtime (世界時) ではそれを使う事ができないという事になる。
それに、%z に対応するメンバーがあっても、普通は %s に対応するものがない、
だから %s は年月日などにデコードされるが、
これも自明な地方時か世界時しか選択肢がない。時差を持っていても矛盾が生じてしまう。
これは https://bugs.ruby-lang.org/issues/7445#note-12 ですでに書いた。

そもそも %s は可搬性に乏しい (存在しない実装もあるだろうし、閏秒の挿入の課題がある)。
環境によっては、ruby の Time と DateTime でも結果に相違が出る。そういうものです。

これまでにも「オレのアプリケーションで使っている日付をサポートしろ」という要求は
何度もありました (最近はないが直接メールしてくる奴もいる)。
いくつか受け入れたものもありますが、そういうの一々受け入れていこうとはまったく思っていません。

俺は strptime が完璧だとは思ってないし、偏見の塊かもしれないと思っている。
田中さんなんかはそういう割切り方に自信があって、なおかつダメなものは諦めるしないと思っているのかもしれないけど、
俺の場合、少なくとも strptime については次善の策を用意しておいた。
_strptime は lib/time.rb に使って貰う為に用意したわけではない。
strptime でダメでも _strptime を叩いてどうにかなるかもしれない。
今回の件は明かに何とかなるでしょ。

'%s %z' はそれ自体おかしいと思うし、既に何度も述べているように、まるでお勧めできない。

その程度のものに原則を曲げて敢て対応する必要はないと思ってます。

大騒ぎすれば言う事を聞くと思ってるかもしれないけど、大間違いです。

#11 Updated by tadayoshi funaba 10 months ago

  • Status changed from Feedback to Rejected

#12 Updated by Akira Tanaka 10 months ago

tadayoshi funaba wrote:

言語の問題もあるんだろうけど、俺が英語に堪能でも Felipe Contreras に俺の考えを解らせるのは無理じゃないかという気がする。

私も "%s %z" がなんでそんなにいけないのか理解していません。

誤解のないよう少し補足しておくと、strcut tm で %s や %z を表現できない、という直接的な問題でもない。
C の時刻関数群はオブジェクト指向では書かれてないけど、データや関数の集合によってどんなモノを表現しているのか
考えないと理解できない。C の時刻関数には、まず、地方時 (あるいは局所時) と世界時の区別しかなく、
基本的に地方時は与えられるもので自分では選べない。選べないという事は、strptime に与えて仮に形式的に受けつけたとしても
仕様に従えば、mktime (自明の地方時) や gmtime (世界時) ではそれを使う事ができないという事になる。
それに、%z に対応するメンバーがあっても、普通は %s に対応するものがない、
だから %s は年月日などにデコードされるが、
これも自明な地方時か世界時しか選択肢がない。時差を持っていても矛盾が生じてしまう。
これは https://bugs.ruby-lang.org/issues/7445#note-12 ですでに書いた。

Ruby の strptime は struct tm じゃなくて DateTime や Time のオブジェクトを生成し、
DateTime や Time のオブジェクトは自分がどんなモノなのかを自分自身で把握しているため、
"%s %z" についてはこのへんの問題は避けられるように思っています。

%s と %z に対応する値を s と z として、
Time.at(s).getlocal(z) とするのがそれほどおかしいことだとは思っていません。

そもそも %s は可搬性に乏しい (存在しない実装もあるだろうし、閏秒の挿入の課題がある)。
環境によっては、ruby の Time と DateTime でも結果に相違が出る。そういうものです。

閏秒については同意します。
その点があるので私もおすすめはしません。

%s が存在しない実装、ということについては、どういう意味かわかりません。
今の Ruby 本体は C の strptime() も strftime() も使っていません。
勘違いしていなければ、ext/date も使っていないように思います。
そのため環境に依存する部分はないように思います。

なお、strftime() を使わなくなったのは以下の変更からです。

Thu Aug 21 00:20:05 2008  Shugo Maeda  <shugo@ruby-lang.org>

        * strftime.c: new file.

        * common.mk (COMMONOBJS): added strftime.$(OBJEXT).

        * time.c (time_strftime): do not use strftime(3).  supported
          %L(millisecond) and %N(nanosecond).

        * test/ruby/test_time.rb: added tests for %L and %N.

この変更の理由は struct tm が小数点以下の秒を表現できないので %L や %N をサポートできないから、
というものですが、このときに %s の値も直接渡すようにもなっています。

俺は strptime が完璧だとは思ってないし、偏見の塊かもしれないと思っている。
田中さんなんかはそういう割切り方に自信があって、なおかつダメなものは諦めるしないと思っているのかもしれないけど、
俺の場合、少なくとも strptime については次善の策を用意しておいた。
_strptime は lib/time.rb に使って貰う為に用意したわけではない。
strptime でダメでも _strptime を叩いてどうにかなるかもしれない。
今回の件は明かに何とかなるでしょ。

ふなばさんはわかっているような気もするのですが、lib/time.rb の strptime と私との関係について、
知らない人も多いような気がするのでいちおう書いておきますと、
lib/time.rb に strptime を足したのはまつもとさんです。
その時点で意見や判断を求められたことはなく、関わっていません。

Fri Mar  4 08:09:12 2005  Yukihiro Matsumoto  <matz@ruby-lang.org>

        * lib/time.rb (Time::strptime): add new function.  inspired by
          [ruby-talk: 132815].

        * lib/parsedate.rb (ParseDate::strptime): ditto.

その後で私も実装をいじっていたりもするので、まったく関係ないとまではいえないのですが。

#13 Updated by tadayoshi funaba 10 months ago

Akira Tanaka wrote:

tadayoshi funaba wrote:

言語の問題もあるんだろうけど、俺が英語に堪能でも Felipe Contreras に俺の考えを解らせるのは無理じゃないかという気がする。

私も "%s %z" がなんでそんなにいけないのか理解していません。

日付としておかしいからです。

Ruby の strptime は struct tm じゃなくて DateTime や Time のオブジェクトを生成し、
DateTime や Time のオブジェクトは自分がどんなモノなのかを自分自身で把握しているため、
"%s %z" についてはこのへんの問題は避けられるように思っています。

主張の根拠になっているのがバグだから直せだからです。
ruby 側の都合の話ではありません。

%s と %z に対応する値を s と z として、
Time.at(s).getlocal(z) とするのがそれほどおかしいことだとは思っていません。

このあたりは誰かが言うと思っていました。
結局、'%s %z' は日付ではなくて、日付オブジェクトだと思えば、
ちょっと納得しそうになるものなんだと思います。
それと対称性を示せば、かなり多くの人を説得できるのかもしれません。

でも俺からすると日付としてやっぱりおかしいと思います。
オブジェクトの操作ではなくあくまで日付だと思うので。
逆にこれを導入しなければならない強い動機が俺にはわかりません。

%s が存在しない実装、ということについては、どういう意味かわかりません。
今の Ruby 本体は C の strptime() も strftime() も使っていません。
勘違いしていなければ、ext/date も使っていないように思います。
そのため環境に依存する部分はないように思います。

%s が存在しないというのは ruby の事ではなくて、他の処理系の事です。
'%s %z' が使えて当たり前というのが彼の考えのようですから。

ふなばさんはわかっているような気もするのですが、lib/time.rb の strptime と私との関係について、
知らない人も多いような気がするのでいちおう書いておきますと、
lib/time.rb に strptime を足したのはまつもとさんです。
その時点で意見や判断を求められたことはなく、関わっていません。

誤解されているようですが、別に lib/time.rb が使うのがダメという事ではありません。
使ってる事に文句を言ってのではなく、単に第一義的にはユーザーが使うものとして用意したという事です。
俺としてはまさにこういう時の為に _strptime はあると思っていますが。
まったく意図していなかった流れですが、まつもとさんが入れたのは言われて思い出しました。

逆に俺からすると、Time.strptime が互換性、統一性を捨てたのがかなり疑問です。
俺は元に戻す事を提案しておきます。

#14 Updated by Felipe Contreras 10 months ago

At some point it would be nice to have something in English so that the international community can comment on that.

#15 Updated by Akira Tanaka 10 months ago

tadayoshi funaba wrote:

日付としておかしいからです。

おかしい、というのはどういう意味でしょう?

たしかに "%s %z" は人間が日常的に扱う形式ではありません。
でも、%s が過去から未来への流れの中の 1点を指定し、
%z がその 1点の表現方法を UTC からの offset という形でを指定する、
という時刻の形式だと解釈できると思います。

時刻の表現として、(閏秒の話を除いて) とくに問題があるとは思えません。

それとも日付という言葉に私が感じる以上の意味があるのでしょうか。
日付というと私は時分秒が入っていないように感じられて、
Time や DateTime とは違う感じがするのですが、日付という言葉を選んだことに何か深い意味があるのでしょうか。

%s と %z に対応する値を s と z として、
Time.at(s).getlocal(z) とするのがそれほどおかしいことだとは思っていません。

このあたりは誰かが言うと思っていました。
結局、'%s %z' は日付ではなくて、日付オブジェクトだと思えば、
ちょっと納得しそうになるものなんだと思います。
それと対称性を示せば、かなり多くの人を説得できるのかもしれません。

でも俺からすると日付としてやっぱりおかしいと思います。
オブジェクトの操作ではなくあくまで日付だと思うので。

ここでいう日付と日付オブジェクトの違いがよくわからないのですが、
もしかすると、"%s %z" をオブジェクトを生成・改変する操作の列とみなすという意味でしょうか。

もしそうだとすると、私はそのようには考えていません。
%s と %z が示す情報は独立なものだと考えています。

上の繰り返しになってしまうのですが、以下のように考えています。
* %s は過去から未来への流れの中の 1点を指定する
* %z はその 1点の表現方法を指定する

%s と %z は独立なので、矛盾なく組み合わせることが可能です。

もちろん、Time オブジェクトを生成するには表現方法を決めないといけないので、
Time.at は地方時を選択し、getlocal はそれを z で指定された方法に変えるわけですが、
それは Time.at が表現方法を指定する引数を持っていないからという以上の意味はありません。

逆にこれを導入しなければならない強い動機が俺にはわかりません。

git で使われているからという動機は述べられているんじゃないでしょうか。

逆に俺からすると、Time.strptime が互換性、統一性を捨てたのがかなり疑問です。
俺は元に戻す事を提案しておきます。

ここでいう互換性、統一性とはなんでしょう?
また、元というのはどの段階でしょう?

#16 Updated by tadayoshi funaba 10 months ago

Akira Tanaka wrote:

tadayoshi funaba wrote:

日付としておかしいからです。

おかしい、というのはどういう意味でしょう?

たしかに "%s %z" は人間が日常的に扱う形式ではありません。
でも、%s が過去から未来への流れの中の 1点を指定し、
%z がその 1点の表現方法を UTC からの offset という形でを指定する、
という時刻の形式だと解釈できると思います。

見慣れないという意味ではないです。ユリウス日のようなものも日付だと思ってますし、%s 単体では特に問題に思っていません。

全然理解できないのですが、%s に時差って意味ないですよね。
田中さんはそこにオブジェクトを見てるから不自然とは感じないという事ですかね。

もしそうだとすると、私はそのようには考えていません。
%s と %z が示す情報は独立なものだと考えています。

上の繰り返しになってしまうのですが、以下のように考えています。
* %s は過去から未来への流れの中の 1点を指定する
* %z はその 1点の表現方法を指定する

やっぱりおかしいですね。%s の表現方法は繰り返しですが %s です。
日付じゃなくて、オブジェクトの操作ですよね。

逆にこれを導入しなければならない強い動機が俺にはわかりません。

git で使われているからという動機は述べられているんじゃないでしょうか。

git に従う理由がありません。しかも ruby でそれが表現できないわけでも
解析できないわけでもありません。

逆に俺からすると、Time.strptime が互換性、統一性を捨てたのがかなり疑問です。
俺は元に戻す事を提案しておきます。

ここでいう互換性、統一性とはなんでしょう?
また、元というのはどの段階でしょう?

Time.strptime('0 -0200', '%s %z')
#=> 1969-12-31 22:00:00 -0200
Time.strptime('20010203 -0200', '%Y%m%d %z')
#=> 2001-02-03 11:00:00 +0900

明らかに統一性がないと思います。
以前は %s も含めて時差はすべて無視されていました。
これは Time の元からの仕様なので気にしていませんでしが、
今はおかしな事になっていると思います。

#17 Updated by Akira Tanaka 10 months ago

tadayoshi funaba wrote:

見慣れないという意味ではないです。ユリウス日のようなものも日付だと思ってますし、%s 単体では特に問題に思っていません。

全然理解できないのですが、%s に時差って意味ないですよね。

%s に UTC からの時差の情報が入っていないことに同意します。

しかし、Time オブジェクトを作るには時差 (あるいは地方時、UTC) を選ばないといけないので、
%z の情報を使ってもいいと思います。

田中さんはそこにオブジェクトを見てるから不自然とは感じないという事ですかね。

「そこにオブジェクトを見てる」というのがどのような意味なのかわかりません。

もしそうだとすると、私はそのようには考えていません。
%s と %z が示す情報は独立なものだと考えています。

上の繰り返しになってしまうのですが、以下のように考えています。
* %s は過去から未来への流れの中の 1点を指定する
* %z はその 1点の表現方法を指定する

やっぱりおかしいですね。%s の表現方法は繰り返しですが %s です。

もし、Time が、地方時、UTC、固定時差以外の表現方法として
1970-01-01T00:00:00Z からの秒数を数値としてサポートしているなら、
それを選ぶのが望ましいのかもしれません。

「%s の表現方法は繰り返しですが %s です。」というのはそのような意味でしょうか?

現在のところ、Time はそのような表現方法をサポートしておらず、
地方時、UTC、固定時差のいずれかを選ばなければならないため、
入力に時差が与えられているのなら固定時差を選ぶのはあり得る選択肢だと思っています。

日付じゃなくて、オブジェクトの操作ですよね。

日付というのが私の言う時刻と違うのかどうか確信が持てません。
また、ふなばさんがいうオブジェクトというものが何を指しているのか分かりません。

逆にこれを導入しなければならない強い動機が俺にはわかりません。

git で使われているからという動機は述べられているんじゃないでしょうか。

git に従う理由がありません。しかも ruby でそれが表現できないわけでも
解析できないわけでもありません。

もちろん従わなければならないわけではありません。
私はそれが提案者の動機だと思った、ということです。

ふなばさんはそれが提案者の動機だとは考えられないのでしょうか。

Time.strptime('0 -0200', '%s %z')
#=> 1969-12-31 22:00:00 -0200
Time.strptime('20010203 -0200', '%Y%m%d %z')
#=> 2001-02-03 11:00:00 +0900

明らかに統一性がないと思います。
以前は %s も含めて時差はすべて無視されていました。
これは Time の元からの仕様なので気にしていませんでしが、
今はおかしな事になっていると思います。

なるほど。
Time が固定時差をサポートする以前は無視されていたというのはそのとおりです。
サポートした後でも、 まだ固定時差を選ぶほうがいい場合でもそうなっていないことがあるというのもそのとおりだと思います。

というわけで Time.strptime('20010203 -0200', '%Y%m%d %z') の場合でもそうするようにしてみました。

#18 Updated by tadayoshi funaba 10 months ago

Akira Tanaka wrote:

tadayoshi funaba wrote:

「そこにオブジェクトを見てる」というのがどのような意味なのかわかりません。

伝わらないのでちょっと別の話をします。

Date.today.ctime #=> "Sat May 3 00:00:00 2014"

これは普通の日付ですよね。
これの Sat を Fri 書き換えると間違った日付です。

たしか、php のライブラリだったと思うけど、こういうのを入力すると
2014-05-02 とか 2014-05-09 なんかが返ってくるものがありました。
これはもう日付というよりコマンド言語みたいなもんですよね。
田中さんの説明からも '%s %z' はそういう部類という事だと思います。

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

「%s の表現方法は繰り返しですが %s です。」というのはそのような意味でしょうか?

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

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

ふなばさんはそれが提案者の動機だとは考えられないのでしょうか。

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

というわけで Time.strptime('20010203 -0200', '%Y%m%d %z') の場合でもそうするようにしてみました。

うーん、それはそれでいいのかどうか判りませんが。

#19 Updated by Akira Tanaka 10 months ago

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_offsetz を取り出せます。
つまり Time オブジェクトは sz を両方そのまま中に持っています。

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

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

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

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

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

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

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

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

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

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

#20 Updated by tadayoshi funaba 10 months ago

Akira Tanaka wrote:

tadayoshi funaba wrote:

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

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

俺は今、日本にいてUTCの時刻を扱っているとします。
それを例えば以下のように記述する事にします。
与えられた時刻はUTCだけど、それを +09:00 で参照する事にします。

2001-02-03T04:05:06 UTC (+0900)

一般的でないので、
DateTime.parse('2001-02-03T04:05:06 UTC').new_offset('+0900')
といったような操作で説明する事になります。

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

日付とはなにかとか、そういうことをもうすこし詳しく述べていただけると、理解が可能になるのかもしれません。

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

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

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

ちょっと意味が判りませんでした。

%s がそもそも不完全と思えるので、なぜこんなに拘るのはわかりません。

%s を空間に置き換えてみると、これでマイルストーンは置けず、ただ距離が示されているだけ、距離の定義がわかない状態ではないですか。

あと、ついでなので、田中さんが固定時差と言ってるものも万能でない事は確認しておきたいです。

与えられた自明の地方時も有用で、時差ではなくタイムゾーン=時間帯の情報は
単なる時差以上の情報を含んでいます。

夏時間など実際に我々が参照している時系と形式は重要じゃないですか。
そういう意味も含めて、%s 偏重の流れに違和感を感じます。

#21 Updated by Felipe Contreras 10 months ago

It don't understand the details of the discussion, but it seems to me Tadayoshi is arguing that dates cannot be represented correctly in "%s %z".

If that was the case why did Git chose it as the format to store dates? Shouldn't Git be having problems with that if that was so?

Git the the most successful DVCS out there by far, and there aren't any problems with its object data storage model which has been the same since pretty much day one.

So if he is arguing that, he's wrong.

#22 Updated by Akira Tanaka 10 months ago

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 を偏重といわれるほど勧めたいとは思っていません。
私としては閏秒の問題が大きいと思います。

#23 Updated by tadayoshi funaba 10 months ago

Akira Tanaka wrote:

tadayoshi funaba wrote:

ここで、Unix Epoch からの秒数やユリウス日はこの異なり方の選択肢をどう選ぶべきか自明ではありません。

しかし、それは Time の場合は自明である地方時、DateTime では UTC という事になっているし、そういう形式なんで仕方がないと思います。
そういう積極的でない時間帯の選択は俺は勝手に「匿名」と読んで許容しています。厳密にはそういうのを別に識別する仕掛けがあるほうがいいのでしょうが。

%s %z は「今x秒です」「オレ %z の時差で生活してます」という感じで
たしかに同じ時刻について言ってるのは確かなんだけど、まるで別の事ではないかと思います。

#24 Updated by tadayoshi funaba 10 months ago

git は良く知らないんだけど、今、git-1.9.2 を見たところでは、
少なくとも現行の核で strptime は使ってないように見えます。
自前で解析して time_t 相当のものを組み立ててるようですね。

git-1.9.2/date.c から引用:
/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
(i.e. English) day/month names, and it doesn't work correctly with %z. */

この %z についての主張は、俺の主張と一致しているように見えます。

#25 Updated by Felipe Contreras 10 months ago

tadayoshi funaba wrote:

/* Gr. strptime is crap for this; it doesn't have a way to require RFC2822
(i.e. English) day/month names, and it doesn't work correctly with %z. */

This has already been agreed: many options in strptime() are not portable, but that includes '%s' as well.

#26 Updated by Akira Tanaka 10 months ago

tadayoshi funaba wrote:

ここで、Unix Epoch からの秒数やユリウス日はこの異なり方の選択肢をどう選ぶべきか自明ではありません。

しかし、それは Time の場合は自明である地方時、DateTime では UTC という事になっているし、そういう形式なんで仕方がないと思います。
そういう積極的でない時間帯の選択は俺は勝手に「匿名」と読んで許容しています。厳密にはそういうのを別に識別する仕掛けがあるほうがいいのでしょうが。

はい。Time や DateTime のインターフェースで hour がないとかは許しがたいので、
なにかを選ばざるを得ないと思います。

%s %z は「今x秒です」「オレ %z の時差で生活してます」という感じで
たしかに同じ時刻について言ってるのは確かなんだけど、まるで別の事ではないかと思います。

ふむ。これは示唆的です。

もしかして、DateTime.strptime に与えるフォーマットに時刻 (時間軸上の点) を同定するのに関係しない要素は与えるべきでない、
と感じるという話でしょうか。

(念のために書いておくと、時刻を同定するのに関係しない要素というのは "%s %z" における %z のことです。)

#27 Updated by Nobuyoshi Nakada 10 months ago

It doesn't seem there is absolute reason that you have to use Time.strptime.
Particular methods feel more suitable, like rfc2822, httpdate, and xml.

class Time
  def self.git(s)
    /\A(\d+)\s+([-+]\d\d)(\d\d)\z/ =~ s or
      raise ArgumentError, "invalid git timestamp: #{s}"
    at($1.to_i).getlocal("#$2:#$3")
  end
  def git
    strftime("%s %z")
  end
end

#28 Updated by tadayoshi funaba 10 months ago

Akira Tanaka wrote:

tadayoshi funaba wrote:

もしかして、DateTime.strptime に与えるフォーマットに時刻 (時間軸上の点) を同定するのに関係しない要素は与えるべきでない、
と感じるという話でしょうか。

極端な話、単に読み飛ばすだけでも意味があると思ってます。

s = 'Sunday 4 May <unknown garbage> 2014; blob'
h = Date._strptime(s, '%a %d %b')
s2 = h[:leftover].gsub(/ *<.*> */, '')
h2 = Date._strptime(s2, '%Y')

h.merge(h2) #=> {:wday=>0, :mday=>4, :mon=>5, :leftover=>"; blob", :year=>2014}

もちろん strptime でも。
結果的に捨てる部分がでてくるのは避けられないんじゃないですかね。

#29 Updated by Felipe Contreras 10 months ago

Nobuyoshi Nakada wrote:

It doesn't seem there is absolute reason that you have to use Time.strptime.

Why wouldn't I? It does exactly what I want:

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

See? The problem is not Time, the problem is DateTime.

What "absolute" reason could there be for one doing the right thing, and the other one not?

#30 Updated by Akira Tanaka 10 months ago

tadayoshi funaba wrote:

Akira Tanaka wrote:

tadayoshi funaba wrote:

もしかして、DateTime.strptime に与えるフォーマットに時刻 (時間軸上の点) を同定するのに関係しない要素は与えるべきでない、
と感じるという話でしょうか。

極端な話、単に読み飛ばすだけでも意味があると思ってます。

うぅむ。期待したものとは違う方向で回答されてしまった気がします。

ここで興味の対象は "%s %z" がなぜいけないのか、という点です。

私の思ったのは、もし、ふなばさんが DateTime.strptime に与えるフォーマットに時刻 (時間軸上の点) を
同定するのに関係しない要素は与えるべきでない、と感じるとすれば、
フォーマットに "%s %z" を与えるのは %z がまさに関係しない要素なので、
提案に否定的になるということが理解できる、というものです。

ですから、単にそうなのかそうでないのか教えてほしかったのですが、どうでしょうか。

読み飛ばすという使い方については私には関係性が見出せませんでした。

#31 Updated by tadayoshi funaba 10 months ago

ここで興味の対象は "%s %z" がなぜいけないのか、という点です。

私の思ったのは、もし、ふなばさんが DateTime.strptime に与えるフォーマットに時刻 (時間軸上の点) を
同定するのに関係しない要素は与えるべきでない、と感じるとすれば、
フォーマットに "%s %z" を与えるのは %z がまさに関係しない要素なので、
提案に否定的になるということが理解できる、というものです。

質問の意図が理解しきれていないかもしれませんが、望ましくはないと思います。
ただ、それと俺の判断に関係があるのかな。

読み飛ばすという使い方については私には関係性が見出せませんでした。

Date.strptime('Sun May 4 00:00:00 2014', '%a %b %d %T %Y')

これは典型的な日付ですが、田中さんのいう点を打つには Sun は余分ですが
これを拒否する事はできないと考えるべきでしょう。

DateTime.strptime('2001-02-03/2014-05-04', '%F/%F')

このようなものは望ましいとは言えないと思います。
濫用や誤解の元になるようなのは良くないと思います。
質問の意図と違うかもしれませんが。

#32 Updated by Akira Tanaka 10 months ago

tadayoshi funaba wrote:

質問の意図が理解しきれていないかもしれませんが、望ましくはないと思います。
ただ、それと俺の判断に関係があるのかな。

関係あると思われないなら私の推測がまちがっていたのでしょう。

そうすると、%s %z がなんでいけない理由はいまだに私にとって謎だなぁ。

#33 Updated by tadayoshi funaba 10 months ago

そうすると、%s %z がなんでいけない理由はいまだに私にとって謎だなぁ。

少し違うかもしれないけど、
もっと基本的なパターンとして '%z' があって、
'%s %z' を受け入れる事になったら、次は '%z' だなって以前に思ったのを思い出した。

Felipe Contreras の主張だとこれも出来ないとバグでしょ。
彼は別に自分が困っててここに来てるわけじゃないからね。
DateTime.strptime ではこれは許さない事になってる。

Time のほうは
Time.strptime('', '') とか
少なくとも以前は Time.parse('foo') なんかも許してたから
このたりは大分違うのかなと思う。

意外とこの辺が考えの違いに関係してるとか。ないか。

#34 Updated by tadayoshi funaba 10 months ago

なんか本質に近いところを突いたような気がしてきた。

DateTime は日付の核になる所から積み上げられないと、そこは無効になるんだけど、
Time にはそういうのがなくて、仮令、核が虚になってても関係ない。

俺の見方だと、そもそも Time は日付 (時刻) になってなくてもいいって事なんだと思う。
そう考えると納得出来るような気がする。

#35 Updated by Yukihiro Matsumoto 10 months ago

私もさすがに"%z"単体を許すべきとは思いません。それ日付でも時刻でもないから。

それはそれとして、"%s %z"はgitがコミット時間をログに記録するのに使ってるフォーマットなんだそうです。
たしかに、手元の .git/logs/HEAD とかに、すべてのコミットについてこの形式でチェックイン時間とタイムゾーンが記録されている。

これくらい実際に広く使われているツールで頻繁に使われているフォーマットであれば、曜日の場合のように矛盾する情報というわけでもないので、このケースについてはoffset情報は残してあげるといいんじゃないかと思います。

もらったパッチをそのまま使うか、独自で書くかはお任せします。

Matz.

#36 Updated by tadayoshi funaba 10 months ago

ずっと俺には何の決定権もないって言われ続けているような気がしたけど
今日は本当にそれを実感した。

#37 Updated by Akira Tanaka 10 months ago

tadayoshi funaba wrote:

Time のほうは
Time.strptime('', '') とか
少なくとも以前は Time.parse('foo') なんかも許してたから

Time.parse は現在時刻で補完するという仕様だったからです。
そういう仕様だったので、その仕様を変えるまでは、まったく時刻情報がなくても受け付けていました。

Time.strptime('', '') もそうで、これはまつもとさんが書いた最初からですが、
r8068 をみると、Time.parse のコードを複製したところがそのままだから、
という感じかなぁ。
変えてもいいかもしれないですね。

#38 Updated by Yukihiro Matsumoto 10 months ago

  • Tracker changed from Bug to Feature
  • Status changed from Rejected to Open

元々のリポートが「これはバグだ」、「当然対応すべきだ」という態度だったのは置いといて、実際に利便性があり、ほかに実害がない以上、機能拡張として対応したほうがいいと思います。

私が見落としてるのかもしれないけど、今までのふなばさんの主張で「対応すべきでない」理由はわかりませんでした。
「対応しなかった」理由はなんとなくわかりましたし、実際の利用例がなく、単に一貫性のためとかだったらこのまま放置でよかったと思いますが。

これを決定権がないとおっしゃるのであれば、私なんかも全然決定権がありませんね。決定がひっくり返されるのもしょっちゅうだし。

Matz.

#39 Updated by tadayoshi funaba 10 months ago

Time.parse は現在時刻で補完するという仕様だったからです。
そういう仕様だったので、その仕様を変えるまでは、まったく時刻情報がなくても受け付けていました。

DateTime でも補完はしますけどね。

Time.strptime('', '') もそうで、これはまつもとさんが書いた最初からですが、
r8068 をみると、Time.parse のコードを複製したところがそのままだから、
という感じかなぁ。
変えてもいいかもしれないですね。

とりあえず、'%z' のみとかはダメらしいですから。

ついでだけど、Time の変更がこのまま進むなら to_time とかも直したほうがいいよ。
元々無理のある仕様だったけど、もう完全にダメになりそう。

#40 Updated by tadayoshi funaba 10 months ago

「対応しなかった」理由はなんとなくわかりましたし、実際の利用例がなく、単に一貫性のためとかだったらこのまま放置でよかったと思いますが。

git については過大評価じゃないかなと思います。
もうどうでもいいですが。

これを決定権がないとおっしゃるのであれば、私なんかも全然決定権がありませんね。決定がひっくり返されるのもしょっちゅうだし。

まつもとさんは大変だと思います (俺も原因になってるし)。

#41 Updated by tadayoshi funaba 10 months ago

変更しました。

今すぐコミッターの活動を停止するわけではありませんが、
今日で date の担当は降ります。

現行の date の実装はこのまま使ってもいいし、要らなくなったら遠慮なく捨てて下さい。

今後は横断的にちょっかいを出したり、
行末の空白を削ったりして、のんびり余生を過そうと思います。

#42 Updated by Felipe Contreras 10 months ago

Well, I still don't understand what was discussed here, but it seems we have a fix (r45822).

Thanks for doing the sensible thing :)

#43 Updated by Yukihiro Matsumoto 10 months ago

tadayoshi funaba wrote:

変更しました。

ありがとうございます。

今すぐコミッターの活動を停止するわけではありませんが、
今日で date の担当は降ります。

現行の date の実装はこのまま使ってもいいし、要らなくなったら遠慮なく捨てて下さい。

要らなくなることはないと思います。義務はないのでまた手伝ってください。

今後は横断的にちょっかいを出したり、
行末の空白を削ったりして、のんびり余生を過そうと思います。

今後ともよろしくお願いします。

#44 Updated by Akira Tanaka 10 months ago

tadayoshi funaba wrote:

とりあえず、'%z' のみとかはダメらしいですから。

そうですね。
Time.strptime("+09:00", "%z") も受け付けていたので、原作者の意図するものではないということで変えてみました。

ついでだけど、Time の変更がこのまま進むなら to_time とかも直したほうがいいよ。
元々無理のある仕様だったけど、もう完全にダメになりそう。

どうダメなのかわからないのでなんともいいようがない、というのが私の正直な感想です。

#45 Updated by tadayoshi funaba 10 months ago

どうダメなのかわからないのでなんともいいようがない、というのが私の正直な感想です。

俺にはもう関係ない事ですし、余計な事でした。
田中さんのほうで気になってなかったのなら別に構わないと思います。

#46 Updated by tadayoshi funaba 10 months ago

  • Status changed from Open to Closed

#47 Updated by Tsuyoshi Sawada 6 months ago

Eric Hodel wrote:

Felipe, your extreme rudeness has no place here.

The rejection reason is described in #7445 as linked.

Not every committer is proficient in English so Japanese is just fine.

I don't suspect you'll get a reason.

Eric, your speculation that Tadayoshi Funaba's comment was written in Japanese (only) because he may not be proficient in English is not correct. In the first comment written in Japanese in #7445, he wrote:

俺の英語は通用しないらしいから日本語で書いてあげます。

which translates to "My English doesn't seem to be understood by you, so I will write it in Japanese for you," which does not make sense at all if interpreted literally under the given situation. I interpret this as a very rude irony. It is Tadayoshi Funaba, who started all the rudeness. Felipe Contreras only responded rudely to a rude comment. I don't think there is anything wrong, generally, if a comment is written in any language. However, in this particular case, it was written in Japanese intentionally to give a certain (negative) effect.

Also available in: Atom PDF