J'utilise PostgreSQL 8.4.11 et trouve une erreur étrange. Quand j'interroge:
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
J'obtiens des résultats:
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
...
Pourquoi?
Je m'attendrais à des dates dans l'intervalle 1-01-01 ... 1-12-31.
Vous vous attendiez à 1-01-01 ... 1-12-31
... mais comment PostgreSQL est-il censé savoir ce que vous entendez par là?
Les littéraux de chaîne sont interprétés selon les paramètres régionaux en vigueur, en particulier lc_time
lors de la conversion en timestamp
ou date
. Je cite le manuel ici :
lc_time (chaîne)
Définit les paramètres régionaux à utiliser pour le formatage des dates et des heures, par exemple avec la famille de fonctions to_char. Les valeurs acceptables dépendent de Du système; voir la section 22.1 pour plus d'informations. Si cette variable Est définie sur la chaîne vide (qui est la valeur par défaut), la valeur Est héritée de l'environnement d'exécution du serveur de manière dépendante du système .
Dans votre cas, le littéral d'horodatage mutilé 1-12-31 23:59:59
est évidemment interprété comme suit:
D-MM-YY h24:mi:ss
Alors que vous auriez espéré:
Y-MM-DD h24:mi:ss
Définissez lc_time
sur un environnement local qui interprète un tel littéral de la même manière que vous. Pas sûr qu'il y en ait un.
Utilisez to_timestamp()
pour interpréter le littéral de chaîne de manière bien définie, indépendamment des paramètres régionaux actuels. Beaucoup mieux.
SELECT to_timestamp('1-12-31 23:59:59', 'D-MM-YY h24:mi:ss')
Mieux encore, utilisez Format ISO 8601 (YYYY-MM-DD
) pour tous les littéraux datetime. C'est sans ambiguïté pour les paramètres régionaux .
SELECT '2001-12-31 23:59:59'::timestamp
Enfin, votre requête est défectueuse pour commencer. Traitez une requête de plage différemment. Réécrivez votre requête pour:
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;
Ou, encore plus simple:
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;
Les nouveaux types de plage de PostgreSQL 9.2 peuvent vous intéresser.
SELECT '1-12-31 23:59:59.999999'::timestamp;
renvoie 2031-01-12 23:59:59.999999
, apparemment Postgres ne considère pas l'année sans siècle comme premier élément de la date.
Vous n'avez pas précisé le format dans lequel vous le vouliez. Le format natif est donc restitué. Peut-être avez-vous même supposé que tout le monde indique l'heure comme vous le faites? Regardez les formats possibles. http://www.postgresql.org/docs/8.2/static/functions-formatting.html