convert datetime to UTC value mssql - sql-server

I have the query like this:
SELECT table.a, table.b, table.c from Table table
How i can cast "table.b" to UTC time just adding CAST into the query?
SELECT
table.a,
**%CAST_TO_UTC_FUNCTION to table.b%**,
table.c
from Table table
I'm not able to cast it separately and declaring local variables.

You can write your query as follows:
SELECT
table.a,
dateAdd(
second,
dateDiff(second, getDate(), getUtcDate()),
table.b) as b_converted_to_UTC,
table.c
from Table table
This converts the values in column bto UTC, by adding to those values the tmie difference that currently exists between the local date (getDate()) and the UTC date (getUtcDate()).
In order for the above query to work, the following must be true:
the date(s) stored in column b must be expressed in local time
the server date/time zone should be properly configured

I solved the problem by creating a temporary table that stores the date range and the current UTC offset.
Here is the partial solution that works for US starting at year 2007, for regions that observe DST.
It can be easily modified to for years before 2007.
Please see the end of the solution for a sample usage
-- GET UTC for time in US for region that observe Daylight Saving Time (meaning will not work for part of Arizona and Hawaii)
DECLARE
#DSTStartDay datetime = '2007-03-1 02:00:00',
#DSTEndDay datetime = '2007-11-1 02:00:00',
#i int = 0,
#currDate datetime,
#offset int
DECLARE
#DST TABLE (StartDate datetime, EndDate datetime, DSTOffset int)
-- Insert into #DST DSTOffset of 0 if not DST date range, and -1 if DST date as temporary offset value
-- Then when we get Time Zone Offset, we can update DSTOffset to actual current offset (hours)
WHILE #i < 20
BEGIN
INSERT #DST
SELECT DATEADD(d,
15 - CASE DATEPART(dw, #DSTStartDay)
WHEN 1 THEN 8
ELSE DATEPART(dw, #DSTStartDay)
END,
#DSTStartDay),
DATEADD(d,
8 - CASE DATEPART(dw, #DSTEndDay)
WHEN 1 THEN 8
ELSE DATEPART(dw, #DSTEndDay)
END,
#DSTEndDay),
-1;
SET #DSTStartDay = DATEADD(yy,1,#DSTStartDay)
INSERT #DST
SELECT DATEADD(d,
8 - CASE DATEPART(dw, #DSTEndDay)
WHEN 1 THEN 8
ELSE DATEPART(dw, #DSTEndDay)
END,
#DSTEndDay),
DATEADD(d,
15 - CASE DATEPART(dw, #DSTStartDay)
WHEN 1 THEN 8
ELSE DATEPART(dw, #DSTStartDay)
END,
#DSTStartDay),
0;
SET #DSTEndDay = DATEADD(yy,1,#DSTEndDay)
SET #i = #i + 1
END
-- Get temporary offset for current date
SET #currDate = GETDATE()
SELECT #Offset = DSTOffset FROM #DST
WHERE StartDate < #currDate AND EndDate >= #currDate
-- Calculate Time Zone Offset (ignore DST) and update DSTOffset in #DST table from temporary to actual offset
SET #Offset = DATEDIFF(hh, GETDATE(), GETUTCDATE()) - #Offset
UPDATE #DST
SET DSTOffset = DSTOffset + #Offset
--SELECT * FROM #DST - look at the table
--Sample usage
DECLARE #myDateNoDST datetime = '2014-03-08 06:00',
#myDateWithDST datetime = '2014-03-09 06:00'
SELECT #myDateNoDST LocalDateNoDST,
(SELECT DATEADD(hh,DSTOffset,#myDateNoDST) FROM #DST d WHERE StartDate < #myDateNoDST AND EndDate >= #myDateNoDST) UTCDateNoDST,
#myDateWithDST LocalDateWithDST,
(SELECT DATEADD(hh,DSTOffset,#myDateWithDST) FROM #DST d WHERE StartDate < #myDateWithDST AND EndDate >= #myDateWithDST) UTCDateWithDST

Related

Find out the quarter based on the financial year in SQL Server stored procedure

I have two tables, one is Period and the other is UserTarget.
Period table is:
QuarterNo StartDate EndDate
-----------------------------------------
1 2018-04-01 2018-06-30
2 2018-07-01 2018-09-30
3 2018-10-01 2018-12-31
4 2019-01-01 2019-03-31
UserTarget table is :
USERID YEAR QTR AMOUNT
---------------------------------
akshay 2019 1 200
Right now I am taking the qtr no from period table. Now I don't need take qtr no from period table. I want it from stored procedure based on year is entered in usertarget table
Existing stored procedure :
ALTER PROCEDURE [dbo].[GetQuarterlyTargetData]
#Userid VARCHAR(50)
AS
BEGIN
DECLARE #QuarterNumber VARCHAR(50)
DECLARE #SetTarget DECIMAL(10);
DECLARE #StartDate DATE
DECLARE #EndDate DATE
SELECT
#QuarterNumber = p.QuarterNo,
#SetTarget = AMOUNT
FROM
PERIOD p
LEFT OUTER JOIN
USERTARGETS s ON p.QuarterNo = s.QTR
WHERE
StartDate <= GETDATE() AND EndDate >= GETDATE()
SELECT
#StartDate = StartDate,
#EndDate = EndDate
FROM
PERIOD
WHERE
QuarterNo = #QuarterNumber
From this procedure I am getting the start date and end date for quarter but I don't want to modify in period table every time when I want to check previous years data.
I believe that the term you are looking for is fiscal year. It's where the company year is different than the calendar year.
Note that many people recommend using a lookup table instead of calculating it. Date matches can be difficult for SQL to optimize.
Here's one way to do it. Finding the fiscal year and quarter would probably be good to put in a table function.
DECLARE #userTarget TABLE (UserId VARCHAR(20), Year INT, Quarter INT, Amount INT)
INSERT INTO #userTarget
VALUES
('akshay', 2018, 4, 150)
,('akshay', 2019, 1, 200)
SELECT
s.UserId
,s.Amount
,FY.FiscalYear
,FQ.FiscalQuarter
FROM
(
SELECT
--DATEFROMPARTS(2019, 2, 23)
GETDATE()
AS reportDate
) AS ReportDate
CROSS APPLY (
SELECT
CASE WHEN MONTH(ReportDate.reportDate) < 4 THEN YEAR(ReportDate.reportDate) - 1 -- Fiscal Year begins in April
ELSE YEAR(ReportDate.reportDate)
END AS FiscalYear
) AS FY
CROSS APPLY (
SELECT
DATEDIFF(QUARTER, DATEFROMPARTS(FY.FiscalYear, 4, 1), ReportDate.reportDate) + 1 AS FiscalQuarter
) AS FQ
INNER JOIN #userTarget s
ON s.Year = FY.FiscalYear
AND s.Quarter = FQ.FiscalQuarter
Also, be careful with end dates. last_day >= GETDATE() does not include the last day. Take as an example the end of last quarter, it would calculate it as '2019-03-31 00:00' >= '2019-03-31 08:20' which is false when you want it to be true.
After thinking I come up to this solutions
ALTER PROCEDURE [dbo].[Dashboard_GetQuarterlyTargetData]
#Userid varchar(50)
AS
Begin
DECLARE #QuarterNumber varchar(50)
DECLARE #SetTarget decimal(10);
DECLARE #AchievedTarget decimal(10);
DECLARE #TargetProgress decimal(10);
DECLARE #RemainingTarget decimal(10);
DECLARE #StartDate Date
DECLARE #EndDate Date
DECLARE #Year as int
Select #QuarterNumber = QTR,#Year=YEAR,#SetTarget=AMOUNT from USERTARGETS where USERID=#Userid
if(#QuarterNumber = 1)
begin
SELECT #StartDate = DATEFROMPARTS(#year,4,1), #EndDate=DATEFROMPARTS(#year,6,30)
End
else if(#QuarterNumber = 2)
begin
SELECT #StartDate = DATEFROMPARTS(#year,7,1), #EndDate=DATEFROMPARTS(#year,9,30)
End
else if(#QuarterNumber = 3)
begin
SELECT #StartDate = DATEFROMPARTS(#year,10,1), #EndDate=DATEFROMPARTS(#year,12,31)
End
else if(#QuarterNumber = 4)
begin
SELECT #StartDate = DATEFROMPARTS(#year,1,1), #EndDate=DATEFROMPARTS(#year,3,31)
End

SQL Sever - Datediff, hours, but exclude Saturday/ Sundays

I'm wondering how to calculate the "number of hours" between two timestamps (2016-02-24 17:30:00 and another, for instance) in SQL server- but excluding Saturday and Sunday's full 48 hour period, if crossed.
This isn't quite the same as pure business hours, but sort of. The reason for this is long-winded and unnecessary.
EDIT: I can also say that the end-date will always be during the week. So really ... the "start date" can simply be transmuted to Monday midnight, if on Sat/ Sun ... then maybe a function include the total week count...
DATEDIFF(Week, date, date2) will return the number of week boundaries that are crossed between the two dates. For SQL Server, this means how many Sundays are between the dates (as opposed to the number of 7 day periods are between them). This means, that if you can indeed assume that start and end date will not be a saturday or sunday, you can subtract 48 X DATEDIFF(Week, date, date2) from your normal DATEDIFF call and that should give you what are after.
I would use the below code
declare #NumberOfHours int
declare #StartTime datetime
declare #EndTime datetime
set #StartTime = '2017-02-02 17:30:00.000'
set #EndTime = '2017-02-07 00:00:00.000'
set #NumberOfHours = DATEDIFF(HOUR,#StartTime,#EndTime)
if(datepart(WEEKDAY, #StartTime)=1)
begin
set #NumberOfHours = #NumberOfHours DATEDIFF(HH,#StartTime,#EndTime)%24
end
else if(datepart(WEEKDAY, #StartTime)=7)
begin
set #NumberOfHours = #NumberOfHours - DATEDIFF(HH,#StartTime,#EndTime)%24
set #NumberOfHours = #NumberOfHours - 24
end
else
begin
set #NumberOfHours = #NumberOfHours - datediff(ww,#StartTime,#EndTime)*48
end
print #NumberOfHours
I would use a calendar table (ex. dbo.DateDimension, ref https://www.mssqltips.com/sqlservertip/4054/creating-a-date-dimension-or-calendar-table-in-sql-server/):
CREATE TABLE dbo.DateDimension
(
DateKey INT NOT NULL PRIMARY KEY,
[Date] DATE NOT NULL,
[Day] TINYINT NOT NULL,
DaySuffix CHAR(2) NOT NULL,
[Weekday] TINYINT NOT NULL,
WeekDayName VARCHAR(10) NOT NULL,
IsWeekend BIT NOT NULL,
IsHoliday BIT NOT NULL,
...
)
and, also, following query:
SELECT SUM(
CASE
WHEN dd.[Date] = CONVERT(DATE, #StartDate) THEN DATEDIFF(MINUTE, #StarDate, DATEADD(DAY, 1, dd.[Date]))
WHEN dd.[Date] = CONVERT(DATE, #EndDate) THEN DATEDIFF(MINUTE, dd.[Date], #EndDate)
ELSE 24 * 60 -- Full day
END) / 60 AS SumOfHours
FROM dbo.DateDimension dd
WHERE dd.[Date] >= CONVERT(DATE, #StartDate) AND dd.[Date] <= CONVERT(DATE, #EndDate)
AND dd.IsWeekend = 0
Above query will compute total amount of minutes for requested period of time and then it will divide by 60 to get number of hours.

How to check if a month and year lies between 2 dates

I have a 2 columns in a table startdate and enddate and I need to create a function get all ID which lies between the date data passed in function.
my function input parameters are
#Year int,
#Month int = null,
#Quarter int = null
now if month is null I need to check only with date which is easy but if month is provided how to check if it lies between startdate and enddate or else if #Quarter is provided I need to check if 3 months of the year collides with startdate and enddate .
What I have written upto now is
CREATE FUNCTION GetAssociatesEmpID(
#Year int,
#Month int = null,
#Quarter int = null
)
RETURNS TABLE
AS BEGIN
IF #Month IS NOT NULL -- Monthly Statistics
BEGIN
END
ELSE IF #Quarter IS NOT NULL -- Quarterly Statistics
BEGIN
END
ELSE -- Yearly Statistics
BEGIN
return SELECT ID FROM Table WHRER #Year>=YEAR(startdate) AND #Year<=YEAR(enddate)
END
END
Kindly help me with condition with month and Quarter
Quarter has 4 possible inuts range between 1-4
and its month range is between #Quarter*3-3 and #Quarter*3
Start by creating two local DateTime variables. (Or DateTime2, or whatever data type your table's start and end date columns are using.) Maybe call them #WhereStartDate and #WhereEndDate.
Use some IF statements to populate your new #WherexxxDate variables. For example, if Month is provided, something like:
DECLARE #Year int = 2016;
DECLARE #Month int = 3;
DECLARE #WhereStartDate datetime;
DECLARE #WhereEndDate datetime;
SET #WhereStartDate = CONVERT( datetime, CAST(#Year as char(4)) + '/' + CAST(#Month as varchar(2)) + '/01');
SET #WhereEndDate = DATEADD( day, -1, DATEADD( month, 1, #WhereStartDate ));
SELECT #WhereStartDate, #WhereEndDate;
Once you have actual date/time variables, you can write your query appropriately...
SELECT ...
...
WHERE startDate >= #WhereStartDate
AND enddate <= #WhereEndDate
This has the added benefit of being sargable. The way that you have written your query is non-sargable. (In short, non-sargable queries will not make use of indexes properly and will have poor performance. If the table is large, the resulting table scans could take a very long time.)
Not where I can test, but this should be close...
WHERE
(#Year >= YEAR(startdate))
AND
(#Year <= YEAR(startdate))
AND
(
( (#Month IS NOT NULL) AND (#Month >= MONTH(startdate)) AND (#Month <= MONTH(startdate)) )
OR
( (#Month IS NULL) AND (#Quarter >= DATEPART(QUARTER, startdate)) AND (#Quarter <= DATEPART(QUARTER, startdate)) )
)

Show 0 if null in query

I am running a sql query that is omitting the day if the return count is 0. I want my query to return the day and a 0 count if the the count is 0. Snare I have is that if 0 were sold for the day, the day is omitted from my return results.
SELECT ISNULL([day],0) As [day], COUNT(ISNULL(Sold,0)) As [Sold]
FROM productionInfo
You're drawing information from a single table, productionInfo. If productionInfo has no rows with that date information (because there are no widgets sold on that date), how does it know what dates to use?
You might want to look at using a Numbers Table to get a row for each day of the month/year, then join that to productionInfo so you have a day value available, even if there was no production that day.
This will give you a dates table:
CREATE FUNCTION dbo.DatesTable (#startDate DATETIME, #endDate DATETIME)
RETURNS #retTable TABLE (DateValue DATETIME)
AS
BEGIN
DECLARE #currentDate DATETIME
SET #currentDate = #startDate
WHILE (DATEDIFF(dd, #currentDate, #endDate) >= 0)
BEGIN
INSERT INTO #retTable VALUES (#currentDate)
SET #currentDate = DATEADD(dd, 1, #currentDate)
END
RETURN
END
Then your query will look like:
SELECT dt.DateValue AS [day], COUNT(Sold) AS [Sold]
FROM dbo.DatesTable('2-1-2014', '2-10-2014') dt
LEFT JOIN productionInfo pi ON pi.day = dt.DateValue
GROUP BY dt.DateValue

SQL Server Check if day does not fall on weekend and if so, iterate to a weekday

I am using SQL Server with t-Sql
I have the following code that checks to see if a date falls on a weekend
and if it does, it will iterate until the day falls on a weekday
Declare #ProDate as Date
set #ProDate = '08/05/12'
WHILE (DATEPART(DW, #ProDate) = 1 OR DATEPART(DW, #ProDate) = 7 )
BEGIN
set #ProDate = DATEADD(day, 1, #ProDate)
END
select #ProDate
The code seems to work. Wondering if I missed anything or if there is a better way to handle this.
This code is dependent on the setting of DATEFIRST in your system.
I'd add a SET DATEFIRST 7 before the date checks
Alternately, this avoids the while loop
declare #df int = ##Datefirst
set datefirst 1
select
case when DATEPART(DW, #ProDate)>=6 then
DATEADD(d, 8-DATEPART(DW, #ProDate), #prodate)
else #ProDate
end
set DATEFIRST #df
This code will work. It is almost identical to code that we use in a heavily used function.
The only suggestion that I might have is do you need to integrate a Holiday check? We have a Holiday table to store dates that need to be skipped as well.
Use below code to get next wrking date after excluding weekends and Holidays
Declare #AddDay as integer = 3
Declare #NextWorkingDate DateTime
Declare #StartDate DateTime = Cast(getdate() as date)
While #AddDay > 0
begin
Select #NextWorkingDate = #StartDate + #AddDay +
(datediff(wk, #StartDate, #StartDate+ #AddDay ) * 2) -- add weekend
--Exclude weekend
If datepart(dw,#NextWorkingDate ) = 1 or datepart(dw,#NextWorkingDate ) = 7 --Add 2 days if target date is either Saturday or Sunday
set #NextWorkingDate = #NextWorkingDate + 2
--Count no of holidays if falling within start date and nextwrking date
Select #AddDay = Count(*) from HolidayTable ST --Holiday list
where ST.OffDate between #StartDate+1 and #NextWorkingDate
Set #StartDate = #NextWorkingDate
End
Select #NextWorkingDate
USE below to exclude weekeends and Holiday
Declare #AddDay as integer = 3
Declare #NextWorkingDate DateTime
Declare #StartDate DateTime = Cast(getdate() as date)
While #AddDay > 0
begin
Select #NextWorkingDate = #StartDate + #AddDay +
(datediff(wk, #StartDate, #StartDate+ #AddDay ) * 2) -- add weekend
--Exclude weekend
If datepart(dw,#NextWorkingDate ) = 1 or datepart(dw,#NextWorkingDate ) = 7 --Add 2 days if target date is either Saturday or Sunday
set #NextWorkingDate = #NextWorkingDate + 2
--Count no of holidays if falling within Hold days/Deposit days
Select #AddDay = Count(*) from HolidayTable ST --Holiday list
where ST.OffDate between #StartDate+1 and #NextWorkingDate
Set #StartDate = #NextWorkingDate
End
Select #NextWorkingDate

Resources