Opened 4 weeks ago

Closed 4 weeks ago

#37323 closed Bug (duplicate)

Reading a DateField from a column of type timestamp produces python datetime.datetime

Reported by: uli123abc Owned by:
Component: Database layer (models, ORM) Version:
Severity: Normal Keywords: DateField, timestamp, date, datetime
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Current behavior:
According to documented behavior [1], DateField should represent a datetime.date object. If however the database column (Postgresql) is of type timestamp [2], reading the field will produce a datetime.datetime object.

Expected behavior:
The ORM should warn about a type mismatch or cast the database value to a datetime.date object.

[1] ​https://docs.djangoproject.com/en/6.1/ref/models/fields/#datefield
[2] ​https://www.postgresql.org/docs/current/datatype-datetime.html

Change History (3)

comment:1 by Yassin Bahri, 4 weeks ago

I reproduced this against PostgreSQL 17.4 using Django 4.2.26, 5.2.8, 6.0, and 6.1.

In each version, a model declaring:

class Event(models.Model):
    happened_on = models.DateField()

returns a datetime.date while the corresponding database column is a PostgreSQL date. After manually altering that column to timestamp, PostgreSQL/psycopg returns a datetime.datetime instead.

This does not appear to be a regression. The model definition and physical database schema disagree: DateField creates and expects a date column, while the actual column is a timestamp. Automatically converting the returned value would hide the schema mismatch and could silently discard the time component. Detecting this on every read would also require additional schema introspection.

The schema should normally be corrected to use date, or the model should use DateTimeField to match the existing timestamp column.

If the mismatch is intentional, an explicit database cast works:

from django.db.models import DateField
from django.db.models.functions import Cast

event = Event.objects.annotate(
    happened_on_as_date=Cast("happened_on", output_field=DateField()),
).get()

I verified that happened_on_as_date is then a datetime.date. This is also consistent with #31506, which clarified that declaring an output field does not itself perform a database cast.

I think this ticket can be closed as invalid.

in reply to:  1 comment:2 by uli123abc, 4 weeks ago

Replying to Yassin Bahri:

Detecting this on every read would also require additional schema introspection.

I don't see why, because isinstance(read_value, datetime.datetime) in Python is sufficient to detect it.

The mismatch wasn't intentional in that case and relying on DateField to produce datetime.date introduced a bug in the code that relied on that.

Overall the behavior seems to be consistent though with other field types such as IntegerField when used on a float column type.

The schema should normally be corrected to use date

I agree that altering the column type in the database is overall the best solution.

Last edited 4 weeks ago by uli123abc (previous) (diff)

comment:3 by David Smith, 4 weeks ago

Resolution: → duplicate
Status: new → closed

Duplicate of #23803.

While the database is different (sqlite -> postgres) the underlying issue and potential solutions in user projects are the same.

Note: See TracTickets for help on using tickets.
Back to Top