How to convert local time to UTC? - postgresql

I need to convert local time to UTC using a function. The inputs I have is the local time, timezone of the local time (e.g. 'Pacific/Auckland'). What I need to get from the procedure is the UTC time for the local time based on given timezone.
Can someone please help?
I am using version 8.3

This is covered in the manual, but it's not always obvious how to actually work with dates/times. The SQL spec is a bit bizarre.
In the case of your question it isn't clear whether you want to store the time in UTC but display it in the server's local time (TimeZone), or whether you wan to ignore TimeZone and always display it as UTC. I'll assume the latter.
For timestamps you'd just use AT TIME ZONE twice, like:
SELECT TIMESTAMP '2013-08-13 00:00:00' AT TIME ZONE 'Australia/Sydney' AT TIME ZONE 'UTC';
You need to use AT TIME ZONE twice. Once to convert the input timestamp to timestamptz according to the argument timezone, then another to convert that to a timestamp at UTC.
Unfortunately because of the (IMO insane) way the SQL spec defines AT TIME ZONE for TIME, you can't do the same thing for TIME. You'll have to manipulate the TimeZone variable instead:
SET TimeZone = 'UTC';
SELECT TIME '07:00' AT TIME ZONE 'Australia/Sydney';
This still leaves you with a timetz not a time. So its display value changes with the timezone setting.

You can use select now() at time zone 'UTC' for postgresql.

Related

Postgres: How can I update timezone of a timestamp without changing the time?

I am using django models. TIMEZONE in django settings is UTC.
and constructing a timestamp by doing some arithmetic.
return queryset.annotate(
**{f"server_time":RawSQL(
f'''
SELECT TO_TIMESTAMP((FLOOR((EXTRACT(EPOCH FROM "{gmdts_table}"."date_key" AT TIME ZONE %s) + %s) / %s)::INTEGER * %s) - %s)::TIMESTAMP
''',
params=[str(requested_time_zone), bucket_offset, time_interval, time_interval, bucket_offset]
)}
)
I have timestamp being returned as 2021-07-26 00:00:00 when I am using ::timestamp
If I use ::TIMESTAMPTZ, it becomes 2021-07-26 00:00:00+00:00 even though requested_time_zone is 'America/New_York'
I want the output to be 2021-07-26 00:00:00-04:00 ie. show the same time with offset of 'America/New_York appended'. Essentially I just want to append the offset.
I have derived this timestamp by making some calculations and it actually belongs to the timezone 'America/New_York' (it can be any time zone say calculated_time_zone).
How can I update the timezone of this timestamp without actually changing the time for the output, which is:
2021-07-26 00:00:00-04:00
When I use AS TIME ZONE 'America/New_York', I get the output as 2021-07-26 04:00:00+00 which is not what I want.
In python, it can be easily done with a <datetime_object>.replace(tzinfo=new_time_zone). I am looking for the same thing in postgresql.
Any manner in which it can be done with django database functions would be helpful too (I wasn't able to find any)
It's important to understand that the timestamptz type does not store a timezone! It simply stores the UTC timestamp. Which means that your timestamp isn't "in the wrong timezone" because it isn't in any timezone. It is, however, displayed to you in a certain timezone, defined by your session settings.
If you need to shift your timestamp by four hours, as the case may be, then you can add an interval of 4 hours to it. But if you need to "reinterpret" the UTC timestamp to be a timestamp of a different timezone (which means you probably did something wrong when building the timestamp initially), then you can do so by switching to a timezone-naive timestamp and back again:
SELECT timestamp AT TIME ZONE 'UTC' AT TIME ZONE 'America/New_York'
But don't be surprised if this new timestamp is displayed in the same timezone as before, because that's defined by your session settings, not by the timestamp itself.
Strip off the timezone, then add back the new timezone you want. This can be done with:
(myfield::timestamp || '+00:00')::timestamptz

Best way to save date and time in a PostgreSQL database

I'm gonna to save date and time in my PostgreSQL database and fetch and show it to the user in an appropriate format.
Suppose that application users are located in Iran and use Jalali date/time system. In the first half of year, Iran time is UTC+04:30, but in the rest of year, it is UTC+03:30. As a matter of fact daylight saving time is used in Iran.
IMPORTANT: Sometimes we make a decision and change database server location from Iran to Europe or elsewhere.
Now I have some questions:
What data type is more convenient to save date with time? TIMESTAMP (TIMESTAMP WITHOUT TIMEZONE) or TIMESTAMPZ (TIMESTAMP WITH TIME ZONE)?
What data type is more convenient to save time only? TIME or TIME WITH TIME ZONE?
What data type is more convenient to save date only? DATE (Gregorian) String (Jalali) or a custom data type?
How can I set TIMEZONE for our database once? I wanna set TIMEZONE for database one time and after that all queries over TIMESTAMPZ columns will be saved and fetched within that TIMEZONE and also it considered daylight saving time ?
What SQL query is the best when I wan to save current date and time ?
a- INSERT INTO test(d) VALUES(now());
b- INSERT INTO test(d) VALUES(now() at time zone 'utc');
c- INSERT INTO test(d) VALUES(now() at time zone 'Asia/Tehran');
d- INSERT INTO test(d) VALUES(current_timestamp);
e- INSERT INTO test(d) VALUES(now() at time zone 'utc');
f- INSERT INTO test(d) VALUES(now() at time zone 'Asia/Tehran');
Is number 5-c and 5-f considered daylight saving times when save it or not?
Is number 5-a and 5-d saved in 'Asia/Tehran' when database has 'Asia/Tehran' time zone ?
When I wan to query from database, what options is the best in my situation ?
a- SELECT d FROM test;
b- SELECT d at time zone 'utc' FROM test;
c- SELECT d at time zone 'Asia/Tehran' FROM test;
Is number 7-c considered daylight saving times?
Is number 7-a considered 'Asia/Tehran' time zone and daylight saving time when database has 'Asia/Tehran' time zone?
If I'd better use the timestamp to save date/time, then I have to add daylight saving time to it and convert it to Jalali date time and show it to the user, and vice versa.
https://www.postgresql.org/docs/current/static/datatype-datetime.html
For timestamp with time zone, the internally stored value is always in
UTC (Universal Coordinated Time, traditionally known as Greenwich Mean
Time, GMT). An input value that has an explicit time zone specified is
converted to UTC using the appropriate offset for that time zone. If
no time zone is stated in the input string, then it is assumed to be
in the time zone indicated by the system's TimeZone parameter, and is
converted to UTC using the offset for the timezone zone.
When a timestamp with time zone value is output, it is always
converted from UTC to the current timezone zone, and displayed as
local time in that zone. To see the time in another time zone, either
change timezone or use the AT TIME ZONE construct
timestamptz
timestamptz and select date only
timestamptz and select time only
database saves tz aware time stamps in UTC, no matter your locale or settings. stamps are always converted to UTC adjusting it by TimeZone parameter. Same deconvert happens on displaying data every time. TimeZone for server is only default value, used if client does not specify any. database TimeZone overrides the one in postgresql.conf for specified database, but still, client settings will override the database ones.

Postgresql date timezone issue

I have a pg database with a column type timestamp with time zone. I inserted the following date:
2016-08-01 00:00:00 GMT
However, in the database, it shows up as:
2016-07-31 20:00:00-04
Does anyone know what might be going on?
Thanks in advance!
Despite the name, TIMESTAMP WITH TIME ZONE doesn't actually store the time zone. It uses the session's time zone to normalize to UTC, and stores UTC. On retrieval it converts back from UTC to the session time zone.
You can change the session time zone by using the SET TIME ZONE command. Preferably, you should use the standard IANA time zone identifiers. For example:
SET TIME ZONE 'Europe/Paris'
or
SET TIME ZONE 'UTC'
Alternatively use the TIMESTAMP [WITHOUT TIME ZONE] type instead, which does no conversions.

Postgres timestamp with timezone

I have column 'event_date_time' in my 'events' table with type 'timestamp with timezone'. My python flask application is saving date like '2014-08-30 02:17:02+00:00' but postgres automatically converts it to '2014-08-30 07:17:02+05'. It converts the timestamp to my local timezone i-e Pakistan. I want to save it without converting.
I have tried
set timezone='UTC'
and it does change timezone to 'UTC' but pgadmin3 is still saving the converted time.
I am using MAC OS and Postgresql 9.3.
The reason pgadmin is displaying hours +5 is because your system timezone is set to this.
When you save a "timestamp with time zone" value at GMT + or - any value, the system offsets whatever timezone your input was to GMT (or UTC), so that when you go to retrieve it, you can specify the timezone you want it displayed in.
For example let's establish a current time for say... New York.
select now()::timestamp with time zone at time zone 'America/New_York';
At the time of asking it returned '2014-08-23 08:50:57.136817'. 8:50 Saturday morning, or 8:51 if you're being pedantic.
Now if we take that same time and display it in GMT we will see a different result:
select '2014-08-23 08:50:57.136817 America/New_York'::timestamp with time zone at time zone 'GMT';
Now have a new time of '2014-08-23 12:50:57.136817'... 5 hours into the "future"!
Finally let's get the original timestamp and display it in what I believe is the Pakistan time zone (PKT) and see what it shows
select '2014-08-23 08:50:57.136817 America/New_York'::timestamp with time zone at time zone 'PKT';
The result? '2014-08-23 17:50:57.136817' further into the future still!
Again I must stress the reason it can do this is because it is always converting the input time offset to UTC or GMT. Postgres processes all of its "timestamp with time zone" data types in this way. It is designed to avoid time zone problems such as daylight savings and so on.
Your issue appears to be that python is inserting the time at an offset of +00, and if this was supposed to be a local time then you will be 5 hours off as far as postgres is concerned. Without knowing exactly what queries python is making, I would assume you may want to look at that to make sure it is giving you the correct time, presumably set timezone='PKT' should be a fix. Either way, when you are viewing timestamp with time zone using a browser such as pgadmin, the timestamp is being converted to your local timezone and this is why you see +5.
Alternatively if you do wish to see those times at +00 then you must specify that you want this in your SELECT queries.

PostgreSQL wrong converting from timestamp without time zone to timestamp with time zone

I faced with the following issue this morning:
select '2011-12-30 00:30:00'::timestamp without time zone AT TIME ZONE 'EST5EDT';
returns me 2011-12-30 05:30:00+00 witch is wrong.
But next queries below:
select '2011-12-30 00:30:00'::timestamp without time zone AT TIME ZONE 'UTC-5';
select '2011-12-30 00:30:00' AT TIME ZONE 'EST5EDT';
i see right date 2011-12-29 19:30:00
Preventing your question about my local timezone:
SELECT current_setting('TIMEZONE');
current_setting
-----------------
UTC
(1 row)
Do anyone have answer why postgresql converts timestamp without time zone some weird way and instead taking away 5 hours it adds instead?
Key things to understand
timestamp without time zone AT TIME ZONE re-interprets a timestamp as being in that time zone for the purpose of converting it to UTC.
timestamp with time zone AT TIME ZONE converts a timestamptz into a timestamp at the specified timezone.
PostgreSQL uses ISO-8601 timezones, which specify that east of Greenwich is positive ... unless you use a POSIX timezone specifier, in which case it follows POSIX. Insanity ensues.
Why the first one produces an unexpected result
Timestamps and timezones in SQL are horrible. This:
select '2011-12-30 00:30:00'::timestamp without time zone AT TIME ZONE 'EST5EDT';
inteprets the unknown-typed literal '2011-12-30 00:30:00' as timestamp without time zone, which Pg assumes is in the local TimeZone unless told otherwise. When you use AT TIME ZONE, it is (per the spec) re-interpreted as a timestamp with time zone in the time zone EST5EDT then stored as an absolute time in UTC - so it's converted from EST5EDT to UTC, i.e the timezone offset gets subtracted. x - (-5) is x + 5.
This timestamp, adjusted to UTC storage, is then adjusted for your server TimeZone setting for display so that it gets displayed in local time.
If you instead wish to say "I have this timestamp in UTC time, and wish to see what the equivalent local time in EST5EDT is", if you want to be independent of the server TimeZone setting, you need to write something like:
select TIMESTAMP '2011-12-30 00:30:00' AT TIME ZONE 'UTC'
AT TIME ZONE 'EST5EDT';
This says "Given timestamp 2011-12-30 00:30:00, treat it as a timestamp in UTC when converting to timestamptz, then convert that timestamptz to a local time in EST5EDT".
Horrible, isn't it? I want to give a firm talking to whoever decided on the crazy semantics of AT TIME ZONE - it should really be something like timestamp CONVERT FROM TIME ZONE '-5' and timestamptz CONVERT TO TIME ZONE '+5'. Also, timestamp with time zone should actually carry its timezone with it, not be stored in UTC and auto-converted to localtime.
Why the second works (so long as TimeZone = UTC)
Your original "works" version:
select '2011-12-30 00:30:00' AT TIME ZONE 'EST5EDT';
will only be correct if TimeZone is set to UTC, because the text-to-timestamptz cast assumes TimeZone when one isn't specified.
Why the third one works
Two problems cancel each other out.
The other version that appears to work is TimeZone independent, but it only works because two problems cancel themselves out. First, as explained above, timestamp without time zone AT TIME ZONE re-interprets the timestamp as being in that time zone for conversion to a UTC timestamptz; this effectively subtracts the timezone offset.
However, for reasons I beyond my ken, PostgreSQL uses timestamps with the reverse sign to what I'm used to seeing most places. See the documentation:
Another issue to keep in mind is that in POSIX time zone names, positive offsets are used for locations west of Greenwich. Everywhere else, PostgreSQL follows the ISO-8601 convention that positive timezone offsets are east of Greenwich.
This means that EST5EDT is the same as +5, not -5. Which is why it works: because you're subtracting the tz offset not adding it, but you're subtracting a negated offset!
What you'd need to get it correct is instead:
select TIMESTAMP '2011-12-30 00:30:00' AT TIME ZONE 'UTC'
AT TIME ZONE '+5';