Cookieの日付形式

Cookieの日付形式

[1] Cookie では Expires 属性の値として日時が使われますが、 Wdy, DD-Mon-YYYY HH:MM:SS GMT のような独自の書式で日時を記述します。

[27] RFC 6265HTTP の標準的な日付形式で記述することを求めていますが、 依然として、元々の NetscapeのCookie仕様で指定されていた形式が広く用いられています。

仕様書

構文

Netscape の仕様での定義

[15] Cookieの日付形式

Wdy, DD-Mon-YYYY HH:MM:SS GMT
のように日時UTC で記述します。>>14 HTTPの日付形式に似ていますが、の要素間に - を入れなければいけません。

[16] 仕様書 >>14 には

This is based on RFC 822, RFC 850, RFC 1036, and RFC 1123, with the variations that the only legal time zone is GMT and the separators between the elements of the date must be dashes.

などと訳がわからないことが書かれています。当時は HTTPRFC 化されていなかったのでそれを参照していないのは仕方がないにせよ (でも Internet Draft はあったはず)、 なんでこんなおかしな説明の書き方をしたのかは謎です。

[17] 仕様書で示された書式や実際の例示 >>2 の書式は RFC 850の日付形式に一番近いですが、 >>16 にある通り時間帯GMT に固定されています。 Wdy とあるといかにも省略形の曜日が使われそうですが、 >>2 の例示は長い名前になっていて、これは RFC 850 と一致しています。 現実には短い名前の方が一般的な気がします。

[18] 年号>>15 からすると4桁でなければならないように見えますが、>>2 の例示は2桁になっています。

RFC 6265 での定義

[20] RFC 6265 における日付の構文
 sane-cookie-date  = <rfc1123-date, defined in [RFC2616], Section 3.3.1>

[21] 利用者エージェントによって2桁西暦年号の解釈が異なるため、 4桁の年号を指定するRFC 1123の日付形式を使うべきである >>19 とされています。

[22] 利用者エージェントによっては 32ビットtime_t で日付を処理しますが、そのため実装によっては不具合により 2038年以降の日付を正しく処理できないことがある >>19 と指摘されています。

[34] 構文解析の方法に従うと、1600年とそれ以前は正しく処理されないことになります。 構文上はそのような制約は明記されていません。

構文解析

[28] RFC 6265 は次のような構文解析の算法を規定しています >>24。これに従えば HTTPの日付形式と元々の Netscape の日付形式のいずれも解釈できます。

  1. 次のオクテット区切子として入力を字句列に分割します。
  2. 字句列の字句に対して順に次の操作を行います。
    1. 時刻がまだ見つかっておらず、次の正規表現に一致するなら、これを時刻とし、次の字句に進みます。
    2. 日がまだ見つかっておらず、次の正規表現に一致するなら、これを日とし、次の字句に進みます。
    3. 月がまだ見つかっておらず、最初の3文字が12種類の月名のいずれかにASCII大文字・小文字不区別で一致するなら、 これを月とし、次の字句に進みます。
    4. 年がまだ見つかっておらず、次の正規表現に一致するなら、これを年とし、次の字句に進みます。
  3. 年が 70-99 なら、1900を足します。
  4. 年が 00-69 なら、2000を足します。
  5. 次のいずれかに該当するなら構文解析は失敗であり、停止します。
    1. 年月日、時刻のいずれかが指定されなかった場合
    2. 年が 1601 未満の場合
    3. 日が 1 未満の場合
    4. 日が 31 より大きい場合
    5. 時が 23 より大きい場合
    6. 分が 59 より大きい場合
    7. 秒が 59 より大きい場合
  6. 得られた年月日、時刻を UTC の日時として解釈します。該当する日時が存在しないなら失敗であり、停止します。
  7. 得られた日時を返します。

[29] 2桁の年が指定された場合、 >>28 の通り1970年が1900年代と2000年代の境界になります。

[30] RFC 2616 の推奨とは異なっています。2桁西暦年号の解釈の項を参照してください。

閏秒

[31] 閏秒を記述しても良いかどうかについては、 RFC 2616 に定義が委ねられており、その RFC 2616 は明確に規定していないため、不明です。 (HTTPの日付形式を参照してください。)

[32] >>28 の通り、構文解析において閏秒は不正な日時とみなされます。

歴史

RFC 6265

[25] RFC 6265Cookieの日付形式HTTPの日付形式を構文解析できる算法を定義しています。 ただし字句の定義が若干間違っています。 ( non-digit *OCTET ) は省略可能と解釈する必要があります。

実装

[33] au の2011年秋以降の端末では Cookie の仕様変更がありました。 それに伴い、 HTTPの日付形式 (RFC 1123の日付形式) は受け付けなくなり、 元々の Netscape の規定に基づく「-」が入る形式でなければ Expires 属性は無視されてしまうようになりました。

テスト・ケース

[26] <https://github.com/abarth/http-state/tree/master/tests/data/dates> に日付の構文解析のテスト・データがあります。

メモ

[3] >>2 の例は Netscape の仕様書からの引用ですが、ここでは4桁でなければならないと規定されているはずの年号が2桁になっています。 (それに、 >>1 の構文なら曜日は短い名前のはずだと思うのですがね。)

[4] 巷の CGI script などを見ていると、日付の指定が間違っているものも見受けられます。

[8] >>4,>>6-7 当然、不正な形式に対する動作は未定義です。

とはいえ、 >>2 のように仕様からしてぐちゃぐちゃなので、どうしたものでしょうか。

[9] >>8 もちろん、 >>1 の形式を使えば全ての Cookie 対応 UA で問題なく処理されるはずです。

[10] >>8 そういうのを解説してる書籍とか Web page があるらしいです。ひどいな!

[11] [JavaHouse-Brewers:31373] Re: Cookie.setMaxAge() について ( 版) <http://java-house.jp/ml/archive/j-h-b/031373.html>

「問題」

ブラウザがInternet Explorer 5の場合、

  1. Cookie.setMaxAge()へのパラメータが正の場合、 クッキーは設定されるが、指定された秒数が経過しても、 クッキーは無効にならない。 クッキーの有効期間には、、"木, 9 14 30828 02:48:05"が設定されている。 (クッキー受信時の確認ダイアログで確認) ブラウザを再起動しても、クッキーは有効である。 # NN4.7では、指定された時間が経過するとクッキーは無効になる。

  1. Cookie.setMaxAge()へのパラメータに0を指定した場合、 クッキーが設定されたままになる。 ブラウザを再起動しても、クッキーは有効である。 クッキーの有効期間には、"木, 9 14 30828 02:48:05"が設定されている
NN4.7では、ブラウザはクッキーを受信した旨をダイアログで表示する。 しかし、その後のリクエストではこのクッキーを送信しない。(期待通り)

「原因」

Internet Explorer 5(version 3, 4では調べていない)では、 次のようにタイムゾーンがJSTで指定されている有効期限付きSet-Cookieヘッダを 正しく解釈できません。

Set-Cookie:NAME=VALUE; expires=Tuesday,28-Feb-2000 19:00:00 JST

IE5では、タイムゾーンがGMTである場合は、クッキーの有効期限が正しく設定されます。 (タイムゾーンがその他の場合の動作は、調べていません。)

[12] 教えて!北京五輪「みんなにQ&A」 クッキーの有効期限の記述について ( 版) <http://qa.asahi.com/qa1158822.html>

IEでは、曜日は確かに 無視されているようでした(曜日をいろいろ変えても 設定日時には、クッキーが削除されました)。

[13] [JavaScript + Cookie]実は有効期限指定がすごく簡単だった件について / 文系大学的IT系の悲哀 (LiosK 著, 版) <http://liosk.blog103.fc2.com/blog-entry-22.html>

手元にあるIE6, Firefox2, Opera9で確認済み。Date#toUTCStringで有効期限が指定できるなら楽だ。

[23] Java 6のHttpCookieの野郎は、日本ではexpires指定ありのクッキーを処理できていない。 - 片っ端から忘れていけばいいじゃない。 ( (0xC000013A 著, 版)) <http://0xc000013a.blog96.fc2.com/blog-entry-131.html>

[36] Expires=Sat, 20 Feb 2016 02:25:16 UTC

nicovideo.jp が使っている形式。

[37] PHP: DateTime - Manual () <http://php.net/manual/en/class.datetime.php#datetime.constants.cookie>

DateTime::COOKIE

DATE_COOKIE

HTTP Cookies (example: Monday, 15-Aug-2005 15:52:01 UTC)

[38] なぜ GMT でなく UTC としているのか謎。

[39] PHP: DateTime - Manual () <http://php.net/manual/en/class.datetime.php#datetime.changelog>

5.4.24 The COOKIE constant was changed to reflect RFC 1036 using a four digit year rather than a two digit year (RFC 850) as prior versions.