Need help in writing a Case statement to get the 'US Eastern Standard Time' from the sys.time_zone_info system view in SQL Server. There is an error in the Select statement and cannot figure out where. The CN.CreateDate is currently in UTC time and need to convert to EST taking into account Daylight Savings time.
select
CN.CreateDate
,case when (SELECT * FROM sys.time_zone_info TZI WHERE
TZI.name = 'US Eastern Standard Time'
AND ISNULL(TZI.is_currently_dst,0)=0)
THEN DATEADD(hour, -5,CN.CreateDate)
ELSE DATEADD(hour, -4,CN.CreateDate)
END AS CreateDateEST
from MC_CDCPContactNotes CN
This functionality is built into SQL Server with AT TIME ZONE, there's no need to re-invent the wheel here. Only thing to note is that you may need to convert to UTC then to your required zone first, e.g.
WITH MC_CDCPContactNotes AS
( SELECT t.CreateDate
FROM (VALUES (('20221225 00:00'), ('20220625 00:00')) AS t (CreateDate)
)
SELECT CN.CreateDate,
EasternTime = cn.CreateDate AT TIME ZONE 'UTC' AT TIME ZONE 'US Eastern Standard Time'
FROM MC_CDCPContactNotes CN;
Which gives:
CreateDate
EasternTime
2022-12-25
2022-12-24 19:00:00 -05:00
2022-06-25
2022-06-24 20:00:00 -04:00
Example on db<>fiddle
Just to fix your query:
select
CN.CreateDate
,case when (SELECT
count(*)
FROM sys.time_zone_info TZI
WHERE TZI.name = 'US Eastern Standard Time'
AND ISNULL(TZI.is_currently_dst,0)=0) = 1
THEN DATEADD(hour, -5,CN.CreateDate)
ELSE DATEADD(hour, -4,CN.CreateDate)
END AS CreateDateEST
from MC_CDCPContactNotes CN
But I would rewrite it like:
select
CN.CreateDate
,dateadd(hour,-5+ISNULL(TZI.is_currently_dst,0),CN.CreateDate) as CreateDateEst
from MC_CDCPContactNotes CN
join sys.time_zone_info TZI
on TZI.name = 'US Eastern Standard Time'
Related
I'm using PostgreSQL for this. I need to count the calls to the sales department during the week and for those that came in between business hours. Here's my query so far:
SELECT
SUM(CASE WHEN call_logs.to_phone_number IN ('15125551234') THEN 1 ELSE 0 END) as sales_all,
SUM(
CASE WHEN
call_logs.to_phone_number IN ('15125551234') AND call_logs.start_time >= '08/08/2022 7:30 AM' AND call_logs.start_time <= '08/08/2022 5:30 PM'
OR
call_logs.to_phone_number IN ('15125551234') AND call_logs.start_time >= '08/09/2022 7:30 AM' AND call_logs.start_time <= '08/09/2022 5:30 PM'
OR
call_logs.to_phone_number IN ('15125551234') AND call_logs.start_time >= '08/10/2022 7:30 AM' AND call_logs.start_time <= '08/10/2022 5:30 PM'
OR
call_logs.to_phone_number IN ('15125551234') AND call_logs.start_time >= '08/11/2022 7:30 AM' AND call_logs.start_time <= '08/11/2022 5:30 PM'
OR
call_logs.to_phone_number IN ('15125551234') AND call_logs.start_time >= '08/12/2022 7:30 AM' AND call_logs.start_time <= '08/12/2022 5:30 PM'
THEN 1 ELSE 0 END) as sales_between_business_hours,
FROM call_logs
WHERE call_logs.start_time >= '08-08-2022 12:00 AM' AND call_logs.start_time <= '08-14-2022 11:59 PM';
This works, but the the second case statement to get sales_between_business_hours seems a bit excessive. Anybody see a more elegant way to do this?
Equivalent, less verbose, unambiguous, and faster, too:
SELECT count(*) AS sales_all
, count(*) FILTER (WHERE start_time BETWEEN '2022-08-08 07:30' AND '2022-08-12 17:30'
AND start_time::time BETWEEN '07:30' AND '17:30'
) AS sales_between_business_hours
FROM call_logs
WHERE to_phone_number = '15125551234'
AND start_time >= '2022-08-08' -- always use unambiguous ISO format!
AND start_time <= '2022-08-14 11:59';
Or, shorter yet (but not faster):
...
, count(*) FILTER (WHERE start_time BETWEEN '2022-08-08' AND '2022-08-13'
AND start_time::time BETWEEN '07:30' AND '17:30'
) AS sales_between_business_hours
...
Or, while there are only a hand full of ranges, making use of the new multirange types and operators in Postgres 14 or later:
...
, count(*) FILTER (WHERE start_time <#
tsmultirange '{[2022-08-08 07:30, 2022-08-08 17:30]
, [2022-08-09 07:30, 2022-08-09 17:30]
, [2022-08-10 07:30, 2022-08-10 17:30]
, [2022-08-11 07:30, 2022-08-11 17:30]
, [2022-08-12 07:30, 2022-08-12 17:30]}'
) AS sales_between_business_hours
...
Yes, this is a valid timestamp literal: '2022-08-08' - same as '2022-08-08 00:00:00'. And it's best to always use unambiguous ISO 8601 format. See:
Selecting records between two timestamps
PostgreSQL: between with datetime
About aggregate FILTER:
Aggregate columns with additional (distinct) filters
BETWEEN always includes lower and upper bound, just like your original formulation does. If your timestamp values are not all truncated to minutes, you might reconsider, though, as either formulation includes the start of the full minute for the upper bound, but excludes the rest of it.
Related:
Perform this hours of operation query in PostgreSQL
I have timestamp column and for the start time if my time is greater than 5:30Pm I would like to consider the time as 5:00PM and I need to subtract the converted minutes from start date and enddate.
SELECT [starttime], [endtime],
case when FORMAT([starttime],'HH:mm') >'17:30' then 17.00
end as newstarttime,
FORMAT([endtime],'HH:mm') as newendtime
FROM Table1
I tried to convert the timestamp into 24hour format but not sure about the next steps.
Starttime Endtime
2019-08-13 17:40:33:000 2019-08-13 19:00:00:000
I am assuming that you are using SQL Server, and I think you want:
select t1.*,
(case when convert(time, starttime) >= '17:30:00'
then dateadd(hour, 17, convert(datetime, convert(date, starttime)))
else starttime
end) as new_starttime
from table1 t1;
You can also express the date add logic as:
convert(datetime, convert(date, starttime)) + '17:00:00'
I have timestamp field and for the start time if my time is greater than 5:30Pm I would like to consider the time as 5:00PM
To do this, its easier to work with dates than doing character conversion. See the below query:
SELECT [starttime], [endtime]
, case
when FORMAT([starttime],'2020-01-01 HH:mm:00') > '2020-01-01 17:30:00' then '17:00'
else FORMAT([starttime],'HH:mm')
end as newsttime
, FORMAT([endtime],'HH:mm') as newendtime
FROM Table1;
What do you mean by:
I need to subtract the converted minutes from start date and enddate.
I created a query which calculates the average of several sums over multiple tables. This needs to be run every week and how the code is made currently I need to change 4 dates in the query every time. I'm thinking this can be done more efficiently but i'm unsure how.
Select ROUND(
(Select sum (calls)
FROM (SELECT sum(ski.ANSTIME) AS calls
FROM SYNONYMS syn
JOIN SKILL ski on (syn.value = ski.split)
WHERE syn.ITEM_TYPE = 'split'
AND (SELECT (timestamp '1970-01-01 00:00:00 GMT' +numtodsinterval(ski.starttime_utc, 'SECOND'))
at time zone 'Europe/Warsaw'
FROM dual) >= '17-07-17 00:00:00 EUROPE/WARSAW' -- Date to be altered every week
AND (SELECT (timestamp '1970-01-01 00:00:00 GMT' +numtodsinterval(ski.starttime_utc, 'SECOND'))
at time zone 'Europe/Warsaw'
FROM dual) <= '24-07-17 00:00:00 EUROPE/WARSAW' -- Date to be altered every week
UNION ALL
SELECT sum(vdn.ANSTIME) AS calls
FROM SYNONYMS syn
JOIN VDN vdn on (syn.value = vdn.vdn)
WHERE syn.ITEM_TYPE = 'vdn'
AND (SELECT (timestamp '1970-01-01 00:00:00 GMT' +numtodsinterval(vdn.starttime_utc, 'SECOND'))
at time zone 'Europe/Warsaw'
FROM dual) >= '17-07-17 00:00:00 EUROPE/WARSAW' -- Date to be altered every week
AND (SELECT (timestamp '1970-01-01 00:00:00 GMT' +numtodsinterval(vdn.starttime_utc, 'SECOND'))
at time zone 'Europe/Warsaw'
FROM dual) <= '24-07-17 00:00:00 EUROPE/WARSAW')) -- Date to be altered every week
/ -- devided by
(SELECT sum (calltime)
FROM (SELECT sum(ski.acdcalls) AS calltime
FROM SYNONYMS syn
JOIN SKILL ski on (syn.value = ski.split)
WHERE syn.ITEM_TYPE = 'split'
AND (SELECT (timestamp '1970-01-01 00:00:00 GMT' +numtodsinterval(ski.starttime_utc, 'SECOND'))
at time zone 'Europe/Warsaw'
FROM dual) >= '17-07-17 00:00:00 EUROPE/WARSAW' -- Date to be altered every week
AND (SELECT (timestamp '1970-01-01 00:00:00 GMT' +numtodsinterval(ski.starttime_utc, 'SECOND'))
at time zone 'Europe/Warsaw'
FROM dual) <= '24-07-17 00:00:00 EUROPE/WARSAW' -- Date to be altered every week
UNION ALL
SELECT sum(vdn.acdcalls) AS calltime
FROM SYNONYMS syn
JOIN VDN vdn on (syn.value = vdn.vdn)
WHERE syn.ITEM_TYPE = 'vdn'
AND (SELECT (timestamp '1970-01-01 00:00:00 GMT' +numtodsinterval(vdn.starttime_utc, 'SECOND'))
at time zone 'Europe/Warsaw'
FROM dual) >= '17-07-17 00:00:00 EUROPE/WARSAW' -- Date to be altered every week
AND (SELECT (timestamp '1970-01-01 00:00:00 GMT' +numtodsinterval(vdn.starttime_utc, 'SECOND'))
at time zone 'Europe/Warsaw'
FROM dual) <= '24-07-17 00:00:00 EUROPE/WARSAW')) -- Date to be altered every week
,0) AS average
FROM dual
If I understand correctly you're trying to generate some weekly summary so instead of entering date you can try to use trunc(sysdate) for second date and trunc(sysdate - 7) for first.
Second possibility is to create temporary table (or just with statement) which will hold single date and join that to your query. Instead <= '24-07-17 00:00:00 EUROPE/WARSAW' you will have <= temp_date where temp_date comes from CTE.
I have DB with timezone +04:00 (Europe/Moscow) and need to convert a string in format YYYY-MM-DD"T"HH24:MI:SSTZH:TZM to DATE data type in Oracle 11g.
In other words, I have a string 2013-11-08T10:11:31+02:00 and I want to convert it to DATE data type (in local DB timezone +04:00 (Europe/Moscow)).
For string 2013-11-08T10:11:31+02:00 my desired transformation should return DATE data type with date 2013-11-08 12:11:31 (i.e. with local timezone transformation of time to +04:00 (Europe/Moscow)). Timezone of string may be different and +02:00 in string above is just example.
I tried to do this with TIMESTAMP data type, but no success with time zone transformation.
to_timestamp_tz() function with at time zone clause can be used to convert your string literal to a value of timestamp with time zone data type:
SQL> with t1(tm) as(
2 select '2013-11-08T10:11:31+02:00' from dual
3 )
4 select to_timestamp_tz(tm, 'yyyy-mm-dd"T"hh24:mi:ss TZH:TZM')
5 at time zone '+4:00' as this_way
6 , to_timestamp_tz(tm, 'yyyy-mm-dd"T"hh24:mi:ss TZH:TZM')
7 at time zone 'Europe/Moscow' as or_this_way
8 from t1
9 /
Result:
THIS_WAY OR_THIS_WAY
----------------------------------------------------------------------------
2013-11-08 12.11.31 PM +04:00 2013-11-08 12.11.31 PM EUROPE/MOSCOW
And then, we use cast() function to produce a value of date data type:
with t1(tm) as(
select '2013-11-08T10:11:31+02:00' from dual
)
select cast(to_timestamp_tz(tm, 'yyyy-mm-dd"T"hh24:mi:ss TZH:TZM')
at time zone '+4:00' as date) as this_way
, cast(to_timestamp_tz(tm, 'yyyy-mm-dd"T"hh24:mi:ss TZH:TZM')
at time zone 'Europe/Moscow' as date) as or_this_way
from t1
This_Way Or_This_Way
------------------------------------------
2013-11-08 12:11:31 2013-11-08 12:11:31
Find out more about at time zone clause and to_timestamp_tz() function.
SELECT
CAST((FROM_TZ(CAST(timezonefield AS TIMESTAMP),'GMT') AT TIME ZONE 'CET') AS DATE)
FROM table;
Converts a timestamp in GMT to date in Central European time
if you want your timestamp with timezone to convert to a date in sync with "sysdate" then use the following:
select cast(to_timestamp_tz('2013-11-08T10:11:31-02:00'
,'yyyy-mm-dd"T"hh24:mi:sstzh:tzm'
)
at time zone to_char(systimestamp
,'tzh:tzm'
)
as date
)
from dual
to cast time stamp to date :
cast(registrationmaster.Stamp5DateTime as date) >= '05-05-2018' AND
cast(registrationmaster.Stamp5DateTime as date) <= '05-05-2018'
you can manage timezones with CAST(x AT TIME ZONE 'YYYY' AS DATE), this helps me:
WITH t1 (tm) AS (SELECT TIMESTAMP '2021-12-14 15:33:00 EET' FROM DUAL)
SELECT 'EET' tz, CAST (tm AT TIME ZONE 'Europe/Kaliningrad' AS DATE) AS datetime FROM t1
union SELECT 'MSK' tz, CAST (tm AT TIME ZONE 'Europe/Moscow' AS DATE) AS datetime FROM t1
union SELECT 'CET' tz, CAST (tm AT TIME ZONE 'Europe/Prague' AS DATE) AS datetime FROM t1
union SELECT 'UTC' tz, CAST (tm AT TIME ZONE 'UTC' AS DATE) AS datetime FROM t1
I need to write sql query to obtain records for a date range in IST format.
We are storing data in the database in GMT format.
select *
from tableA a
where to_date(a.end_date,'DD-MON-YYYY') between date1 and date2;
(end_date is one of the column in tableA table)
Now date1 and date2 should fetch the records from database in IST time zone.
How i can write sql query for the above requirement.
Just Try the following query
SELECT FROM_TZ (
CAST (SYSDATE AS TIMESTAMP)--replace sysdate with your date column
, 'GMT'
)
AT TIME ZONE 'Asia/Calcutta'
FROM DUAL;
In My case timezone is CET , and there is 3.5 hour difference from INDIA
select systimestamp from dual
7/30/2013 4:24:10.379910 PM +02:001
SELECT FROM_TZ (
CAST (SYSDATE AS TIMESTAMP)--replace sysdate with your date column
, 'GMT'
)
AT TIME ZONE 'Asia/Calcutta'
FROM DUAL;
7/30/2013 7:54:10.000000 PM +05:30