The problem is that a timestamp of “00:00 1 jan” may have a different UTC time depending on the timezone your client is in. So if your laptop is set to Melbourne time then the UTC time would be “14:00 31 Dec”. If your server is set to UTC then the code you deploy would treat it as 0000 UTC. The behaviour changes depending on environment.
This happens because PG silently converts timestamp to timestamptz for many time operations, so the final result will depend on the environment TZ, which you don’t necessarily control or set. From the perspective of the SQL expression, the behaviour becomes nondeterministic.
If you want to guarantee deterministic behaviour you should use timestamptz which does not require conversion.
Timestamp is really only useful IMO when you have a feature such as “enable this setting from 2pm local time wherever the user is”
Side note: As much as I love PG, the implicit casting between these two incompatible types is pretty baffling.
Assuming you send the time in epoch time format, you would use:
select to_timestamp(1628506048);
to convert to a `timestamp with time zone` (yes that is correct). If you insert this value into a database using `timestamp without time zone` then the database forgets that the time is UTC and will use whatever TZ is set on the client that happens to run the query.If you can 100% guarantee that all your devices - developer machines, test machines, VMs, production, the whole works, if you can absolutely 100% guarantee that they are all set to UTC then timestamp and timestamptz are largely the same.
But why take the risk? I can tell you from experience that learning this the hard way is really hard.
I don't see it as a risk, I'd recommend doing that in any instance to save from confusion eventually, but thanks for clarifying in details.
Any chance you have an example query (or instructions to follow) to trigger a bad case? I'd like to verify our setup
I see your point, I need to evaluate the consequences of it
The two types are different and incompatible. Timestamptz refers to a fixed moment in time regardless of your local Timezone. Timestamp refers to the time on the clock wherever you are in the world. A timestamp of “7pm” means “7pm” wherever your server - or client, depending on how it gets executed - happens to be.
It’s really really confusing because select now(), which returns Timestamptz, internally uses UTC time, but prints the time in your local time zone eg ‘10:16 Aug 9 2021+10’ in my case.
Select now()::timestamp prints the same time, but without the timestamp, leading you to think that the former stores the +10, but it doesn’t.
In fact the +10 is telling you that PG knows that the time is UTC and your local TZ is UTC+10. The latter, without the offset, is telling you that PG doesn’t know what time zone the time is in and so can’t convert it to your local time zone.
It is super confusing but the best possible advice is never use a plain timestamp without time zone because it leads to a bunch of subtle errors that will drive you nuts.
Put another way: if you are used to using Unix Epoch Time, then the equivalent data type in PG is timestamptz.
If the client sends 2021-08-08T07:00:00+03 to the server, in either case the offset of +03 is going to be lost. As you know, timestamp will keep the clock time and timestampz will keep the "moment in time" (under the hood by converting to UTC.) I'd argue those are just two different rules for "dropping the offset".
But with timestamptz you don't need to use the timezone in most calculations while with timestamp you do need to use the timezone otherwise unexpected behaviour can creep in.
But yes I do agree that you're technically correct, and that's the best kind of correct after all :)
Do you want PG to store the same value or different values?
If you answer 'same', you want with time zone.
Now your answer might be: "make sure your application doesn't do that" in which case your probably fine either way but then you need to make sure you do that correctly.