Search code examples
postgresqlnestjstypeorm

How to get a date from Postgres in my timezone


I try to deploy a JS application using TypeORM and Postgres on a host. Locally I had a Postgress DB so running in my own TZ. The remote host happens to have its system time set to UTC:

$ date
Mon Oct 7 15:45:00 UTC 2019

$ psql
> select localtimestamp;
2019-10-07 15:45:00.123456

I have a table with an automatically updated date in it (meaning it updates when record is updated).

// my.entity.ts
@UpdateDateColumn({type: 'timestamp', name: 'lastUpdate', default: () => 'LOCALTIMESTAMP' })
lastUpdate: Date;

A row is inserted at 12:00 CEST:

> select "lastUpdate" from myTable;
2019-10-07 10:00:00.000000+00

I would like to get the date out in my timezone (CEST) regardless of the server time, so it should return me 2019-10-07 12:00. I prefer to not hardcode any tricks because it should also work on my CEST machine.

Postgress has all the info:

> show timezone;
UCT
  • it knows it runs on UTC time
  • I can tell it in which timezone I want the date

So I would expect it to be easy to convert this to my requested format. However, the following examples I found don't seem to work:

> select ("lastUpdate" at time zone 'CEST') from myTable;
2019-10-07 08:00:00.000000+00

> select timezone('CEST', "lastUpdate") from myTable;
2019-10-07 08:00:00.000000+00

There is one way I can get it right, and thats by specifying the current timezone:

> select ("lastUpdate" at time zone 'UTC' at time zone 'CEST') from myTable;
2019-10-07 12:00:00.000000

However, like I said I don't want to hardcode this (as other DB's run at other TZs) and Postgres knows it's own timezone.

Is there another syntax to do this correctly?


Solution

  • All timestamps in Postgres are stored in UTC regardless of the server configuration. This is important to realize, unlike other databases it does not interpret your input to be in its local time zone. However it will present it back in its time zone.

    timestamp stores just the time without a time zone. timestamptz stores UTC plus a time zone.

    Demonstrating these together on a Postgres server with its time zone set to UTC...

    => create table demo ( time timestamp, timetz timestamptz );
    CREATE TABLE
    
    => insert into demo values ('2019-10-07 10:00', '2019-10-07 12:00 +0200');
    INSERT 0 1
    
    => select * from demo;
            time         |         timetz         
    ---------------------+------------------------
     2019-10-07 10:00:00 | 2019-10-07 10:00:00+00
    

    timestamp ignores the offset and simply stores October 7th, 2019 10:00 with no offset. While timestamptz stores the offset of +0200, but presents the time back to me in its own UTC time zone. They're the same point in time.


    You could change the database time zone for your session to CEST. Then Postgres will format timestamptz in CEST.

    => set time zone 'Antarctica/Troll';
    
    => select * from demo;
            time         |         timetz         
    ---------------------+------------------------
     2019-10-07 10:00:00 | 2019-10-07 12:00:00+02
    

    But this is brittle. You have to make sure it happens on every connection. Your application is relying on a specific configuration of your database connection. It's an action-at-a-distance anti-pattern. It's not obvious what's doing the formatting, and if it's removed lots of seemingly unrelated things break.

    Instead, you should reformat your times as you like after receiving them from the database. You can do this manually...

    => select timetz at time zone 'CEST' from demo;
          timezone       
    ---------------------
     2019-10-07 12:00:00
    

    But generally this is something your ORM takes care of for you. I don't know typeorm, but most have a means of translating database types consistently. You should be able to set up typeorm to automatically translate Postgres timestamptz into your local application time zone. Better yet, instead of returning a string it can translate it into a proper Time object which you then have full control over.