I am storing timestamps in database as expressed in UTC, e.g. '2015-03-27 08:32:46.024 +00:00'
And I am using the current servers timezone to convert the timestamps to local time.
select
SWITCHOFFSET (CAST(CAST('2015-03-27 08:32:00.000 +00:00' AS datetime2(3)) as DateTimeOffset(3)), DATEPART(TZ, SYSDATETIMEOFFSET ()) )
This works fine as long as I look to wintertime timestamps in wintertime.
For last Fridays time wintertime timestamp get expressed in summer time: '2015-03-27 10:32:00.000 +02:00'.
I would like to see 2015-03-27 09:32:00.000 +01:00.
Anyone that has a solution without storing winter- and summertime in the database?
As I mentioned in the question's comments, this is usually best done in application code, rather than in the database. However, there are some scenarios where having it in the database can be quite useful, or necessary. For example, you may need to group by a date in a specific time zone, or you may need to convert many items in bulk, or generate data for a reporting system.
For these, you can use my SQL Server Time Zone Support project.
Follow the installation instructions, then you can do this:
SELECT Tzdb.UtcToLocal('2015-03-27 08:32:46.024', 'Europe/Paris')
I am guessing at your time zone. You can choose any from the list here.
Related
I having an column of UNIX time stamp in my database table, which comes from a system that is in the Kuwait time zone.
My database server's time zone is Eastern Time US & Canada. Now I need to convert the UNIX time stamp in to Kuwait time zone date value using an SQL query.
Can anyone tell me how I can convert this UNIX time stamp into a Kuwait time zone date value?
Unix timestamps are integer number of seconds since Jan 1st 1970 UTC.
Assuming you mean you have an integer column in your database with this number, then the time zone of your database server is irrelevant.
First convert the timestamp to a datetime type:
SELECT DATEADD(second, yourTimeStamp, '1970-01-01')
This will be the UTC datetime that corresponds to your timestamp.
Then you need to know how to adjust this value to your target time zone. In much of the world, a single zone can have multiple offsets, due to Daylight Saving Time.
Unfortunately, SQL Server has no ability to work work time zones directly. So if you were, for example, using US Pacific time, you would have no way of knowing if you should subtract 7 hours or 8 hours. Other databases (Oracle, Postgres, MySql, etc.) have built-in ways to handle this, but alas, SQL Server does not. So if you are looking for a general purpose solution, you will need to do one of the following:
Import time zone data into a table, and maintain that table as time zone rules change. Use that table with a bunch of custom logic to resolve the offset for a particular date.
Use xp_regread to get at the Windows registry keys that contain time zone data, and again use a bunch of custom logic to resolve the offset for a particular date. Of course, xp_regread is a bad thing to do, requires certain permissions granted, and is not supported or document.
Write a SQLCLR function that uses the TimeZoneInfo class in .Net. Unfortunately, this requires an "unsafe" SQLCLR assembly, and might cause bad things to happen.
IMHO, none of these approaches are very good, and there is no good solution to doing this directly in SQL. The best solution would be to return the UTC value (either the original integer, or the datetime at UTC) to your calling application code, and do the timezone conversion there instead (with, for example, TimeZoneInfo in .Net or similar mechanisms in other platforms).
HOWEVER - you have lucked out in that Kuwait is (and always has been) in a zone that does not change for Daylight Saving Time. It has always been UTC+03:00. So you can simply add three hours and return the result:
SELECT DATEADD(hour, 3, DATEADD(second, yourTimeStamp, '1970-01-01'))
But do recognize that this is not a general purpose solution that will work in any time zone.
If you wanted, you could return one of the other SQL data types, such as datetimeoffset, but this will only help you reflect that the value is three hours offset to whomever might look at it. It won't make the conversion process any different or better.
Updated Answer
I've created a project for supporting time zones in SQL Server. You can install it from here. Then you can simply convert like so:
SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'Asia/Kuwait')
You can use any time zone from the IANA tz database, including those that use daylight saving time.
You can still use the method I showed above to convert from a unix timestamp. Putting them both together:
SELECT Tzdb.UtcToLocal(DATEADD(second, yourTimeStamp, '1970-01-01'), 'Asia/Kuwait')
Updated Again
With SQL Server 2016, there is now built-in support for time zones with the AT TIME ZONE statement. This is also available in Azure SQL Database (v12).
SELECT DATEADD(second, yourTimeStamp, '1970-01-01') AT TIME ZONE 'Arab Standard Time'
More examples in this announcement.
Let's say I have a table with a date column; can I attach some sort of "watcher" that can take action if the date gets smaller than getdate()? Note that the date is larger than getdate() at the time of insertion.
Are there any tools that I might be unaware of in SQL Server 2008/2012?
Or would the best option be to poll the data from another application?
Edit: Note that there is no insertion/update taking place.
You could set up a SQL Job which runs periodically and executes a stored procedure which can then handle the logic around past dates.
https://msdn.microsoft.com/en-gb/library/ms187910.aspx
For example a SQL Job could be set up to run once daily to find out user's birthdays and send out an automated email.
In your case a job could be set up every minute (if required) which detects past dates and does something with those records. I would suggest adding some kind of flag to each record so that it isn't actioned the next time the job runs.
Alternatively if you have a lot of servers and databases, you could centralise your job scheduling using a third-party tool such as ActiveBatch.
I would love to insert a default value into a column with data type datetime2(7). However, because my website is hosted on a server in a different timezone, the getdate function doesn't work properly. I wonder if there is a solution to this. I have done some research and found two ways.
First is to use GetUTCDate() function. However, I would need to do the conversion when I display the information. I am sure my web application is used for only my timezone. So I would like to avoid this.
Second way, this is the closest I could get this done by using SwitchOffSet function:
CREATE TABLE [dbo].[Test_Date](
[test_id] [int] NOT NULL,
[test_date] [datetime2](7) NOT NULL
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Test_Date] ADD CONSTRAINT [DF_Test_Date_test_date] DEFAULT (switchoffset(CONVERT([datetimeoffset],getutcdate()),'+13:00')) FOR [test_date]
GO
However, my problem is the +13:00 cause in the next few months, it will be +12:00 cause of the day light saving time change. As a result, I would need to change it every time. Anybody has a solution to this?
Thanks.
SELECT GETDATE() AT TIME ZONE 'UTC' AT TIME ZONE 'Central Standard Time'
You need the first 'AT TIME ZONE UTC' in order to tell the DB what the value currently is in, so it knows how to get to the second given time zone, 'Central Standard Time' in my example.
You can use SYSDATETIMEOFFSET function
select SYSDATETIMEOFFSET()
MSDN description:
Returns a datetimeoffset(7) value that contains the date and time of the computer on which the instance of SQL Server is running. The time zone offset is included.
More on MSDN.
Based on clarification in the comment below:
Because you want to store the local time of the client, SQL Server has no way of knowing what is your local time. The best option that would work best would be to send the current time from the client each time.
Since Sql Server 2016 you can use AT TIME ZONE...
SELECT CONVERT(datetime2(0), '2015-03-29T01:01:00', 126)
AT TIME ZONE 'Central European Standard Time';
... as specified in the documentation
Just store the data in UTC, and use a calendar table to calculate offsets when you read the data (see these tips: part 1, part 2, part 3). Related Q & A:
GET UTC Date of a past date
Daylight saving time and time zone best practices
Best Practices working with Datetimeoffset
how to convert all datetime columns in a sql server 2005 express database with data to UTC
Where to set a UTC datetime value in n-tier application: Presentation Layer, Domain, or Database?
How do I handle the timezones for every Chat message
since the db timezone info is different with your web server, its best you explicitly pass your desired datetime value from your web app to the db, instead of using db server-side default function.
Getdate() function to get date for Japan Standard Time Zone[JST]
SELECT CAST( GETDATE() AT TIME ZONE 'Asia/Tokyo' AS Date )
I'm creating an online Calendar app (like Google Calendar or MS Outlook), and not sure how I should store the data to make it fast to query for the basic views: Daily, Weekly, Monthly.
Before you mark this as a duplicate, please keep in mind I have read several threads here and in most cases they say "too hard to optimize for general purposes". In my case this is a very specific purpose that I haven't seen asked about yet -- a very specific type of data which many developers have [hopefully] had experience with.
I need to quickly get any rows that land inside my view (day, week, month), so something like:
[end date of row] >= [start date of query]
AND
[start date of row] <= [end date of query]
I don't see a normal b-tree index working well for this, but I also suspect someone has figured out something clever that will work with SQL Server 2005 (and probably older), since calendar apps have been around forever, and there are 100s of them.
I'm also curious about reoccurring events, how to store those, although my current plan is to just always read all of those (index by "Is Recurring") and optimize that in code, and not SQL. There shouldn't be a huge number of those, unlike normal events which could get very large over time.
Update: Also unique to this question, because it is for a calendar app, I need to store dates with timezone info, but my queries cannot be timezone specific. If you have experience with a Calendar app, you'll know what I mean (if not, you'll just say store as UTC).
I've had to work with something similar to this a while back. It was emergency room software and we had to do a lot of date range and shift calculations and couldn't have time zone issues affect us. What we ended up having to do is store 6 columns for each date. A set three columns (Date, Date as int, and time as int) once as entered and once as UTC. All calculations are done using UTC to avoid timezone issues. You could also add in a timezone column if needed.
Date as datetime -- in the time zone entered - Used for display
UDate as a datetime -- The UTC version of the date.
-- Used for display and some calculations
IntDate as int -- Date as an int YYYYMMDD so 20130417
IntUDate as int -- UTC date as an int.
IntTime as int -- Time as an int HHMMSS.
-- So for 1:12:40 PM it would be 131240 and for 1:12:40 AM
-- it would be 11240. Note only 5 places.
-- May need to be decimal if you need more precision)
IntUTime as int -- Sames as IntTime but for the UTC datetime
You may not need the time columns. We did because of the shift calculations. Create indexes on the columns as needed. At least the IntDate and IntUDate columns. Because these are integers the indexes will be blazing fast. Note that all calculations should be done using the UTC columns to avoid timezone issues. Displays are done typically with the Date column.
Next create a date table. What you have to realize here is that this table is fairly narrow and you can fill in hundreds of years worth of dates and still not have that large a table. Aprox 36525 rows per 100 years. Add in indexes and again it's very fast.
Ours looked something like this.
CREATE TABLE DateTable (
[Date] Int PRIMARY KEY,
[DayOfYear] smallint,
[Month] tinyint,
[Quarter] tinyint,
[Year] smallint,
[LeapYear] bit,
[DaylightSavings] bit
)
With indexes on (Year, DayOfYear), (Year, Month, Day) etc. Whatever you need. Also you can add any other columns you need. Say leap year, holidays, first day of the month, last day of the month etc.
if you need to pull say everything for a given year/quarter you add a join on the datetable and everything is nicely indexed.
Using the example you have above you could do something like this:
SELECT *
FROM MyTable
WHERE EXISTS
(SELECT 1 FROM DateTable
WHERE DateTable.[Date] BETWEEN MyTable.UTCStartDate AND MyTable.UTCEndDate
AND DateTable.[Date] BETWEEN #StartDate AND #EndDate)
Because I think the timezone issue is important to calendar applications, and several existing applications do not handle this well (even Outlook, prior to 2007), I'm adding this info as an answer, and as follow-up to the prior comments.
I hope the Google developers will also read this, because based on http://support.google.com/calendar/answer/2367918?hl=en, it seems they also have the "shift" issue. Here is what they say, which seems wrong/unacceptable to me:
However, this process doesn't always work in cases where a country
decides to change when they switch to DST or even their overall time
zone. If you had created an event before we knew about the change,
Calendar converted your time zone into UTC, using the information
available at the time of creation. Once the time zone change is known,
Calendar will use the new rule to display events in your time zone,
and it might cause events to shift in your calendar.
The last part in bold is what should NEVER happen. If I set a meeting for 8am PST, it will be at 8am PST, it will not "shift" just because some timezone rules change.
In a calendar applications, if a user enters an event for "April 26, 2020, 12:00pm, Arizona Time". If you convert this to UTC for storage, as most applications do, you will be saving that as (with the rules at the time of me typing ths) "April 26, 2020, 7:00pm, UTC".
Then, if you want to do a query to find out if there are any events happening at "April 26, 2020, 12:00pm, Arizona Time", you would query for "April 26, 2020, 7:00pm, UTC", because that is what the current conversion rules tell you to do.
At first you would find the item, correct, yeah.
Now, if the Timezone rules change, say in the year 2018 Arizona becomes -0800 UTC instead of -0700 UTC (maybe they decide to support DST, who knows). Then you do your query again, looking for any events happening at "April 26, 2020, 12:00pm, Arizona Time". This time, when you do the query, you are going to look for "April 26, 2020, 8:00pm, UTC". This is because you only know to use the current rules when you do your query, you don't know that some of your data used an older rule when it was saved. So you don't find the item, even though you should have, and the user misses the event.
Now, how you decide to display that item is different from app to app, but for a calendar/schedule app it should never change the time from what the user entered. It should still be displayed as "April 26, 2020, 12:00pm, Arizona Time" when the user views it. However, the UTC value you use to base your queries on, doesn't match that time, because of the rules change.
The way a good calendar app should handle this (from what I've learned after much research) is:
Store the following info for each time entered by the user:
The Time Zone (in Windows I use the Windows Time Zone ID, but this can come from other sources, so long as it is unique and is what you use to do your conversions with).
Date and Time as entered by the user
Date and Time converted to UTC using the rules at the time the user entered the info (problem area)
Anytime Time Zone rules change, make sure your conversion code is updated (i.e.-Windows Updates, library update, etc), AND within the same update process, update all UTC times in your database using the new rules.
The "update" process is something like this:
Query for all records with the Time Zone that changed. Can filter for records that have a date after the rules change if you want, since any before that have not changed (this would be based on the date as the user entered it, not the UTC value).
For each of those records (doesn't matter if you didn't filter exactly, or even if you just blinding do this for every record in the DB in every time zone)... run the same conversion code you did when the record was added/edited last, just take the value the user entered and convert it to UTC using the current rules, and save that new UTC value.
The proof that this mess is required is that the results will be that some of your UTC values have changed, and none of the values the user entered have changed (because we can't allow that, that would be silly for a calendar app, unless the event time was UTC based, in which case the user should have set the timezone to UTC when they added it).
Think about what happens if you don't do this update process. All of the queries you do based on UTC are incorrect. How could they not be?
I have a datetime column in a table called 'createdDate' were the default value is set to getutcdate(). However when a row is added to the table the createdDate's time value is 1 hour behind the system time. So my question is how do I increase the current database system timestamp by 1 hour?
Thanks in advance.
It sounds like your servers are aware of daylight saving (GMT, BST and so on), and your database is resolutely using UTC.
Use GetDate() if you want your dates in the database to match the database server's time.
Alternatively, uncheck the box to "automatically adjust clock for daylight saving changes" in the Date and Time properties on your server and continue to use GetUtcDate().
The database server is probably in a time zone that has a one hour offset from UTC time. Take a look at the MSND entries for GetDate() and GetUtcDate(), respectively.
You should always ensure that your server and your DB agree on timezones and DST changes.
IMO you should always settle on UTC, since that insulates you from any subtle errors as a result of disparate DST changes (such as what happened in the US last year).