0

First of all I know there are a lot threads about this and I could use the solutions there, f.e. write a python function which converts datetime object to the timezone I need and add this as a filter to jinja2.

But I wanted to skip this step.

Usually PostgreSQL saves datetime objects in UTC.

What I did is: I changed the default timezone which postgreSQL uses to save datetime objects to: Europe/Berlin

ALTER DATABASE postgres SET timezone TO 'Europe/Berlin';

This worked, SHOW timezone; tells me its Europe/Berlin.

But what Postgres does, it still saves the datetime as UTC, but with a +1 offset for Europe/Berlin, which is actually not a problem.

I assumed that when reading the datetime object, Postgres would apply the offset and return the Europe/Berlin time, but it doesn't. It still returns the UTC time, so whats the point in changing the timezone?

I still need to write this filter and manually convert it.

I think there should be a simple way to apply the offset on DB level, or am I wrong?

EDIT

Some information, which might help, the model:

class User(UserMixin, Base):
    __tablename__ = 'users'
    date_added = Column(DateTime(timezone=True), nullable=False)

How it looks in the DB:

enter image description here

And here is an example how I load it in jinja2/html:

{{ tenant.date_added.strftime('%d.%m.%Y um %H:%M Uhr') }}
Laurenz Albe
  • 209,280
  • 17
  • 206
  • 263
Roman
  • 3,563
  • 5
  • 48
  • 104

1 Answers1

0

First, you are right to handle this completely inside the database. When dealing with time zones, either use timestamp with time zone throughout and let the database handle conversions and such, or use timestamp without time zone throughout, store UTC timestamps and let the application deal with time zone handling. Mixing these two is usually not a good idea.

PostgreSQL internally stores a timestamp with time zone as a timestamp in UTC. Upon conversion to a string , e.g. when data are sent to the client, the data is converted to the session time zone, which is configured by the timezone parameter.

Setting timezone with ALTER DATABASE will change the setting for all future sessions, that is, you have to disconnect and reconnect for the new setting to take effect.

However, every session is free (and encouraged) to change timezone using the SET command or the set_config function, and this determines to which time zone the timestamps will be converted. Use SHOW timezone to see your current setting.

If you store a timestamp without an explicit time zone (like 2019-02-01 12:00:00), it will be interpreted in your current session time zone. So if that is Europe/Berlin, the UTC timestamp stored internally will be 2019-02-01 11:00:00 UTC. Now if you SELECT the value, it will be displayed as 2019-02-01 12:00:00+01, because that is your current time zone offset. If you change timezone, the same value will be displayed differently.

Laurenz Albe
  • 209,280
  • 17
  • 206
  • 263
  • I have timestamp with time zone, and the DB timezone is Europe/Berlin, so it should return Europe/Berlin on default. I will try to restart the DB. Thanks for the reply. – Roman Feb 01 '19 at 11:42
  • Thats a problem now. I use heroku postgres and its not possible to restart a DB. Is there an other way? – Roman Feb 01 '19 at 11:46
  • There is no such thing as a "database time zone". There only is a session time zone. You don't have to restart the database, only disconnect and reconnect. – Laurenz Albe Feb 01 '19 at 11:53
  • Super weird things happening here. It has shown the correct time. I open the site in incognito mode and it shows again UTC time, switch back to non-incognito (where the time was Europe) it is UTC again. – Roman Feb 01 '19 at 11:59
  • Your explanation is on point. I think the issue is somewhere else. – Roman Feb 01 '19 at 12:01
  • Using this at app start `db_session.execute("SET TIME ZONE 'Europe/Berlin';")` doesn't influence session settings. It still shows UTC times. – Roman Feb 01 '19 at 12:03
  • It would have to be `SET timezone = 'Europe/Berlin'`. – Laurenz Albe Feb 01 '19 at 12:06
  • But that is valid SQL for PostgreSQL. You can use `TO` instead of `=`, that is the same. – Laurenz Albe Feb 01 '19 at 13:00
  • Actually, the `SET TIME ZONE` you did above is also valid SQL, sorry. How can you tell it shows UTC times? What exactly is the result? – Laurenz Albe Feb 01 '19 at 13:02
  • Thanks again for the reply Laurenz, I have created a new question: https://stackoverflow.com/questions/54480171/postgresql-sqlalchemy-and-timestamp-with-time-zone-why-is-incognito-different-f I found an other issue. – Roman Feb 01 '19 at 13:07