Will an existing timestamp without time zone value ever automatically change? - postgresql

For example, certain time values might auto change when the system time zone changes. Will a timestamp without time zone value that's already stored in the database auto change for any reason at all?

Neither timestamp (timestamp without time zone) nor timestamptz (timestamp with time zone) values will ever change by themselves. Only the display of timestamptz adapts to the current timezone setting.
Or you can display date and time for a given time zone with the AT TIME ZONE construct. And / or you can format it any way you like with various formatting functions.
The actual setting in your session is relevant for display, not the system time zone. Related:
Ignoring time zones altogether in Rails and PostgreSQL
Time zone storage in data type "timestamp with time zone"

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

Common practice for time format in PostgreSQL

What is the common (good) practice for the type of date+time columns in PostgreSQL? Timestamp WITH or WITHOUT time zone? Is it possible to output timestamps in all queries (selects) as a UTC string timestamp even if the column has a type TIMESTAMP WITH TIME ZONE?
Last question first: you can set the timestamp parameter to UTC or use AT TIME ZONE 'UTC'.
What data type to choose depends on how you want to handle time zones:
if you don't care about time zones, use timestamp without time zone
if you want to handle time zones in the application, use timestamp without time zone and store everything in UTC
if you want to handle time zones in the database, use timestamp with time zone and set tge timezone parameter correctly

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.

How to convert local time to UTC?

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.

Specify a time zone to use as the reference time zone

Based on the first two answers, the question was unclear as originally posted, thus I am completely rewriting it:
The following question is concerned only with how and what data is stored, and is no way shape or form concerned with converting data upon retrieval. As such, converting at SELECT to the desired time zone is not an appropriate answer.
When inserting a value into a timestamp with time zone field, it is retrieved (and thus presumably stored) with the timestamp converted to the local time zone of the database at the time it was inserted.
That is so say, a timestamp inserted as 2012-01-01 00:00:00+00:00 is retrieved as 2011-12-31 19:00:00-05, where the local time zone of the database at the time of the insert was -05. Timestamps that were inserted during daylight savings time, when the database was at -04, are returned using the -04 time zone.
What I want is for all timestamps to use an arbitrary time zone when stored (and thus all be retrieved without any additional work as having that time zone). That is to say, were the server orbiting the planet, all times would be at +00:00 (arbitrary time zone), instead of -12:00 to +12:00.
Can I insert into a timestamp with time zone column such that all timestamps are stored relative to an arbitrary time zone? If so, how?
Original follows.
When inserting a value into a timestamp with time zone field, it is being converted to the server's current time zone.
Example: If I insert a value specifying a time zone of -1, retrieving it will give back the time at -5 (the time zone of the server at the time it was inserted).
Is it possible to specify that it should be stored using an arbitrary time zone?
Note: This question is not how to convert the returned time to another time zone, this is specific to how the time is stored.
You have to save the time zone offset in addition to the timestamp.
As #Milen already explained (and linked to the manual): a timestamp only saves a point in time (as abstract value). The time zone modifier is not saved, it only serves to adjust the timestamp relative to UTC.
Consider the following demo:
-- DROP TABLE tbl;
CREATE TEMP TABLE tbl (id int, myts timestamptz, mytz interval);
INSERT INTO tbl VALUES
(1, now() , EXTRACT (timezone from now()) * interval '1s')
,(2, '2012-01-01 00:00-05', interval '-5h')
,(3, '2012-01-01 00:00+04', interval '4h')
,(4, '2012-11-11 20:30+03', interval '3h');
SELECT *
,(myts AT TIME ZONE mytz)::text
|| CASE WHEN mytz > '0:0' THEN '+' ELSE '' END
|| to_char(mytz, 'FMHH24:mi') AS timestamp_at_origin
FROM tbl;
Run it locally to see. Pay special attention to the details of the AT TIME ZONE construct, and how I extract the time zone from the (local!) timestamp with time zone.
now() returns timestamp with time zone or timestamptz for short.
EXTRACT (timezone from now()) * interval '1s'
timestamp_at_origin displays the timestamp with time zone as seen at its origin. If I understood your question, then that is what you are looking for.
You could further improve formatting.
You may be interested in this related question which sheds some light on the ambiguities and pitfalls of time zones.
When inserting a value into a timestamp with time zone field what actually happens is the timestamp is converted to UTC. Another matter altogether is to what time zone that value is converted on output. There are a few ways to control that:
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 (see Section
9.9.3).
You can do your select with an at time zone operator:
select insertTs at time zone 'CST' from table
See more here.
I always store times in GMT so that the client can convert based on it's current GMT offset (the GMT offest is available in most language).
I write C# - so I can easily convert all DateTime objects to GMT using DateTime.ToUniversalTime() as I store data in the database.
I am not sure what language you are using or how to convert all times to GMT in postgressql, but from a logic standpoint - storing all times in GMT will allow a uniform time zone that all other time zones can easily relate to.
Hope this helps!
Greenwich Mean Time