I use PostgreSQL 8.4.11 and find strange error. When I query:
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
I get results:
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
...
Why?
I would expect dates in interval 1-01-01 ... 1-12-31.
You expected 1-01-01 ... 1-12-31
... but how is PostgreSQL supposed to know what you mean by that?
String literals are interpreted according to your current locale settings, in particular lc_time
when cast to timestamp
or date
. I quote the manual here:
lc_time (string)
Sets the locale to use for formatting dates and times, for example with the to_char family of functions. Acceptable values are system-dependent; see Section 22.1 for more information. If this variable is set to the empty string (which is the default) then the value is inherited from the execution environment of the server in a system-dependent way.
In your case, the mutilated timestamp literal 1-12-31 23:59:59
is obviously interpreted as:
D-MM-YY h24:mi:ss
While you would have hoped for:
Y-MM-DD h24:mi:ss
3 options
Set
lc_time
to a locale that interprets such a literal in the same way as you do. Not sure there is one.Use
to_timestamp()
to interpret the string literal in a well defined way - independent of the current locale. Much better.SELECT to_timestamp('1-12-31 23:59:59', 'D-MM-YY h24:mi:ss')
Better yet, use ISO 8601 format (
YYYY-MM-DD
) for all datetime literals. That is unambiguous with any locale.SELECT '2001-12-31 23:59:59'::timestamp
Rewrite query
Finally, your query is faulty to begin with. Handle a range query differently. Rewrite your query to:
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;
Or, simpler yet:
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;
The new range types of PostgreSQL 9.2 may be of interest to you.
SELECT '1-12-31 23:59:59.999999'::timestamp;
returns 2031-01-12 23:59:59.999999
, apparently Postgres does not consider year-without-century as first element in the date.
You didn't say what format you wanted it in. So it gives back the native format. Perhaps you even assumed that everyone denotes time the way you do? Have a look at the possible formats. http://www.postgresql.org/docs/8.2/static/functions-formatting.html
来源:https://stackoverflow.com/questions/12425853/postgresql-between-with-datetime