Opened 6 years ago

Closed 6 years ago

Last modified 6 years ago

#29580 closed Bug (invalid)

Now() database function doesn't respect TIME_ZONE with USE_TZ

Reported by: lobziik Owned by: nobody
Component: Database layer (models, ORM) Version: 2.0
Severity: Normal Keywords: postgres, postgresql, time zones, USE_TZ
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Hi guys!
Seems that PostgreSQL database wrapper doesn't set the timezone on connection initialization.

My database settings:

{
  "NAME": null,
  "USER": "lobziik",
  "PASSWORD": "",
  "HOST": "127.0.0.1",
  "PORT": 5432,
  "ENGINE": "django.db.backends.postgresql",
  "ATOMIC_REQUESTS": false,
  "AUTOCOMMIT": true,
  "CONN_MAX_AGE": 0,
  "OPTIONS": {
    
  },
  "TIME_ZONE": null,
  "TEST": {
    "CHARSET": null,
    "COLLATION": null,
    "NAME": "test_django_test",
    "MIRROR": null
  }
}

psql behaviour on this database

$ psql -d test_django_test

psql (10.4)
Type "help" for help.

test_django_test=# select * from statement_timestamp();
              now
-------------------------------
 2018-07-20 01:37:54.903856+02
(1 row)

system date:

$ date
Fri Jul 20 01:38:44 CEST 2018

Trying to annotate some qs with built-in Django Now function:

In [8]: User.objects.all().annotate(now=Now()).last().now
Out[8]: datetime.datetime(2018, 7, 19, 23, 42, 51, 125068, tzinfo=<UTC>)

In [15]: settings.TIME_ZONE
Out[15]: 'Europe/Prague'

In [13]: settings.USE_TZ
Out[13]: True

I found strange behaviour in django.db.backends.base.base.BaseDatabaseWrapper#timezone_name, this prop is used in django.db.backends.postgresql.base.DatabaseWrapper#ensure_timezone for checking, if we should set timezone for connection or not.
But with USE_TZ = True, it always will be UTC in postgres case.

    @cached_property
    def timezone_name(self):
        """
        Name of the time zone of the database connection.
        """
        if not settings.USE_TZ:
            return settings.TIME_ZONE
        elif self.settings_dict['TIME_ZONE'] is None:
            return 'UTC'
        else:
            return self.settings_dict['TIME_ZONE']

Also it impossible to pass TIME_ZONE manually for postgres database. See django.db.backends.base.base.BaseDatabaseWrapper#check_settings

Change History (6)

comment:1 by lobziik, 6 years ago

Also, documentation mentions that connection timezone should be set as TIME_ZONE: https://docs.djangoproject.com/en/2.0/topics/i18n/timezones/#postgresql

comment:2 by Tim Graham, 6 years ago

Resolution: invalid
Status: newclosed
Summary: Postgresql: db Now() doesnt respect TIME_ZONE with USE_TZNow() database function doesn't respect TIME_ZONE with USE_TZ

I don't see anything in the documentation for the Now database function that suggests that settings.TIME_ZONE should be respected: "Returns the database server’s current date and time when the query is executed".

From the time zone documentation, "When support for time zones is enabled, Django stores datetime information in UTC in the database, uses time-zone-aware datetime objects internally, and translates them to the end user’s time zone in templates and forms."

in reply to:  2 comment:3 by lobziik, 6 years ago

Replying to Tim Graham:

I don't see anything in the documentation for the Now database function that suggests that settings.TIME_ZONE should be respected: "Returns the database server’s current date and time when the query is executed".

From the time zone documentation, "When support for time zones is enabled, Django stores datetime information in UTC in the database, uses time-zone-aware datetime objects internally, and translates them to the end user’s time zone in templates and forms."

Yep, seems title is so misleading. Can I change it and reopen ticket?

The main problem described is:

Seems that PostgreSQL database wrapper doesn't set the timezone on connection initialization.

And Now() behaviour is just a side effect.

And according to time zone documentation: "As a consequence, if you’re using PostgreSQL, you can switch between USE_TZ = False and USE_TZ = True freely. The database connection’s time zone will be set to TIME_ZONE or UTC respectively, so that Django obtains correct datetimes in all cases. You don’t need to perform any data conversions."

comment:4 by Tim Graham, 6 years ago

It looks to me like the time zone is set if needed. The code matches the documentation you quoted as far as I see.

in reply to:  4 comment:5 by lobziik, 6 years ago

Replying to Tim Graham:

It looks to me like the time zone is set if needed. The code matches the documentation you quoted as far as I see.

timezone_name looks broken for me...
If settings.TIME_ZONE is True, UTC returns here
If TIME_ZONE presented in database settings it will cause the ImproperlyConfigured exception here.

Should we patch this if statement and remove not there? Or redefine this method in postgresql.base.DatabaseWrapper.

comment:6 by Tim Graham, 6 years ago

Paraphrasing the documentation you quoted, "The database connection’s time zone will be set to TIME_ZONE (if USE_TZ is False) or UTC (if USE_TZ is True)." This statement matches the implementation of BaseDatabaseWrapper.timezone_name as far as I see.

I still don't see a problem.

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