I have a TIMESTAMP field in an hsqldb table that I want to set to "2015-02-11 16:02:01.488 America/Los_Angeles", but the insert fails even if I set the column to TIMESTAMP WITH TIMEZONE, the reason being hsqldb seems to support '2008-08-08 20:08:08-8:00' format but not spelled out like America/Los_Angeles. Is there way to make the insert accept America/Los_Angeles type zones ?
Sorry, but hsqldb doesn't support working with IANA/Olson time zones directly. You are correct that TIMESTAMP WITH TIMEZONE only supports a time zone offset. You can review the hsqldb docs for confirmation.
Many databases do not support named time zone. Oracle and Postgres support them, but most others do not.
Consider also that while a named time zone can usually determine the offset, there are still cases of ambiguity around the fall-back daylight saving time transition. In other words, if you had "2015-11-01 01:30:00 America/Los_Angeles", you could not deterministically tell whether it was Pacific Daylight Time (UTC-07:00) or Pacific Standard Time (UTC-08:00). This is why usually just the offset is stored.
The converse is also true though. If you only store "-08:00" then you can't deterministically know that it came from "America/Los_Angeles".
Here's a general guideline that will help:
If the local time is unimportant, then just store a TIMESTAMP based on UTC.
If the local time is important, but the value will never be modified, then store a TIMESTAMP WITH TIMEZONE, using the local time and it's associated time zone offset.
If the local time is important AND the value can be modified, then store a TIMESTAMP WITH TIMEZONE in one column, and the time zone name (ie. "America/Los_Angeles") in a second VARCHAR column, or elsewhere in your database. During an edit operation, use the time zone name to calculate the offset of the new value. It might be the same, or it may be different.
See also DateTime vs DateTimeOffset, which presents a similar argument for .Net and/or SQL Server.
Related
Is there any convention to add in a local timezone (whatever the user has set it as) in a database?
For example, like I can do the following for UTC time:
2014-01-01 01:02:03Z
Is there something like the following to mean local time?
2014-01-01 01:02:03L
Or some other suffix where it can either pick up the user's system time or take it from a variable that can be set? For example, something like (for Postgres):
ALTER DATABASE postgres SET timezone TO 'Europe/Berlin';
This has nothing to do with Postgres.
The format you're asking about is ISO 8601. Specifically in that format, the absence of a Z or an offset such as -07:00 or +05:30 is defined as "local time".
So what you are looking for is a string without an offset, such as 2014-01-01T01:02:03.
postgres would use the system timezone, or what you called local, if no timezone is specified. see manual
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.
...
Conversions between timestamp without time zone and timestamp with time zone normally assume that the timestamp without time zone value should be taken or given as timezone local time.
Your concept is flawed for a couple of reasons:
A user in Germany connects to a Web server in England that connects to a database server is America. What constitutes local?
More to the point Postgres does not store the time zone in with time zone fields. So you will not recover the entered time zone on data retrieval.
If you are dealing with multiple time zones then the field you need to use is timestamp with time zone. This will rotate entered timestamp values to UTC for storage. You now have a fixed point in time that you can rotate to whatever 'local' time you want on retrieval.
Just treat the undecorated time as a timestamp with time zone:
richard=> SET timezone='Europe/London';
SET
richard=> SELECT '2022-08-27 21:42:22.25891'::timestamptz;
timestamptz
------------------------------
2022-08-27 21:42:22.25891+01
(1 row)
richard=> SET timezone='Europe/Paris';
SET
richard=> SELECT '2022-08-27 21:42:22.25891'::timestamptz;
timestamptz
------------------------------
2022-08-27 21:42:22.25891+02
(1 row)
I want to update a date with a timezone (+2 hours) but it ends up as UTC (0 hours)
Date type is 'timestamp-with-timezone'
Query...
update table set date = '2022-05-25 13:28+02:00'
will end up as this in the database.
2022-05-25 11:28:00+00
What's wrong here?
tl;dr
Nothing wrong. Postgres stores values of TIMESTAMP WITH TIME ZONE in UTC, always an offset from UTC of zero. Any submitted offset or zone is used to adjust to UTC.
Details
Date type is 'timestamp-with-timezone'
No such type in standard SQL, nor in Postgres.
I’ll assume you meant TIMESTAMP WITH TIME ZONE.
it ends up as UTC (0 hours)
Read the fine manual. You are seeing documented behavior.
Postgres always stores values in a column of type TIMESTAMP WITH TIME ZONE in UTC, that is, with an offset of zero hours-minutes-seconds.
Any time zone or offset provided with an input is used to adjust into UTC. That provided zone or offset is then discarded.
So the name of the type TIMESTAMP WITH TIME ZONE is a misnomer. First, the authors of the SQL were thinking in terms of offset, not real time zones. Second, any submitted time zone is not stored. A submitted zone is used to adjust and then discarded.
If you need to track the original offset or zone, add an extra column. You’ll have to add code to store the offset amount or the time zone name.
update table set date = '2022-05-25 13:28+02:00' will end up as this in the database. 2022-05-25 11:28:00+00 What's wrong here?
Nothing is wrong. That is a feature, not a bug. Both of those strings represent the very same simultaneous moment.
FYI, database engines vary widely in their behavior handling date-time types and behaviors.
Some do as Postgres does regarding TIMESTAMP WITH TIME ZONE, adjusting to UTC and then discarding any provided time zone or offset. Some others may not.
The SQL standard barely touches on the topic of date-time handling. It declares a few types, and does that poorly with incomplete coverage of all cases. And the standard neglects to define behavior.
So, be very careful when it comes to date-time handling in your database work. Read very carefully the documentation for your particular database engine. Do not make assumptions. Run experiments to validate your understanding. And know that writing portable SQL code for date-time may not be feasible.
I'm struggling to deal with time zone and daylight saving when querying SAP HANA. The datetime stamp is in the form of NVARCHAR, eg 20210304132500 YYYYMMDDHHMISS in UTC, which means local time is 14:25:00(GMT +01:00) but my query returns 13:25:00 (UTC). How do I edit my results to match local time? Sample query below if that helps.
SELECT DATE_TIME,LOCATION,PART_NUMB
FROM "PUBLIC"."internal.sap.datamodel::ACTIVITY"
WHERE SUBSTRING(DATE_TIME,9,2) IN ('08','11')`
The desired result is local date_time in any format.
HANA comes with timezone conversion functions (UTCTOLOCAL) that can perform the necessary calculations.
These functions require that the data/time input is in either SQL date/time format or that it can be converted to that. They also require that the timezone data has been set up and maintained in the HANA DB. This is the actual information about which timezone has which offsets and daylight saving begin and end times.
For your example, it may make sense to expose the DATE_TIME as a type converted field DATE_TIME_UTC that is already in sql-date time:
to_seconddate (DATE_TIME, 'YYYYMMDDHHMISS') as DATE_TIME_UTC
With this conversion done, you can convert the timezone like this:
UTCTOLOCAL (DATE_TIME_UTC, 'Berlin', 'platform') as LOCAL_DATE_TIME
Note, that the target time zone name may be something like "GMT+1" but this is really just a name and not a calculation instruction. If "GMT+1" is not found in the list of timezone conversions, HANA won't just add an hour - it won't perform the calculation.
With this data type and timezone conversion done, you could have a WHERE clause like this:
WHERE
HOUR(LOCAL_DATE_TIME) IN (8, 11)
This order of transformations (data type -> time zone -> hour component) is of course rather expensive. It may be worthwhile to check whether the resulting query performance is satisfactory on realistic data volume.
Also important to note is that time zone conversion only works on complete date-time information, not just the time. That is to say, if the date is unknown, it cannot be determined which offset rule between two time zone applies. So, simply separating the hours and date components won't help in this case.
Finally, I've written quite a bit about handling date, time, and time zones in HANA, you may want to have a look at that:
The time is now, isn’t it?
Trouble with time?
You got the time?
In PostgreSQL, the data types timestamp and timestamp with timezone both use 8 bytes.
My questions are:
What format is used to store date & time in a timestamp?
How is the time zone information stored in the timestamp with timezone
type, and how is it parsed later when reading the type?
This is just a misunderstanding stemming from the somewhat misleading type name. The time zone itself is not stored at all. It just acts as offset to compute a UTC timestamp (input), which is actually stored. Or as decorator in the display of a timestamp according to the current or given time zone (output). That's all according to the SQL standard.
Just the point in time is stored, no zone information. That's why 64 bit of information is enough. The timestamp is displayed to the client according to the current time zone setting of the session.
Details:
Ignoring time zones altogether in Rails and PostgreSQL
Also, since Jon mentioned it, time with time zone is defined in the SQL standard and thus implemented in Postgres, but its use is discouraged:
time with time zone is defined by the SQL standard, but the definition
exhibits properties which lead to questionable usefulness.
It's an inherently ambiguous type that cannot deal with DST properly.
Looking at the documentation:
Timestamps are stored either as integers, or (deprecated) floating point numbers
I don't believe timestamp with timezone could be correctly encoded within 8 bytes if it actually stored a time zone. Just the timestamp requires 64 bits, as log2(298989 * 365 * 24 * 60 * 60 * 1000000) is greater than 63. Note that time with time zone requires 12 bytes, with the same precision but a range of a single day.
See Erwin's answer to explain how it actually manages to be stored in 8 bytes - it should be called "timestamp without a time zone, but stored in UTC and converted into the local time zone for display". Ick.
I would like to convert the date/time values stored in UTC-0 (GMT) to a user preferred time zone value by passing in the time zone (e.g EST, CST etc). However, SQL Server doesn't seem to have a method that takes in a time zone, but does honor the offset. I was wondering if any one had any luck doing so, so that the date/time value reflects the DST change, when a SQL query is issues against the table that contains these values. Oracle is the only database, that seems to honor the Time Zone as well as offset. Please advice.