Handling timezones - sql-server

I have a view on a database that gets me the status of some work items. For example, it gets a start date, and end date, and then does some maths based on GetDate() to return me a 'Work Remaining' type of answer.
Problem is, the database server is in the United States and I am sitting in Australia.
So, the time here now is 19h33 on the 20th of July, and GetDate() on the server returns 02h33 on the 20th.
How should timezones be handled? Should my userprofile have a timezone field, and I deduct or add hours on the client side? Problem with that is that everything needs to manipulate dates and times. That is, the application, and any reports.
I have a view, for example, that returns me the remaining hours of a particular piece of work. It uses GETDATE() to calculate this:
ALTER VIEW [dbo].[vwSprintSummary] AS
SELECT
SprintId,
SprintName,
MIN(DateValue) AS FirstSprintDate,
MAX(DateValue) AS LastSprintDate,
SprintEndDate,
COUNT(DISTINCT PersonId) AS AssignedPeople,
COUNT(DISTINCT ProjectResourceId) AS AssignedRoles,
SUM(AssignedProductiveHours * CanBurnDown) AS Capacity,
SUM(CASE WHEN CAST(GETDATE() AS DATE) <= DateValue THEN AssignedProductiveHours* CanBurnDown ELSE 0 END) AS RemainingCapacity
FROM [vwSprintDailyBreakdown]
GROUP BY SprintName, SprintId, SprintStartDate, SprintEndDate
GO
Somehow, I need to change the GetDate() to a 'DATEADD...' so that I can get answers in the correct time zone?
In this case, a 'fix' would be to change the GETDATE() to DATEADD(HOUR, 17, GETDATE())
Hardcoded, I know, but in essence, that would fix a problem.
Is there no way to somehow tell the server my zone, and get it to return dates based on my location?

Generally speaking, store all information in your database in UTC and do all business-logic processing in UTC too, only convert to a local timezone in your presentation-logic layer - this approach will save you no-end of trouble, and means that the database server can (and should) remain blissfully unaware of your timezone.
In my own projects I tend to trust the webserver's clock rather than the database server's clock, so I never use GETUTCDATE() on the SQL Server, instead I provide all dates and times to the as a SQL parameter, e.g. a query to find "orders placed today" will provide its own definition of "today" (i.e. by providing a minimum and maximum date/time value).

Related

Dynamic dates in SSRS

I need to make a report of all patients who had an appointment last week. This report will be added to another excel with some lookups and then put into Power BI because we don't have way of connecting our sql server.
I'm trying to reduce the amount of manual work I have to do by instead of using parameters with dates, adding a dynamic date.
I have tried using TODAY, CURRENT_DATE and they all come back with an error.
I just need it to give me data for 7 days prior to the current date
Any help would be greatly appreciated.
This is what the first part looks like:
SELECT
PM.vwApptDetail.Patient_Last_Name
,PM.vwApptDetail.Patient_First_Name
,PM.vwApptDetail.Patient_DOB
,PM.vwApptDetail.Appointment_DateTime
,PM.vwApptDetail.Appt_Type_Desc
,PM.vwApptDetail.Resource_Desc
,PM.vwApptDetail.Status
FROM
PM.vwApptDetail
WHERE
PM.vwApptDetail.Appointment_DateTime >
I ended up using:
WHERE Appointment_DateTime BETWEEN GETDATE() AND DATEADD(DAY, -7, GETDATE())
and it seems to have worked.

SQL Server calendar zero point '1900-01-01 00:00:00' is fixed?

Is this date '1900-01-01 00:00:00', which is zero point in SQL Server's calendar, fixed for good or it is dynamic according to century or system settings or something else?
The DateTime type stores a range of dates and times internally as two integers (date part and time part), with the date part holding the number of days before or after 01-01-1900 (negative values for before).
If Microsoft were to change the meaning of 0 (being 01-01-1900) in a future release, it would invalidate the data being stored in the table (as users would see different dates being displayed) - so it will not happen.
If they did need to change the datetime type, they would bring out a new type (say datetime3), but datetime would still be there - for backwards compatibility.

Group by 24hr Period starting at 7:00 AM

I have some high frequency data that I need to group by 24hr period starting at 7:00 AM. How can I do that?
For example, there is a timestamp every 5 minutes and I want to group it by day, but each day starts at 7:00 AM.
How would I go about doing that?
SQL Server 2016.
I am going to presume your time is probably in UTC.
I would look at converting the time to the timezone you need. Then it gives you more options of how you want to deal with the data, also you could customize the report for people in different zones. For some info about timezones I found this stackoverflow post.
Convert datetime value from one timezone to UTC timezone using sql query
Something like this in an group by clause should work. The code below says if the hour is under 8 then it's still yesterday, else it's really today. You would need to replace the getdate() with the correct column. If I Am correct about that the times are in UTC/GMT I would recommend looking at just converting it to the timezone you want.
case when datepart(hh, getdate())<8 then
cast((DATEADD(day, -1, getdate())) as date)
else
cast(getdate() as date)
end

Filtering table record based on time availability in SQL Server

I have one table tblAvailability in which I have two column StartTime time and EndTime time.
There I set StartTime=7 AM and EndTime=10.
Now I have filter in front end which send time range like 6 TO 10 OR 7:30 TO 10 like this.
I wrote the SQL query like below.
Where CONVERT(varchar, StartTime, 108) >= CONVERT(varchar, #startTime, 108)
AND CONVERT(varchar, EndTime, 108) <= CONVERT(varchar, #endTime, 108)
Now I would like to filter out rows based on start and end time range, means would like to get all records table whose start and end time ranges between selected time range.
As mentioned in the comments above, you are not clear whether you are using time of date or date and time. Can you please post more information.
You should be aware that date types and ranges in SQL Server can differ to a client language such as C# (although you don't mention your client language). For example, if you are using SQL Server "datetime" you can restrict the client date range in C# by using the appropriate type, e.g.
System.Data.SqlDbType.DateTime
You say you have written a query you want to use as to filter some data, which I assume you run within SQL Server.
Assume using C# as the client, an efficient way of returning data is to write a View in SQL Server and add this to an Entity Framework model. To query this data at the client, use LinqSQL which will convert your client code into SQL and runs surprisingly efficiently.
var filteredData = (from i in _db.vw_SomeData where i.StartDate >= fromDate && i.EndDate < toDate select i).ToList()
Be careful of your data endpoints (inclusive and exclusive values). If you use SQL Server datetime and you want all times within a day, then I use (date >= today and date < tomorrow) which is guaranteed to work. trying to test against the last second of the day with a "less than or equals" won't work where there is a time between the last second and midnight.
To sum up, comparing date and or time is best performed natively for those types. Only where some of the comparison data is a string should you convert one to the other. The only easily sortable and comparable date and time is yyyymmdd and HHmmss

how to convert all datetime columns in a sql server 2005 express database with data to UTC

background: We recently upgraded to handle UTC. ie., went thru each sp and func and changed the t-sql code to handle utc. For eg., changed getdate() to getutcdate() etc. For new shipments we are good where the db is blank. For our older customers who want to keep their data we need to run a script that will update all the dates to utc. I am about to code in t-sql something like below and want to know if this is best way. Below is pseudo code. thanks
foreach (table in mydb.tables())
{
foreach (column col in table)
{
if (col.type == datetime)
{
update table set col = fn_convert_date_to_utc(col)
}
}
}
Assuming you know the offset between UTC and the timezone the data is stored in, it's pretty simple:
DECLARE #offset INT;
SET #offset = <offset>;
UPDATE table SET col = DATEADD(HOUR, #offset, col);
Note that might be negative or positive, I have no idea which side of Greenwich you are.
Of course this gets more complicated if you are in a timezone that observes daylight saving time; in this case you may need a more expansive solution such as using a calendar table. This is particularly complex if your data extends back before George Bush changed the American DST rules, for example. I do have an article from a long time ago that may be useful; a more recent series is here:
Handle conversion between time zones in SQL Server - part 1
Handle conversion between time zones in SQL Server - part 2
Handle conversion between time zones in SQL Server - part 3
Also if any of your data falls in that window between 12:00 AM and 2:00 AM on a spring forward/fall back day, where I am never sure whether it is right to change it because it's the changeover day or to not change it because it's before 2 AM.

Resources