Calculate Daylight Savings Time (DST) on SQL/Database level - sql

My location in Sydney, Australia. The dates that I explain will be in UK or Australia date format.
Observe the following:
2010-04-15 04:30:00.000 => 15/04/2010 14:30:00 EST (UK date format - Add 10 hours)
2010-11-05 01:00:00.000 => 05/11/2010 12:00:00 EST (UK date format - Add 11 hours)
Both these times are retrieved from the database in UTC format and then calculated on the Web level whether +10 or +11 hour is applicable.
In Australia, Daylight Savings Time (DST) transition dates vary year by year. The transition dates are usually Early April and Late October.
So how accurate would the Web calculation be? If this year the transition date is a few days later (say 03/04/2010), but the Web calculation bases on a fixed date (say 01/04/2010), wouldn't that mean that the days in between will be off by 1 hour when displayed (due to the fixed calculation nature to a specific day of the month)?
I believe the transition dates is not pre-determined and is actually announced to the public. Is that assumption true?
If not (that means the DST dates are pre-determined), would I be able to do the calculation outside the Web level (on the SQL/Database level)?
The database is SQL Server 2005 and I'm using Report Definition Language (RDL) to display the fields in UTC time. If SQL/database level is not the best way, how do I work out +10 or +11 and format the time accordingly to show the right time?
Thank you.

The database is a bad choice for it: it has less information than c# or .net to work it out. .net uses the registry which is kept upto date periodically by patches. SQL Server would have to have a table with date ranges and offsets.
The transitions are fixed because of scheduling (flights, trains ,whatever). IIRC it only changed once at short notice recently in Australia for some Olympic games and it caused chaos around the world. In 2007 the US changed but this was known in advance.
By fixed, it's the "last Sunday" type fixed even if the date varies.
I would leave it in the web code: the DB does not know where your caller is for example, the web site can work it out.

The problem is whoever wrote this app does not quite understand UTC, its value, and how to use it. The database is the correct location for the dat, but the system is not using UTC as intended.
If you use UTC, then all your date arithmetic should use UTC. In the database. It is currently using a saved UTC and then converting at some (doesn't matter if seciond tier or third) other layer; some other library. Half UTC, and Half something else. Have you considered historic dates, as in what is the DATEDIFF() between 15 Feb 2010 and today ?
This eliminates the concern re DST in Australia or Greenland.; and concern re what date/time the changeover actually happens. Everyone is using Greenwich Mean Time for that particular day.
Do all you date arithmetic in the db, in UTC. And display the result (only) in the local time zone, which as you have it, is the web layer, based on the user.
Many systems have dropped that last step altogether, and display in UTC only, regardless of the user's time zone.

The database can handle DST for you. Use its time zone conversion functions to go from whatever zone you stored the dates in to whatever zone you want to get for the user.
MySQL has CONVERT_TZ(), I don't know what other RDBMS's have.

Related

Storing DATETIME with and without TIMEZONE

Databases often store a datetime without timezone as a separate type as a datetime with a timezone. As an example, I'll use BigQuery (though most databases store this the same):
DATETIME is a date/time that does not store timezone.
TIMESTAMP is a date/time that does store timezone.
I understand abstractly that "Dec 2 at 2:45 PM" is a different time in Japan as it is in New York, but I'm wondering why that even matters if all the dates are stored in UTC by the application. For example, if the value to be inserted is:
2021-12-02 14:45:00
Wouldn't that value be inserted as 2021-12-02 14:45:00 UTC in both data types? Or, would the 2:45PM be stored as "2:45 PM UTC" in the DATETIME type but would be stored as (if using EST) 2:45 PM EST --> 6:45 PM UTC in the TIMESTAMP type?
And if the value was:
2021-12-02 14:45:00 EST
Wouldn't that value also be inserted as 2021-12-02 18:45:00 UTC in both data types, and stored the same way? It seems to only 'timezone' is on the query-side, and can't that act either as a cursor-variable or some sort of metadata on the field (similar to a NULL check)? I guess I'm not following why the timezone-aware and no-timezone need to be stored as two different types if all date/times get stored as UTC anyways.
The SQL standard defines two types for a date with time-of-day:
TIMESTAMP (Also known more clearly in some databases such as Postgres as TIMESTAMP WITHOUT TIME ZONE)
TIMESTAMP WITH TIME ZONE
The first type is meant to purposely lack any context of time zone or offset-from-UTC. So noon on the 23rd of January next year, 2022-01-23 12:00, means noon anywhere and everywhere. It means noon on Tokyo Japan as well as noon on Toulouse France, and also noon in Toledo Ohio US. These are all obviously different moments, several hours apart. Therefore, this type cannot represent a moment, is not a specific point on the time line.
The second type does represent a moment, is a specific point on ne timeline. When you want to track actual moments, such as when a row was written to the database, or when a shipment arrived in a warehouse, use this type.
Unfortunately, the SQL spec says little about the various date-time types and behaviors. So the various database products vary widely in their support for these types and their interpretations of behavior.
In some databases such as Postgres, a value submitted to a column of the fist type (TIMESTAMP WITHOUT TIME ZONE) containing an indicator of zone or offset will have the date and time recorded as submitted. No adjustment is made. Any zone or offset input is ignored and discarded.
In some databases such as Postgres, a value submitted to a column of the second type (TIMESTAMP WITH TIME ZONE) containing an indicator of zone or offset will have its date and time adjusted to UTC before being written to the database. In such databases, this type is always in UTC, that is, represents a moment as seen with an offset of zero.
What is an offset? Merely a number of hours-minutes-seconds ahead of UTC (+) or behind UTC (-). A time zone, in contrast, is much more. A time zone has a name in Continent/Region format, and contains the history past, present, and future changes to the offset used by the people of a particular region as decided by their politicians.
So the TIMESTAMP WITH TIME ZONE type in databases such as Postgres is a misnomer. No time zone information is stored in the database. Any time zone or offset info submitted with the date and time is used to adjust to UTC. The zone/offset info is then discarded. So if remembering the zone originally submitted is important to you, you will need to store that yourself in a second column. Regarding the misnomer, you can think of the type as being TIMESTAMP WITH REGARD FOR SUBMITTED OFFSET OR TIME ZONE. But be clear, in databases such as Postgres your moment is stored in UTC, always UTC, and is retrieved as UTC, always UTC.
Unfortunately, there is a wrinkle here. All too commonly, tooling and middleware will inject a default time zone, adjusting the retrieved UTC moment into some time zone. While well-intentioned, this anti-feature creates the illusion that the value was stored with that time zone. But the values actually stored in UTC, at least with databases such as Postgres.
You asked:
2021-12-02 14:45:00 Wouldn't that value be inserted as 2021-12-02 14:45:00 UTC in both data types?
No.
In a column of a data type akin to the TIMESTAMP WITHOUT TIME ZONE, that date and time will be stored as submitted, a quarter to 3 PM on the second of December this year.
In a column of a data type akin to TIMESTAMP WITH TIME ZONE, the value stored may depend on the behavior of your particular database and your particular middleware, tooling, and driver. The behavior might simply assume you meant 2021-12-02 14:45:00 as seen in UTC, and store that. Or the behavior may assume you meant 2021-12-02 14:45:00 as seen in a particular time zone. And in databases such as Postgres, an adjustment to UTC would be applied before finally storing. You must study the documentation of your particular database, middleware, tooling, and driver to discover which behavior will be seen in your software. Be sure to conduct experiments to verify your understanding.
You asked:
2021-12-02 14:45:00 … Or, would the 2:45PM be stored as "2:45 PM UTC" in the DATETIME type but would be stored as (if using EST) 2:45 PM EST --> 6:45 PM UTC in the TIMESTAMP type?
”Likely yes”, for the first clause. But no EST involved at all. The date is stored as-is, 2021-12-02, along with the time-of-day as-is, 14:45:00. The EST part is ignored and discarded. (But experiment to verify this behavior in your particular tooling.)
And “maybe” for the second clause. As discussed in last bullet above, the behavior for TIMESTAMP WITH TIME ZONE may vary. Read docs, and conduct experiments.
You said:
though most databases store this the same
No, incorrect. That would be a very big “No”.
Databases vary widely in their support for date-time features, their kinds of date-time types, the names of their types, the technical details of their types, and the behaviors of the database server, middleware, drivers, and tooling.
Some older database systems have legacy data types supplanted by newer types, but all still supported, further complicating the picture.
You said:
I guess I'm not following why the timezone-aware and no-timezone need to be stored as two different types if all date/times get stored as UTC anyways.
You incorrectly assume that the “no-timezone” type stores in UTC. It does not.
That is what the “no-timezone” means: no regard for an offset or zone, no consideration for any offset or zone, no adjustment for any offset or zone, and no concept of offset or zone. The TIMESTAMP WITHOUT TIME ZONE type means simply, literally, a date, a time-of-day, and nothing more. Anything more than that is either (a) a figment of your imagination, or (b) interference by your middleware/tooling/drivers.

Datetime Offset Conversion in SQL

I’m working with a table that uses date time offset. I have a value that looks like 2020-01-02 13:30:00 -07:00.
Is the time in my time zone 13:30 or do I need to subtract 7 hours from it. I saw people do it differently on YouTube.
In MS SQLServer, the last section of the string representation that you posted of the DateTimeOffset describes the time zone. So, if you are currently located in time zone -7:00 (e.g., Arizona, USA), then the time portion of the string refers to your local time, not UTC. See the Microsoft documentation:
For example, 1999-12-12 12:30:30.12345 -07:00 should be represented [in UTC] as
1999-12-12 19:30:30.12345Z
Someone would subtract the offset from the number only if they want to manually get the UTC value, but that would might produce errors if the data come from a daylight saving time (DST) region, so you would need to enforce DST handling at the time of entry. SQLServer already stores the data in UTC behind the scenes:
The data is stored in the database and processed, compared, sorted,
and indexed in the server as in UTC.

Trying to reformat timestamp in postgresql

I can't seem to find a question/answer that works for what I'm trying to achieve. Currently, this is how my DB outputs a timestamp:
2015-08-18T19:43:04.738-06:00
However, I would like it to appear as such in the column:
2015-08-18T19:43:04.738 America/Denver
Google has recently changed their formatting options and instead of downloading the output and performing a find/replace, I want an output that doesn't require additional work. I looked on SO and have tried using trim and replace but having no luck.
Thanks for the help in advance!
For whatever reason, the one we've used since February (third from the bottom) no longer works.
2015-08-18T19:43:04.738-06:00 is not quite the right format. Google does not accept milliseconds (which is annoying if they don't just ignore it). You need to send 2015-08-18T19:43:04-06:00. They may have become more strict in what they accept.
Try date_trunc('second', yourtime).
It's not possible to accurately translate an offset like -0600 to a time zone like America/Denver. They say two different things.
-0600 says, with absolute certainty, that this time is 6 hours behind UTC. 12:00:00-06:00 and 18:00:00Z (Z represents UTC) are the same time.
America/Denver means to interpret this timestamp under the rules applicable to the city of Denver, Colorado, USA at that time. To figure out what time it is in UTC you need to look up the offset rules for Denver, Colorado, USA. The offset will change depending on the time of year, usually because of daylight savings time. Because the rules change, it's important to apply the rules as they were at that time.
For example, 2006-03-15 12:00 America/Denver is -0700. But the next year on 2007-03-15 12:00 America/Denver is -0600. Between 2006 and 2007 the daylight savings time rules in the US changed.
Whereas -06:00 avoids all that and simply says the time is offset from UTC by six hours.
You could fake it by simply replacing the offset with America/Denver. So long as you're only sending recent times that should work. You'll be off by at most an hour. But don't do that.
Unless Google Ads specifically needs a time zone there's no point in sending them one. Internally, Postgres is storing your times in UTC anyway and translating them to your server's time zone, America/Denver. Send Google UTC. And, as noted above, chop off the milliseconds.
select date_trunc('second', '2015-08-18T19:43:04.738-06:00'::timestamp with time zone at time zone 'UTC') as datetime;
datetime
---------------------
2015-08-19 01:43:04

Hibernate DST Date mapping issue for timestamps without time zone

I've a problem with storing java.util/sql.Date in PostgreSQL using hibernate: I'm storing dates as timestamp without time zone type. Now, in most cases everything is alright, as I'm mapping it in entities as java.util(sql).Date.
However, I encountered one problem I don't know how to overcome yet:
On March 30th there was a time change (Daylight Saving Time started). In my country it meant switching from local 2am to local 3am.
In my database I have few entries with times between 2 and 3 am, such as
"2014-03-30 02:15:55"
Now, what Java does is it takes this date and displays it as 3:15:55 am, because of the time change. However, I desperately need it to be 02:15:55, exactly how it's stored in the database (basically meaning don't use the +02:00 timezone BEFORE 3am, but use it AFTER). I'm afraid about 26th October as well, that's when the DST ends.
Is this possible using Hibernate and/or Spring? I'd love a global config for such case.
Best,
Marcin
You need to store dates in UTC timezone to ignore DST. See this question How to store date/time and timestamps in UTC time zone with JPA and Hibernate for solutions

SQL Server Jobs / Schedules - US vs. UK Daylight Savings Adjustment

SQL Server Jobs / Schedules - US vs. UK Daylight Savings Adjustment
We have a UK based server which needs to run a SQL Agent Job at 16:30 (US Central time – this may seem strange but it because of the availability of some data). Usually this wouldn’t be a problem because the time difference between the UK and US is 6 hours so we schedule our job for 22:30.
But because the UK and US adjust their clocks at different times in March and November for daylight savings, there is a 2 week period when the time difference between the UK and US is 5 hours.
I would like to implement a way in which SQL Server could identify this change of time difference and then re-schedule the job it’s self using something like sp_update_schedule.
One approach I have is to get the current timestamp on a US based server and then compare that with the current UK time. If the time difference is 5 hours then reschedule the job to 21:30, if the time difference is 6 hours then reschedule the job to 22:30.
But can anyway suggest another solution, perhaps one which wouldn’t involve get the current timestamp on the US based server and ideally not having to store a list of daylight savings adjustment dates in a table. Something more dynamic maybe?
Actually, it looks like you've mentioned the two viable solutions: Ask a server on that timezone or store a list of critical dates. The party line as to why at the first link below. You can implement your own function (which would have to either store a list of dates or ask a server for the offset). Or you can get a public domain list of time zone information (as at the second link below). There are also several web services which will return offsets. Oracle implements that database of time zones to convert between named time zones, so if you already support both you could do that.
There is a C# implementation that you could wrap in CLR functions at the third link.
http://blogs.msdn.com/b/sqlprogrammability/archive/2008/03/18/using-time-zone-data-in-sql-server-2008.aspx
http://www.twinsun.com/tz/tz-link.htm
http://timezone.codeplex.com/