Q1 :Pourquoi la base de données ne renvoie-t-elle pas une valeur valide pour la moyenne de ces deux dates ?
R : La valeur retournée est attendue, c'est un comportement MySQL bien défini.
Manuel de référence MySQL :https://dev .mysql.com/doc/refman/5.5/en/date-and-time-types.html
Dans MySQL, le AVG
la fonction d'agrégation fonctionne sur numérique valeurs.
Dans MySQL, une DATE
ou DATETIME
l'expression peut être évaluée dans un numérique contexte.
À titre de démonstration simple, effectuer une opération numérique opération d'addition sur un DATETIME
convertit implicitement la valeur datetime en nombre. Cette requête :
SELECT NOW(), NOW()+0
renvoie un résultat comme :
NOW() NOW()+0
------------------- -----------------------
2015-06-23 17:57:48 20150623175748.000000
Notez que la valeur renvoyée pour l'expression NOW()+0
n'est pas un DATETIME
, c'est un nombre .
Lorsque vous spécifiez un SUM()
ou AVG()
fonction sur un DATETIME
expression, cela équivaut à convertir le DATETIME
en un nombre, puis en additionnantou en faisant la moyenne du nombre.
Autrement dit, le retour de cette expression AVG(mydatetimecol)
est équivalent au retour de cette expression :AVG(mydatetimecol+0)
Ce qui est "moyenne" est une valeur numérique. Et vous avez observé que la valeur renvoyée n'est pas une date/heure valide ; et même dans les cas où cela ressemble à une date/heure valide, ce n'est probablement pas une valeur que vous considéreriez comme une véritable "moyenne".
Q2 :Comment puis-je obtenir la moyenne réelle de ce champ si la méthode décrite échoue ?
A2 : Une façon de le faire est de convertir la date/heure en une valeur numérique dont la moyenne peut être "précise", puis de la reconvertir en date/heure.
Par exemple, vous pouvez convertir la date/heure en une valeur numérique représentant un nombre de secondes à partir d'un point fixe dans le temps, par exemple
TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)
Vous pouvez ensuite "faire la moyenne" de ces valeurs, pour obtenir un nombre de secondes moyen à partir d'un point fixe dans le temps. (REMARQUE :méfiez-vous de l'addition d'un nombre extrêmement élevé de lignes, avec des valeurs extrêmement élevées, et du dépassement de la limite (valeur numérique maximale), problèmes de dépassement numérique.)
AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date))
Pour reconvertir cela en une date/heure, ajoutez cette valeur sous forme de nombre de secondes retour à un point fixe dans le temps :
'2015-01-01' + INTERVAL AVG(TIMESTAMPDIFF(SECOND,'2015-01-01',t.my_date)) SECOND
(Notez que le DATEIME
les valeurs sont évaluées dans le fuseau horaire de la session MySQL ; il y a donc des cas extrêmes où le réglage du time_zone
variable dans la session MySQL aura une certaine influence sur la valeur renvoyée.)
MySQL fournit également un UNIX_TIMESTAMP()
fonction qui renvoie une valeur entière de style unix, nombre de secondes depuis le début de l'ère (minuit 1er janvier 1970 UTC). Vous pouvez l'utiliser pour accomplir la même opération de manière plus concise :
FROM_UNIXTIME(AVG(UNIX_TIMESTAMP(t.my_date)))
Notez que cette expression finale fait vraiment la même chose ... convertir la valeur datetime en un nombre de secondes depuis '1970-01-01 00:00:00' UTC, en prenant une moyenne numérique de cela, puis en ajoutant cette moyenne nombre de secondes de retour à '1970-01-01' UTC, et enfin reconverti en un DATETIME
valeur, représentée dans la session en cours time_zone
.
Q3 :Django DateTimeField n'est-il pas configuré pour gérer la moyenne ?
R : Apparemment, les auteurs de Django sont satisfaits de la valeur renvoyée par la base de données pour une expression SQL AVG(datetime)
.