Wondering if I'm doing this correctly or if I went too far or not far enough.
I have a scheduling/POS system which each location has it's own data.
Each location will report on it's own data.
The "owner" will be able to run reports for all locations.
I'm storing datetime as UTC.
Each location has it's timezone stored.
The end user passes over appointment information to the application which calls a stored proc. This grabs the locations stored timezone and converts local to UTC.
DECLARE #offeset VARCHAR(6)
SELECT #offeset = tz.current_utc_offset FROM sys.time_zone_info tz
INNER JOIN Location cl ON cl.TimeZoneStandardName = tz.[name]
WHERE cl.LocationID = #locationID
DECLARE #newStart DATETIME = dbo.fnConvertLocalToUTC(#startTimeLocal, #offset)
DECLARE #newEnd DATETIME = dbo.fnConvertLocalToUTC(#endTimeLocal, #offset)
Function: fnConvertLocalToUTC
ALTER function [dbo].[fnConvertLocalToUTC](
#datetime datetime2,
#offset varchar(6)
)
returns datetime2
as
BEGIN
return SWITCHOFFSET(CONVERT(datetimeoffset, CONVERT(varchar, #datetime, 121) + ' ' + #offset), 0)
END
Pulling a list of today's appointments I created a view that contains the following to convert UTC back to their local time.
SELECT ....
, CONVERT(VARCHAR(19), dbo.fnConvertUTC(a.StartTimeUTC, cl.TimeZoneStandardName), 120) AS StartTime
, CONVERT(VARCHAR(19), dbo.fnConvertUTC(a.EndTimeUTC, cl.TimeZoneStandardName), 120) AS EndTime
FROM Appointment a
INNER JOIN Location cl ON cl.LocationID = a.LocationID
WHERE
CAST(dbo.fnConvertUTC(a.StartTimeUTC, cl.TimeZoneStandardName) AS DATE) = CAST(dbo.fnConvertUTC(GETUTCDATE(), cl.TimeZoneStandardName) AS DATE)
Function: fnConvertUTC
ALTER function [dbo].[fnConvertUTC](
#datetime datetime2,
#timezonename varchar(60)
)
returns datetime2
as
BEGIN
return CONVERT(datetime, SWITCHOFFSET(#datetime, DATEPART(TZOFFSET, #datetime AT TIME ZONE #timezonename)))
END
Related
How can we pass the date (data type DateTime) in the execution command to run a stored procedure?
Here is the code snippet.
ALTER PROCEDURE [dbo].[datefiltered]
#months_margin int,
#oDate datetime
AS
BEGIN
SELECT *
FROM dbo.table20
WHERE date = oDate
-- more code...
END
I am trying to execute this stored procedure using GETDATE() function or even pass date and time as a string but it's not working.
exec datefiltered 23 getDate()
As you want to apply date filter, you don't need to pass datetime value. You can convert to DATE datatype for equality.
select * from dbo.table20
where date = CAST(#oDate AS DATE)
Also, if you are just passing GETDATE() as default, you can keep getdate as default value, as given below:
Alter procedure [dbo].[datefiltered]
#months_margin int,
#oDate datetime = null
AS
Begin
IF #oDate IS NULL
BEGIN
SET #oDate = CAST(GETDATE() AS DATE)
END
When you call the procedure with default value, you don't need to pass parameter value for it.
exec datefiltered 23 -- getdate() filter is applied automatically
ALTER PROCEDURE [dbo].[datefiltered]
#months_margin int,
#oDate datetime
AS
BEGIN
SELECT *
FROM dbo.table20
WHERE date = CAST(#oDate AS DATE)
-- more code...
END
Executing this stored procedure:
exec datefiltered 23, '2010-02-30'
I use SQL SERVER 2012.
I have stored prcedure:
ALTER PROCEDURE [dbo].[SP_TEST_TLP]
#DateFrom date,
#DateTo date
AS
BEGIN
SET NOCOUNT ON;
select *
from Clients
WHERE DateReview between (#DateFrom) and (#DateTo)
END
As you can see I pass two parameters to stored procedure above and those parameters I use to filter the result in where clause.
My problem is that I need to filter result only by month and year.
For example, if I have passed those parameters:
#DateFrom date = '2016-05-15' ,
#DateTo date = '2016-10-09'
According to stored procedure I will get result between dates above.But I need to get rows from start of the month 05 and end of the month 10 i,e the result should be equivalent to those params:
#DateFrom date = '2016-05-01'
#DateTo date = '2016-10-31'
How can I get the desired result?
You can also use EOMONTH function
select *
from Clients
WHERE DateReview between DATEADD(DAY,1,EOMONTH(#DateFrom,-1) ) and EOMONTH(#DateTO)
Try this :
Here
DATEADD(dd,-(DAY(#DateFrom)-1),#DateFrom) this will give months start date i.e '2016-05-01'
And
DATEADD(dd,-(DAY(DATEADD(mm,1,#DateTo))),DATEADD(mm,1,#DateTo)) will give month end date i.e '2016-10-31'
ALTER PROCEDURE [dbo].[SP_TEST_TLP]
#DateFrom date,
#DateTo date
AS
BEGIN
SET NOCOUNT ON;
SET #DateFrom = DATEADD(dd,-(DAY(#DateFrom)-1),#DateFrom)
SET #DateTo = DATEADD(dd,-(DAY(DATEADD(mm,1,#DateTo))),DATEADD(mm,1,#DateTo))
Updated ---^
select *
from Clients
WHERE DateReview between (#DateFrom) and (#DateTo)
END
Here is one way:
select *
from Clients
where DateReview >= dateadd(day, 1 - day(#DateFrom), #DateFrom) AND
DateReview < dateadd(month, 1, dateadd(day, 1 - day(#DateTo), #DateTo))
This method allows the query to make use of an index on DateReview. You could also do this as:
where year(DateReview) * 100 + month(DateReview)
between year(#DateFrom) * 100 + month(#DateFrom) and
year(#DateTo) * 100 + month(#DateTo)
You can use EOMonth() function
ALTER PROCEDURE [dbo].[SP_TEST_TLP]
#DateFrom date,
#DateTo date
AS
BEGIN
SET NOCOUNT ON;
select *
from Clients
WHERE DateReview between Dateadd(d,1,EOMonth(#DateFrom,-1)) and EOMonnth(#DateTo)
END
I am trying to create dynamic code for date calculation in SQL stored procedures but am having problems executing string expressions and parameters as date expressions.
I want to hold generic string expressions in a table that will create the dates according to the value of the parameters.
for example this is a generic expression :
DATEADD(#TimeResolution, -#IterationN, #CurrentCalc)
as you can see these generic expressions are composed out of parameters to.
in the stored procedures I intend to declare the variables that are in the expression and assign values to them using a select statement from a different table.
the problem is that after deriving these string values and writing the expression it does not give me the date I want but fails.
so for example if I write the following code
declare #Today date
declare #LastYear date
set #Today = getdate()
set #LastYear = DATEADD(year, -1, #Today)
select #Lastyear
it works fine and I will get last year's date.
but when I try something like this :
declare #Today date
declare #LastYear date
declare #Timeresolution varchar(5)
select #Timeresolution = [Timeresolution] from dbo.mytable where rule_id=1//Timeresolution is a varchar column in my table holding the values 'year' or 'month'
declare Iteration int
select #Iteration = [Iteration] from dbo.mytable where rule_id=1 //Iteration is a int column in my table holding the values 1 or 2, or 3
set #Today = getdate()
set #LastYear = DATEADD(Timeresolution , -Iteration , #Today)
select #Lastyear
this gives me a conversion error.
Is there a way to create such dynamic date expressions?
It isn't possible to use a variable for the interval in DATEADD, but you can do something like this:
IF #Timeresolution = 'year'
BEGIN
SET #LastYear = DATEADD(year, -#Iteration , #Today)
END
IF #Timeresolution = 'month'
BEGIN
SET #LastYear = DATEADD(month, -#Iteration , #Today)
END
The code select DATEPART(month,getutcdate()) returns an integer representing the numeric month value of the current date.
The value MONTH is one of a number of predefined options for the interval parameter.
What is the underlying data type of that interval value?
declare #date datetime = getutcdate()
, #interval notNVarChar(16) = 'month' --what type should this be?
--Would it need quotes for assignment?
select DATEPART(#interval, #date)
You can make it parameterize by making a dynamic SQL as below:
declare #date datetime
set #date = GETDATE()
declare #option varchar(50)
declare #sql varchar(max)
SET #option = 'MONTH' --Here you can set other options like hour, second, milisecond etc..
set #sql = 'SELECT DATEPART('+ #option + ',''' + CONVERT(varchar,#date,21)+''')'
print #sql
EXEC( #sql)
There isn't one - you cannot parameterize it.
From the documentation:
DATEPART ( datepart , date )
datepart
Is the part of date (a date or time value) for which an integer will be returned. The following table lists all valid datepart arguments. User-defined variable equivalents are not valid.
(my emphasis)
There are lots of options available like :
day
week
hour
minute
second
millisecond
etc..
PLease go thru thisLINK
In a scenario, I have to check whether daylight savings is in effect or not. Based on the outcome of the check, I have to do some calculations in a SQL server procedure.
What is the best way to quickly check if daylight savings is currently in effect?
I used this Daylight Savings Time Functions in SQL Server that is created by Tim Cullen.
Specifically, the code that I used was:
Start Date Function
CREATE function [dbo].[fn_GetDaylightSavingsTimeStart]
(#Year varchar(4))
RETURNS smalldatetime
as
begin
declare #DTSStartWeek smalldatetime, #DTSEndWeek smalldatetime
set #DTSStartWeek = '03/01/' + convert(varchar,#Year)
return case datepart(dw,#DTSStartWeek)
when 1 then
dateadd(hour,170,#DTSStartWeek)
when 2 then
dateadd(hour,314,#DTSStartWeek)
when 3 then
dateadd(hour,290,#DTSStartWeek)
when 4 then
dateadd(hour,266,#DTSStartWeek)
when 5 then
dateadd(hour,242,#DTSStartWeek)
when 6 then
dateadd(hour,218,#DTSStartWeek)
when 7 then
dateadd(hour,194,#DTSStartWeek)
end
end
End Date Function
CREATE function [dbo].[fn_GetDaylightSavingsTimeEnd]
(#Year varchar(4))
RETURNS smalldatetime
as
begin
declare #DTSEndWeek smalldatetime
set #DTSEndWeek = '11/01/' + convert(varchar,#Year)
return case datepart(dw,dateadd(week,1,#DTSEndWeek))
when 1 then
dateadd(hour,2,#DTSEndWeek)
when 2 then
dateadd(hour,146,#DTSEndWeek)
when 3 then
dateadd(hour,122,#DTSEndWeek)
when 4 then
dateadd(hour,98,#DTSEndWeek)
when 5 then
dateadd(hour,74,#DTSEndWeek)
when 6 then
dateadd(hour,50,#DTSEndWeek)
when 7 then
dateadd(hour,26,#DTSEndWeek)
end
end
I then use the functions like this in my query:
declare #DLSStart smalldatetime
, #DLSEnd smalldatetime
, #DLSActive tinyint
set #DLSStart = (select MSSQLTIPS.dbo.fn_GetDaylightSavingsTimeStart(convert(varchar,datepart(year,getdate()))))
set #DLSEnd = (select MSSQLTIPS.dbo.fn_GetDaylightSavingsTimeEnd(convert(varchar,datepart(year,getdate()))))
if #Date between #DLSStart and #DLSEnd
begin
set #DLSActive = 1
end
else
begin
set #DLSActive = 0
end
select #DLSActive
In Western Europe, the summer time starts the last Sunday of March at 02:00
select
DATEADD(
day,
DATEDIFF(
day,
'1900-01-07',
DATEADD(month,DATEDIFF(MONTH,0,concat(year(getdate()),'-03-01')),30)
)/7*7,
'1900-01-07 02:00'
) as SummerTimeStarts
and ends the last Sunday of October at 03:00
Select
DATEADD(
day,
DATEDIFF(
day,
'1900-01-07',
DATEADD(month,DATEDIFF(MONTH,0,concat(year(getdate()),'-10-01')),30)
)/7*7,
'1900-01-07 03:00'
) as SummerTimeEnds
It gives as en function :
CREATE function [dbo].[DateIsSummerTime]
(#datetime datetime)
RETURNS bit
as
begin
declare #SummerTimeStarts datetime, #SummerTimeEnds datetime
set #SummerTimeStarts = (select DATEADD(day,DATEDIFF(day,'1900-01-07',DATEADD(month,DATEDIFF(MONTH,0,concat(year(getdate()),'-03-01')),30))/7*7,'1900-01-07 02:00'))
set #SummerTimeEnds = (Select DATEADD(day,DATEDIFF(day,'1900-01-07',DATEADD(month,DATEDIFF(MONTH,0,concat(year(getdate()),'-10-01')),30))/7*7,'1900-01-07 03:00'))
Return Case when #datetime > #SummerTimeStarts and #datetime < #SummerTimeEnds then 1 else 0 end
end