PostgreSQL 8.4.11を使用していて、奇妙なエラーを見つけました。私がクエリすると:
SELECT "documents_document"."given_on"
FROM "documents_document"
WHERE (EXTRACT('month' FROM "documents_document"."given_on") = 1
AND "documents_document"."given_on"
BETWEEN '1-01-01 00:00:00' and '1-12-31 23:59:59.999999')
ORDER BY "documents_document"."created_on" DESC
私は結果を得ます:
given_on
------------
2002-01-16
2011-01-25
2012-01-12
2012-01-12
2012-01-12
2012-01-20
2012-01-19
2012-01-13
2012-01-31
2012-01-16
2012-01-31
2012-01-12
...
どうして?
1-01-01 ... 1-12-31の範囲の日付を期待します。
_1-01-01 ... 1-12-31
_を期待していましたが、それによってPostgreSQLはどういう意味かをどのようにして認識するのでしょうか?
文字列リテラルは、現在のロケール設定、特にtimestamp
またはdate
にキャストされた場合の_lc_time
_に従って解釈されます。私はマニュアルを引用します ここ :
lc_time(文字列)
たとえば、to_charファミリーの関数を使用して、日付と時刻のフォーマットに使用するロケールを設定します。許容値はシステムに依存します。詳細は項22.1を参照してください。この変数が空の文字列(デフォルト)に設定されている場合、値はシステム依存の方法でサーバーの実行環境から継承されます。
あなたの場合、切断されたタイムスタンプリテラル_1-12-31 23:59:59
_は明らかに次のように解釈されます:
_D-MM-YY h24:mi:ss
_
あなたが望んでいたと思いますが:
_Y-MM-DD h24:mi:ss
_
_lc_time
_を、そのようなリテラルを同じ方法で解釈するロケールに設定します。あるかわかりません。
to_timestamp()
を使用して、現在のロケールに関係なく、文字列リテラルを明確に定義された方法で解釈します。ずっといい。
_SELECT to_timestamp('1-12-31 23:59:59', 'D-MM-YY h24:mi:ss')
_
さらに良いのは、すべての日時リテラルにISO 8601形式(_YYYY-MM-DD
_)を使用することです。それは どのロケールでも明確です です。
_SELECT '2001-12-31 23:59:59'::timestamp
_
最後に、クエリは最初から不完全です。範囲クエリを異なる方法で処理します。クエリを次のように書き換えます。
_SELECT d.given_on
FROM documents_document d
WHERE EXTRACT('month' FROM d.given_on) = 1
AND d.given_on >= '2001-01-01 0:0'
AND d.given_on < '2002-01-01 0:0'
ORDER BY d.created_on DESC;
_
または、もっと簡単です:
_SELECT d.given_on
FROM documents_document d
WHERE d.given_on >= '2001-01-01 0:0'
AND d.given_on < '2001-02-01 0:0'
ORDER BY d.created_on DESC;
_
PostgreSQL 9.2の新しい範囲タイプ は興味があるかもしれません。
SELECT '1-12-31 23:59:59.999999'::timestamp;
戻り値 2031-01-12 23:59:59.999999
、どうやらPostgresは世紀のない世紀を日付の最初の要素と見なしていません。
希望するフォーマットは何も言わなかったので、ネイティブフォーマットが返されます。おそらく、あなたは誰もがあなたがするように時間を表すと思っていましたか?可能なフォーマットを見てください。 http://www.postgresql.org/docs/8.2/static/functions-formatting.html