I use a query to filter records from Friday midnight until Saturday midnight based on kuwait time zone.
First when I check my server timezone I can see:
select CURRENT_TIMEZONE();
(UTC+01:00) Brussels, Copenhagen, Madrid, Paris
So I assume that the date column I need to filter is based on this timezone since the records where created and stored on this server, right?
Then I have my query:
SELECT
ID,
DATETIME,
DATETIME AT TIME ZONE 'Arab Standard Time' AS kuwait_time
FROM
admin_all.ACCOUNT_TRAN_ALL
WHERE
DATETIME BETWEEN (DATEADD(wk, DATEDIFF(wk, 6, GETDATE()), 5) AT TIME ZONE 'Arab Standard Time')
AND (DATEADD(wk, DATEDIFF(wk, 6, GETDATE()), 6) AT TIME ZONE 'Arab Standard Time')
Which returns this output:
+---------+-------------------------+--------------------------------+
| ID | DATETIME | kuwait_time |
+---------+-------------------------+--------------------------------+
| 1050554 | 2019-12-27 21:05:28.073 | 2019-12-27 21:05:28.073 +03:00 |
| 1050555 | 2019-12-27 21:05:42.586 | 2019-12-27 21:05:42.587 +03:00 |
| 1050556 | 2019-12-27 21:06:58.920 | 2019-12-27 21:06:58.920 +03:00 |
| 1050557 | 2019-12-27 21:07:12.906 | 2019-12-27 21:07:12.907 +03:00 |
| 1050558 | 2019-12-27 21:16:56.436 | 2019-12-27 21:16:56.437 +03:00 |
| 1050559 | 2019-12-27 21:17:10.533 | 2019-12-27 21:17:10.533 +03:00 |
| 1050560 | 2019-12-27 21:17:37.913 | 2019-12-27 21:17:37.913 +03:00 |
| 1050561 | 2019-12-27 21:17:37.986 | 2019-12-27 21:17:37.987 +03:00 |
+---------+-------------------------+--------------------------------+
Now my issue. Since I want this to start from last Friday at midnight and finish on last Saturday at midnight and since my local DATETIME field is UTC+1, I should have my first record starting at 22:05 to get this starting at midnight Kuwait time Since Kuwait is 2 hours ahead of me (I am UTC+ 1 and Kuwait is UTC+3).
Why I am then filtering first records at 21:05?
UPDATE: following #Matt's kind support I came up with this query that takes some of his hints, but also include the last friday and Saturday search in the where parameter that was skipped in the answer.
Now query is very slow, there must be a way to speed it up. It gives a correct results:
SELECT id,
datetime at time zone 'Romance Standard Time' AS local_time,
datetime at time zone 'Romance Standard Time' at time zone 'Arab Standard Time' AS kuwait_date
FROM admin_all.account_tran_all
WHERE datetime at time zone 'Romance Standard Time' at time zone 'Arab Standard Time' >=
(
SELECT CONVERT(datetime,
CASE
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Sunday' THEN dateadd(day,-2,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Monday' THEN dateadd(day,-3,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Tuesday' THEN dateadd(day,-4,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Wednesday' THEN dateadd(day,-5,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Thursday' THEN dateadd(day,-6,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Friday' THEN dateadd(day,-7,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Saturday' THEN dateadd(day,-8,cast(CURRENT_TIMESTAMP AS date))
END ) at time zone 'Arab Standard Time')
AND datetime at time zone 'Romance Standard Time' at time zone 'Arab Standard Time' <
(
SELECT CONVERT(datetime,
CASE
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Sunday' THEN dateadd(day,-1,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Monday' THEN dateadd(day,-2,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Tuesday' THEN dateadd(day,-3,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Wednesday' THEN dateadd(day,-4,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Thursday' THEN dateadd(day,-5,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Friday' THEN dateadd(day,-6,cast(CURRENT_TIMESTAMP AS date))
WHEN datename(weekday,cast(CURRENT_TIMESTAMP AS date)) = 'Saturday' THEN dateadd(day,-7,cast(CURRENT_TIMESTAMP AS date))
END) at time zone 'Arab Standard Time' )
the result:
| ID | Original_DATETIME | Local_time | kuwait_date |
|-------------|-------------------------|--------------------------------|--------------------------------|
| 1046053 | 2019-12-26 22:00:01.836 | 2019-12-26 22:00:01.837 +01:00 | 2019-12-27 00:00:01.837 +03:00 |
| 1046054 | 2019-12-26 22:00:01.940 | 2019-12-26 22:00:01.940 +01:00 | 2019-12-27 00:00:01.940 +03:00 |
| 1046055 | 2019-12-26 22:00:17.040 | 2019-12-26 22:00:17.040 +01:00 | 2019-12-27 00:00:17.040 +03:00 |
| 1046056 | 2019-12-26 22:00:19.046 | 2019-12-26 22:00:19.047 +01:00 | 2019-12-27 00:00:19.047 +03:00 |
| 1046057 | 2019-12-26 22:00:19.156 | 2019-12-26 22:00:19.157 +01:00 | 2019-12-27 00:00:19.157 +03:00 |
| 1046058 | 2019-12-26 22:00:44.646 | 2019-12-26 22:00:44.647 +01:00 | 2019-12-27 00:00:44.647 +03:00 |
| 1046059 | 2019-12-26 22:00:44.713 | 2019-12-26 22:00:44.713 +01:00 | 2019-12-27 00:00:44.713 +03:00 |
| 1046060 | 2019-12-26 22:00:47.483 | 2019-12-26 22:00:47.483 +01:00 | 2019-12-27 00:00:47.483 +03:00 |
So i assume that the Date field I need to filter is based on this timezone since the records where created and stored on this server, right?
Sorry, but no - that is not right. There is no implicit binding between the fields stored in your database and the server's time zone. The server's time zone is used by the GETDATE() function to determine the local time, but it is subsequently discarded.
For DATETIME and DATETIME2 fields, you must design your database such that you know what the time zone reference is. For example, often UTC is the reference. If Paris time is your reference, then you'd have to know that when you do your conversions.
Here's how AT TIME ZONE works:
With DATETIME and DATETIME2 types, the AT TIME ZONE statement simply asserts the intended time zone. The result is a DATETIMEOFFSET type with the same local date and time as the original value, but with the correct offset for that time zone applied.
With DATETIMEOFFSET types, the AT TIME ZONE statement converts from the value given to the intended time zone. A DATETIMEOFFSET with the same point in Universal Time is returned, but the date, time, and offset will change to reflect the new time zone.
Thus, if you are starting with a DATETIME or DATETIME2 field, you will need two AT TIME ZONE statements to convert from one time zone to another.
SELECT
DATETIME AT TIME ZONE 'Romance Standard Time' as paris_time,
DATETIME AT TIME ZONE 'Romance Standard Time' AT TIME ZONE 'Arab Standard Time' AS kuwait_time
...
The simpler solution is to use DATETIMEOFFSET fields to begin with. Then you won't have to have any implicit knowledge about the time zone reference.
I also suggest declaring local variables for your start/end points. That will make your code much more readable.
DECLARE #NowInKuwait DATETIMEOFFSET = SYSDATETIMEOFFSET() AT TIME ZONE 'Arab Standard Time';
DECLARE #Start DATETIMEOFFSET = DATEADD(wk, 5, #NowInKuwait) AT TIME ZONE 'Arab Standard Time';
DECLARE #End DATETIMEOFFSET = DATEADD(wk, 6, #NowInKuwait) AT TIME ZONE 'Arab Standard Time';
SELECT ...
FROM ...
WHERE DATETIME >= #Start AND DATETIME < #End
I'm guessing a bit on your desired start and end times, as the DATEADD and DATEDIFF statements in your question do not have the correct parameters.
Also note that I call AT TIME ZONE one more time in the declarations for #Start and #End. That is in case the offset has changed between "now" and the resulting date. If you're only using this for Kuwait, then you can omit that since Kuwait is fixed to UTC+3. However many time zones use daylight saving time, or have had changes to their standard time offset, and thus one can't always assume the offsets are consistent.
Related
I need some help regarding sum of production count for overnight shifts.
The table just contains a timestamp (that is automaticaly generated by SQL server during INSERT), the number of OK produced pieces and the number of NOT OK produced pieces in that given timestamp.
CREATE TABLE [machine1](
[timestamp] [datetime] NOT NULL,
[OK] [int] NOT NULL,
[NOK] [int] NOT NULL
)
ALTER TABLE [machine1] ADD DEFAULT (getdate()) FOR [timestamp]
The table holds values like these (just an example, there are hundreds of lines each day and the time stamps are not fixed like each hour or each 30mins):
timestamp
OK
NOK
2022-08-01 05:30:00.000
15
1
2022-08-01 06:30:00.000
18
3
...
...
...
2022-08-01 21:30:00.000
10
12
2022-08-01 22:30:00.000
0
3
...
...
...
2022-08-01 23:59:00.000
1
2
2022-08-02 00:01:00.000
7
0
...
...
...
2022-08-02 05:30:00.000
12
4
2022-08-02 06:30:00.000
9
3
The production works in shifts like so:
morning shift: 6:00 -> 14:00
afternoon shift: 14:00 -> 22:00
night shift: 22:00 -> 6:00 the next day
I have managed to get sums for the morning and afternoon shifts without issues but I can't figure out how to do the sum for the night shift (I have these SELECTs for each shift stored as a VIEW for easy access).
For the morning shift:
SELECT CAST(timestamp AS date) AS Morning,
SUM(OK) AS SUM_OK,
SUM(NOK) AS SUM_NOK
FROM [machine1]
WHERE DATEPART(hh,timestamp) >= 6 AND DATEPART(hh,timestamp) < 14
GROUP BY CAST(timestamp AS date)
ORDER BY Morning ASC
For the afternoon shift:
SELECT CAST(timestamp AS date) AS Afternoon,
SUM(OK) AS SUM_OK,
SUM(NOK) AS SUM_NOK
FROM [machine1]
WHERE DATEPART(hh,timestamp) >= 14 AND DATEPART(hh,timestamp) < 22
GROUP BY CAST(timestamp AS date)
ORDER BY Afternoon ASC
Since we identify the date of each shift by its start, my idea would be that the result for such SUM of night shift would be
Night
SUM_OK
SUM_NOK
2022-08-01
xxx
xxx
for interval 2022-08-01 22:00:00.000 -> 2022-08-02 05:59:59.999
2022-08-02
xxx
xxx
for interval 2022-08-02 22:00:00.000 -> 2022-08-03 05:59:59.999
2022-08-03
xxx
xxx
for interval 2022-08-03 22:00:00.000 -> 2022-08-04 05:59:59.999
2022-08-04
xxx
xxx
for interval 2022-08-04 22:00:00.000 -> 2022-08-05 05:59:59.999
...
...
...
After few days of trial and error I have probably managed to find the needed solution. Using a subquery I shift all the times in range 00:00:00 -> 05:59:59 to the previous day and then I use that result in same approach as for morning and afternon shift (because now all the production data from night shift are in the same date between 22:00:00 and 23:59:59).
In case anyone needs it in future:
SELECT
CAST(nightShift.shiftedTime AS date) AS Night,
SUM(nightShift.OK) AS SUM_OK,
SUM(nightShift.NOK) AS SUM_NOK
FROM
(SELECT
CASE WHEN (DATEPART(hh, timestamp) < 6 AND DATEPART(hh, timestamp) >= 4) THEN DATEADD(HOUR, -6, timestamp)
WHEN (DATEPART(hh, timestamp) < 4 AND DATEPART(hh, timestamp) >= 2) THEN DATEADD(HOUR, -4, timestamp)
WHEN (DATEPART(hh, timestamp) < 2 AND DATEPART(hh, timestamp) >= 0) THEN DATEADD(HOUR, -2, timestamp)
END AS shiftedTime,
[OK],
[NOK]
FROM [machine1]
WHERE (DATEPART(hh, cas) >= 0 AND DATEPART(hh, cas) < 6)) nightShift
WHERE DATEPART(hh,nightShift.shiftedTime) >= 22
GROUP BY CAST(nightShift.shiftedTime AS date)
ORDER BY Night ASC
PS: If there is anything wrong with this approach, please feel free to correct me as I'm just newbie in SQL. So far this seems to do exactly what I needed.
I am trying to add 1 day to a timezone aware timestamp.
In this example I expected + interval '1' day to add 23 hours because DST starts on 2021-03-28 02:00:00 in Europe/Berlin, but it behaves the same as + interval '24' hour:
select timestamp '2021-03-28 00:00:00 Europe/Berlin' as before_dst,
timestamp '2021-03-28 00:00:00 Europe/Berlin' + interval '1' day as plus_1_day,
timestamp '2021-03-28 00:00:00 Europe/Berlin' + interval '24' hour as plus_24_hour
from dual;
BEFORE_DST
PLUS_1_DAY
PLUS_24_HOUR
2021-03-28 00:00:00.000000000 +01:00
2021-03-29 01:00:00.000000000 +02:00
2021-03-29 01:00:00.000000000 +02:00
Is there a way to add a day to a timestamp so that the beginnings or ends of daylight saving times are respected? For the example above that means a way to have oracle automatically recognize that the day 2021-03-28 only has 23 hours in Europe/Berlin.
I attempted to solve this by converting the timestamp to a local timestamp using at local before adding a day, but that does not work because at local converts the timestamp to the local time zone and not to something like a LocalDateTime in java, resulting in the exact same outcome: + interval '1' day always adding exactly 24 hours.
You could cast the timestamp with time zone value to a plain timestamp, which discards the time zone information; then add the 1-day interval, and declare the result to be in the required time zone:
from_tz(cast(timestamp '2021-03-28 00:00:00 Europe/Berlin' as timestamp) + interval '1' day, 'Europe/Berlin') as plus_1_day
or cast to a date (which could be implicit), add a day, and cast back:
from_tz(cast(cast(timestamp '2021-03-28 00:00:00 Europe/Berlin' as date) + 1 as timestamp), 'Europe/Berlin')
Adapting your example and showing the intermediate values:
select timestamp '2021-03-28 00:00:00 Europe/Berlin' as before_dst,
cast(timestamp '2021-03-28 00:00:00 Europe/Berlin' as timestamp) as as_ts,
cast(timestamp '2021-03-28 00:00:00 Europe/Berlin' as timestamp) + 1 as plus_1_day_ts,
from_tz(cast(timestamp '2021-03-28 00:00:00 Europe/Berlin' as timestamp) + interval '1' day, 'Europe/Berlin') as plus_1_day
from dual;
BEFORE_DST
AS_TS
PLUS_1_DAY_TS
PLUS_1_DAY
2021-03-28 00:00:00 +01:00
2021-03-28 00:00:00
2021-03-29 00:00:00
2021-03-29 00:00:00 +02:00
db<>fiddle
This assumes that you're always dealing with a fixed known time zone region; if you actually have a variable or column value with an unknown time zone then you can extract the region from that and use that as the from_tz() argument.
You should also be aware that this will work for your example at midnight, but won't work for all times. For example if your starting value was timestamp '2021-03-27 02:30:00 Europe/Berlin' then it would fail with "ORA-01878: specified field not found in datetime or interval", because it would end up try to declare 2021-03-28 02:30:00 to be in zone Europe/Berlin - and there is no such time, as that falls into the 'lost' hour of 02:00-03:00. Simply adding a day interval handles that - but then doesn't work as you expect in your example...
And this is because of this line in the documentation:
Oracle performs all timestamp arithmetic in UTC time.
2021-03-28 00:00:00 Europe/Berlin is 2021-03-27 23:00:00 UTC; adding a day to that is 2021-03-28 23:00:00 UTC; which is 2021-03-29 02:00:00 Europe/Berlin
I want to take the value that falls between the current day (today) and yesterday but only when after 9 am yesterday and before 9 am today. The current day must be only on Tuesday - Friday. But, if the current day is Monday, it will take value from Friday after 9 am to Monday before 9 am.
Samples
+---------+------------------------------+
| ID | registration_started_at |
+---------+------------------------------+
| 1 | 2021-05-13 07:00:00.000 |
| 2 | 2021-05-13 11:00:00.000 |
| 3 | 2021-05-14 08:00:00.000 |
| 4 | 2021-05-14 10:00:00.000 |
| 5 | 2021-05-15 12:00:00.000 |
| 6 | 2021-05-16 13:00:00.000 |
| 7 | 2021-05-17 08:00:00.000 |
| 8 | 2021-05-17 10:00:00.000 |
+---------+------------------------------+
So let say when the current_day (today) is Friday (14 May 2021),
When I run the query it must return
Desired Result 1
+---------+------------------------------+
| ID | registration_started_at |
+---------+------------------------------+
| 2 | 2021-05-13 11:00:00.000 |
| 3 | 2021-05-14 08:00:00.000 |
+---------+------------------------------+
But when current_day (today) is Monday (17 May 2021) it should return
Desired Result 2
+---------+------------------------------+
| ID | registration_started_at |
+---------+------------------------------+
| 4 | 2021-05-14 10:00:00.000 |
| 5 | 2021-05-15 12:00:00.000 |
| 6 | 2021-05-16 13:00:00.000 |
| 7 | 2021-05-17 08:00:00.000 |
+---------+------------------------------+
I only manage to get the desired result 1 with this query and I think this still not correct tho for desired result 2
SELECT ID,
DATETIME(registration_started_at, 'Asia/Jakarta') as registration_started_at
FROM `table`
WHERE
DATETIME_DIFF(CURRENT_DATETIME('Asia/Jakarta'), DATETIME(registration_started_at, 'Asia/Jakarta'), week) = 0
AND DATE(DATETIME_ADD(DATETIME(registration_started_at, 'Asia/Jakarta'), INTERVAL -9 HOUR)) = CURRENT_DATE('Asia/Jakarta') - 1
---------edit 1
Using the Mr. Caius Jard answer
WHERE
(DATETIME(registration_started_at, 'Asia/Jakarta') BETWEEN (
(CASE
WHEN EXTRACT(
DAYOFWEEK
FROM CURRENT_DATE('Asia/Jakarta')
) = 2 -- if Monday
THEN DATETIME_ADD(
CURRENT_DATETIME('Asia/Jakarta'),
INTERVAL -63 HOUR
) -- then 63 hours back from midnight today
ELSE DATETIME_ADD(
CURRENT_DATETIME('Asia/Jakarta'),
INTERVAL -15 HOUR
)
END)
) -- else 15 hours back from midnight today
AND DATETIME_ADD(
CURRENT_DATETIME('Asia/Jakarta'),
INTERVAL 9 HOUR
)) -- 9am today
It returns the 63 hours before today's time for Monday or 15 hours before today's time if not Monday, which is incorrect because if I run the query on 15.00 it only returns value from 00.00 today
I think this captures the logic you want:
WHERE DATETIME(registration_started_at, 'Asia/Jakarta') < DATETIME_ADD(DATETIME(DATE(CURRENT_DATETIME('Asia/Jakarta'))), INTERVAL 9 HOUR) AND
(EXTRACT(DAYOFWEEK, DATE(CURRENT_DATETIME('Asia/Jakarta'))) = 2 AND
DATETIME(registration_started_at, 'Asia/Jakarta') > DATETIME_ADD(DATETIME_ADD(DATETIME(DATE(CURRENT_DATETIME('Asia/Jakarta'))), INTERVAL 9 HOUR), INTERVAL -3 DAY) OR
DATETIME(registration_started_at, 'Asia/Jakarta') > DATETIME_ADD(DATETIME_ADD(DATETIME(DATE(CURRENT_DATETIME('Asia/Jakarta'))), INTERVAL 9 HOUR), INTERVAL -1 DAY)
)
What are the important components of this?
This expressoin:
DATETIME_ADD(DATETIME(DATE(CURRENT_DATETIME('Asia/Jakarta'))), INTERVAL 9 HOUR)
Returns 9:00 on the current date in Jakarata. No matter what, you want registration_started_at before that date/time.
This expression
EXTRACT(DAYOFWEEK, DATE(CURRENT_DATETIME('Asia/Jakarta')))
Returns the current day of the week, with 2 for Monday.
These expressions:
DATETIME_ADD(DATETIME_ADD(DATETIME(DATE(CURRENT_DATETIME('Asia/Jakarta'))), INTERVAL 9 HOUR), INTERVAL -3 DAY)
DATETIME_ADD(DATETIME_ADD(DATETIME(DATE(CURRENT_DATETIME('Asia/Jakarta'))), INTERVAL 9 HOUR), INTERVAL -1 DAY)
Just subtract 1 or 3 days from the current 9:00 datetime.
Perhaps something like:
WHERE
registration_started_at
BETWEEN
CASE WHEN EXTRACT(DAYOFWEEK FROM CURRENT_DATE()) = 2 -- if Monday
THEN DATETIME_ADD(CURRENT_DATE(), INTERVAL -63 HOUR)) -- then 63 hours back from midnight today
ELSE DATETIME_ADD(CURRENT_DATE(), INTERVAL -15 HOUR)) END -- else 15 hours back from midnight today
AND
DATETIME_ADD(CURRENT_DATE(), INTERVAL 9 HOUR)) -- 9am today
Never used bigquery, so it might need some fiddling, but the basic idea is that we ask via case when what the current day is and use it to change how much we go back in time
Using Mr. Caius Jard idea, I am able to make it works. I just need to cast CURRENT_DATE to DATETIME() to take the today's 00:00
WHERE
(DATETIME(registration_started_at, 'Asia/Jakarta') BETWEEN (
(CASE
WHEN EXTRACT(
DAYOFWEEK
FROM CURRENT_DATE('Asia/Jakarta')
) = 2 -- if Monday
THEN DATETIME_ADD(
DATETIME(CURRENT_DATE('Asia/Jakarta')),
INTERVAL -63 HOUR
) -- then 63 hours back from midnight today
ELSE DATETIME_ADD(
DATETIME(CURRENT_DATE('Asia/Jakarta')),
INTERVAL -15 HOUR
)
END)
) -- else 15 hours back from midnight today
AND DATETIME_ADD(
DATETIME(CURRENT_DATE('Asia/Jakarta')),
INTERVAL 9 HOUR
)) -- 9am today
I have my timezone in Pacific time.I want to convert it to the local time based on the region .Below is the example
time region
2017-05-23 14:00:00 Central
2017-05-23 14:00:00 Eastern
2017-05-23 14:00:00 Mountain
What i am looking for
time region time_local
2017-05-23 14:00:00 Central 2017-05-23 16:00:00
2017-05-23 14:00:00 Eastern 2017-05-23 17:00:00
2017-05-23 14:05:00 Mountain 2017-05-23 15:05:00
You can join to the timezone system view to adjust the timestamps:
select
time,
region,
time - tz1.utc_offset + tz2.utc_offset
from Example ex
JOIN pg_timezone_names tz1
on tz1.name = 'US/Pacific'
JOIN pg_timezone_names tz2
on tz2.name = 'US/' || ex.region
Assuming your "time" column type is a correct "timestamp with time zone" (also called or "timestamptz" for short):
create table times (time timestamp with time zone not null, region text not null);
set timezone='US/Pacific';
insert into times (time, region) values
('2017-05-23 14:00:00','US/Central'),
('2017-05-23 14:00:00','US/Eastern'),
('2017-05-23 14:00:00','US/Mountain');
select *, time at time zone region as time_local from times;
time | region | time_local
------------------------+-------------+---------------------
2017-05-23 14:00:00-07 | US/Central | 2017-05-23 16:00:00
2017-05-23 14:00:00-07 | US/Eastern | 2017-05-23 17:00:00
2017-05-23 14:00:00-07 | US/Mountain | 2017-05-23 15:00:00
If your time columns is an ordinary timestamp instead then you need to think about changing it before you'll get insane. The timestamp type does not mean timestamp at all - it means what some clock somewhere will show, which means different thing depending on where you are and which date it is and in which country you check and your database client settings and current environment and after which changes to the clock will politicians do in the future. Do not go this path.
You may use such a conversion as below :
SET TIMEZONE TO 'US/Central';
SELECT now()::timestamp;
current_time
2018-07-25T14:01:50.608042Z
SET TIMEZONE TO 'US/Eastern';
SELECT now()::timestamp;
current_time
2018-07-25T15:01:50.608042Z
SET TIMEZONE TO 'US/Mountain';
SELECT now()::timestamp;
current_time
2018-07-25T13:01:50.608042Z
SQL Fiddle Demo 1
OR alternatively Use :
SET TIMEZONE TO 'US/Central';
SELECT concat(current_date,' ',localtime) as current_time;
current_time
2018-07-25 14:10:57.962193
SET TIMEZONE TO 'US/Eastern';
SELECT concat(current_date,' ',localtime) as current_time;
current_time
2018-07-25 15:10:57.962193
SET TIMEZONE TO 'US/Mountain';
SELECT concat(current_date,' ',localtime) as current_time;
current_time
2018-07-25 13:10:57.962193
SQL Fiddle Demo 2
I have a table as test
shiftend | out |
---------------------------------------------
15:00:00.0000000 | 2016-07-22 14:42:00 |
16:00:00.0000000 | 2016-07-22 16:06:00 |
Shiftend is having a datatype as time
out is having a datatype as smalldatetime
I am expecting the output as
shiftend | out | Output
-----------------------------------------------------------------------------
15:00:00.0000000 | 2016-07-22 14:42:00 | -00:18:00
16:00:00.0000000 | 2016-07-22 16:06:00 | 00:06:00
I am trying this query:
select shiftend,out,CAST((out-Shiftend) as time(0)) as Output from test
where
CAST(CONVERT(NVARCHAR(10), out, 101) AS SMALLDATETIME) = CAST(CONVERT(NVARCHAR(10),'2016-07-22', 101) AS SMALLDATETIME)
But i am getting the output as
shiftend | out | Output
-----------------------------------------------------------------------------
15:00:00.0000000 | 2016-07-22 14:42:00 | 23:42:00
16:00:00.0000000 | 2016-07-22 16:06:00 | 00:06:00
23:42:00 is incorrect. How to calcualte the time.
Try the following query:
select
case when (cast(out as time) < shiftend) then '-' else '' end +
convert(varchar(8),
dateadd(minute,
abs(
DATEDIFF(minute,
cast(out as time)
, shiftend)
)
,0)
,108) as Output
Explanation:
You're getting the difference between the two dates with DATEDIFF(minute, cast(out as time), shiftend).
You need just the time component to avoid going to the previous day, so you use cast(out as time). shiftend as you mentioned is already of datatype time
abs returns the absolute value, so -18 becomes 18.
Then generate a date by adding the above value as minutes to 00:00:00 using dateadd(minute, [above value], 0)
The final convert(varchar(8),____,108) is since you required the output as a time.
iif(cast(out as time) < shiftend,'-','') adds negative sign or not to the beginning of the word.
Unfortunately, you can't have negative values in the time datatype. It's turning -18 into 00:00 - 18 which is 23:42. You could:
Use datediff and save the difference as the number of seconds for example.
Save only the modular difference and have a separate column for deciding whether it's a positive or negative difference.
Write your own SQL function for computing this as a varchar as above