Rounding datetime to quarter minutes - sql-server-2008

I have a function to round a datetime to the nearest quarter hour.
But is there a method to round down to the nearest quarter instead?
Example.
08:14:00 becomes 08:00:00
08:03:00 becomes 08:00:00
08:29:00 becomes 08:15:00
08:55:00 becomes 08:45:00
This is what I have now to round to the nearest quarter.
(
#dt datetime
)
returns datetime
as
begin
declare #result datetime
declare #mm int
set #mm=datepart(minute,#dt)
set #result = dateadd(minute,-#mm + (round(#mm/cast(15 as float),0)*15) , #dt )
return #result

Using SQL Server:
select cast(
FLOOR( cast( GetDate() as float)*(24*4)) / (24*4)
as smalldatetime) AS "datetime_quarter"
The strategy is:
Convert the date to a float number, *24 to get number of hours, *4 to get number of quarters
Round down with FLOOR
Convert back to number of days by /(24*4)
Convert number of days to a datetime. smalldatetime is used to avoid float rounding issues.
This can easily be adjusted to use ROUNDor CEILING instead; or to use other hour multiples instead of 4 (quarters).

This is a procedure to get the current quarter upper and lower bound.
declare QUARTER_FLOOR datetime;
declare QUARTER_CEIL datetime;
declare CURRENT_DATETIME datetime;
declare CURRENT_MINUTE int;
// get current datetime without second and millisecond
SET CURRENT_DATETIME = dateformat(getdate(), 'YYYY-MM-DD hh:NN:00.000');
set CURRENT_MINUTE = datepart(minute,CURRENT_DATETIME); // get current minute
// GET CURRENT QUARTER FLOOR
set QUARTER_FLOOR = dateadd(minute, -CURRENT_MINUTE + (round(CURRENT_MINUTE/cast(15 as float),0)*15) , CURRENT_DATETIME );
// GET CURRENT QUARTER FLOOR
set QUARTER_CEIL = dateadd(minute, ((round(CURRENT_MINUTE/cast(15 as float),0)+1)*15) - CURRENT_MINUTE , CURRENT_DATETIME );
// RETURN
select QUARTER_FLOOR, QUARTER_CEIL;

This method relies on integer division when we divide the month by 4. In principle it should be portable, subject of course to modifying the syntax of dateadd() / date_add() and month()/year().
SELECT DATEADD(
MONTH,
3 * (
MONTH( my_date ) / 4
),
CONCAT(
YEAR( my_date ),
'0101' )
) AS my_date_rounded_to_quarter

Related

Timestampdiff excluding some hours and weekend mysql [duplicate]

I have a field of time Timestamp in my MySQL database which is mapped to a DATE datatype in my bean. Now I want a query by which I can fetch all records in the database for which the difference between the current timestamp and the one stored in the database is > 20 minutes.
How can I do it?
What i want is:
SELECT * FROM MyTab T WHERE T.runTime - now > 20 minutes
Are there any MySQL functions for this, or any way to do this in SQL?
If you have MySql version above 5.6 you could use TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) something like
select * from MyTab T where
TIMESTAMPDIFF(MINUTE,T.runTime,NOW()) > 20
MySql version >=5.6
I am using below code for today and database date.
TIMESTAMPDIFF(MINUTE,T.runTime,NOW()) > 20
According to the documentation, the first argument can be any of the following:
MICROSECOND
SECOND
MINUTE
HOUR
DAY
WEEK
MONTH
QUARTER
YEAR
ROUND(time_to_sec((TIMEDIFF(NOW(), "2015-06-10 20:15:00"))) / 60);
Try this one:
select * from MyTab T where date_add(T.runTime, INTERVAL 20 MINUTE) < NOW()
NOTE: this should work if you're using MySQL DateTime format. If you're using Unix Timestamp (integer), then it would be even easier:
select * from MyTab T where UNIX_TIMESTAMP() - T.runTime > 20*60
UNIX_TIMESTAMP() function returns you current unix timestamp.
You can try this:
SELECT * FROM MyTab T WHERE CURRENT_TIMESTAMP() > T.runTime + INTERVAL 20 MINUTE;
The CURRENT_TIMESTAMP() is a function and returns the current date and time. This function works From MySQL 4.0
If you have MySql version prior than 5.6 you don't have TIMESTAMPDIFF. So,I wrote my own MySql function to do this. Accets %i or %m for minutes and %h for hours. You can extend it.
Example of usage:
SELECT MYTSDIFF('2001-01-01 10:44:32', '2001-01-01 09:50:00', '%h')
Here goes the function. Enjoy:
DROP FUNCTION IF EXISTS MYTSDIFF;
DELIMITER $$
CREATE FUNCTION `MYTSDIFF`( date1 timestamp, date2 timestamp, fmt varchar(20))
returns varchar(20) DETERMINISTIC
BEGIN
declare secs smallint(2);
declare mins smallint(2);
declare hours int;
declare total real default 0;
declare str_total varchar(20);
if date1 > DATE_ADD( date2, interval 30 day) then
return '999999.999'; /* OUT OF RANGE TIMEDIFF */
end if;
select cast( time_format( timediff(date1, date2), '%s') as signed) into secs;
select cast( time_format( timediff(date1, date2), '%i') as signed) into mins;
select cast( time_format( timediff(date1, date2), '%H') as signed) into hours;
set total = hours * 3600 + mins * 60 + secs;
set fmt = LOWER( fmt);
if fmt = '%m' or fmt = '%i' then
set total = total / 60;
elseif fmt = '%h' then
set total = total / 3600;
else
/* Do nothing, %s is the default: */
set total = total + 0;
end if;
select cast( total as char(20)) into str_total;
return str_total;
END$$
DELIMITER ;

Select less and less records over time?

I'd like to write a query or stored procedure to retrieve less and less records over time from a relational database.
Think of this like populating the Google Finance stock chart: The past few days will have all ticks fit the day, and the further you go back, less and less ticks are displayed on each date. All ticks will show for today, 50% of ticks will show for one week ago, 30% for one month ago, and 10% for one year ago. Think of this like a gradient.
Is it possible to achieve this with one query? Or perhaps it would be necessary to use multiple queries? What might this look like?
Note that record ids are non-contiguous (there are gaps), but each record has a timestamp for determining order.
Also note that I am using MySQL.
Here is the structure of my table:
quotes
id
security_id
last_price
bid_price
ask_price
date
timestamp
trade_volume
cumulative_volume
average_volume
created_at
Sounds like you are looking for a constant set of records that represent the time-span. You can do so by defining a control date set.
Here's a sample query (doesn't account for weekends and holidays but that can be added):
POPULATE:
CREATE TABLE #quotes
(
id int identity(1,1)
,security_id VARCHAR(50)
,last_price FLOAT
,bid_price FLOAT
,ask_price FLOAT
,[date] DATETIME
,[timestamp] DATETIME
,trade_volume FLOAT
,cumulative_volume FLOAT
,average_volume FLOAT
,created_at DATETIME
)
DECLARE #i int
set #i = 100000
WHILE #i > 0
BEGIN
INSERT INTO #quotes (
security_id
,last_price
,bid_price
,ask_price
,[date]
,[timestamp]
,trade_volume
,cumulative_volume
,average_volume
,created_at
)
values( 'IBM US'
, 100.00 + RAND()
, 100.00 + RAND()
, 100.00 + RAND()
, DATEADD(MINUTE, -1* #i, GETDATE())
, DATEADD(MINUTE, -1* #i, GETDATE())
, 10000000.00 + RAND()*1000000.00
, 10000000.00 + RAND()*1000000.00
, 10000000.00 + RAND()*1000000.00
,getdate())
set #i= #i-1
END
You can change around the time span, but the following will give you around 1000 records that represent the set from start to finish.
DECLARE #StartDate DATETIME,
#EndDate DATETIME,
#j FLOAT,
#step FLOAT
set #StartDate = GETDATE()-20
SET #EndDAte = GETDATE()
set #j = 0.0
CREATE TABLE #TimeTable
(
IntervalDate DATETIME
)
--say you always want 1000 measures
--use the datediff value to define the step size:
select #step = DATEDIFF(MINUTE, #StartDate, #EndDate)/1000.0
WHILE #j < DATEDIFF(MINUTE, #StartDate, #EndDate)
BEGIN
INSERT #TimeTable (IntervalDate) VALUES (DATEADD(minute, #j, #StartDate))
SET #j = #j+#step
print #j
END
select security_id
,last_price
,bid_price
,ask_price
,[date]
,[timestamp]
,trade_volume
,cumulative_volume
,average_volume
,created_at
from #Quotes q
join #TimeTable t on dateadd(mi, datediff(mi, 0, q.date), 0) = dateadd(mi, datediff(mi, 0, t.IntervalDate), 0)

convert int to date to add a dayn and convert to int back

I have int value with YYYYMM. I want to:
1. convert it into datetime
2. add one day DATEADD(Day, +1, #date)
3. convert it back into int
What's the easiest way to do this?
Here is a nice exercise and I hope it works out for you...
declare #date date
declare #newDate date
set #date = convert(date, '20100101')
set #newdate = DateAdd(dd, 1, #Date)
select #date
select #newdate
select convert(int, convert(varchar, #newdate, 112)) -- this is your final conversion back to int
If your initial int is, say, 201310 (October 2013), then what I think you want is this:
select convert(datetime, rtrim(201310 * 100 + 1))
The function RTRIM is a trick to convert int to string type.
The result is this:
2013-10-01 00:00:00.000
If you don't want to use RTRIM, the command below will get you the same result:
select convert(datetime, convert(char, 201310 * 100 + 1))

SQL Server - calculate elapsed time between two datetime stamps in HH:MM:SS format

I have a SQL Server table that has a "Time" column. The table is a log table the houses status messages and timestamps for each message. The log table is inserted into via a batch file. There is an ID column that groups rows together. Each time the batch file runs it initializes the ID and writes records. What I need to do is get the elapsed time from the first record in an ID set to the last record of the same ID set. I started toying with select Max(Time) - Min(Time) from logTable where id = but couldn't figure out how to format it correctly. I need it in HH:MM:SS.
SQL Server doesn't support the SQL standard interval data type. Your best bet is to calculate the difference in seconds, and use a function to format the result. The native function CONVERT() might appear to work fine as long as your interval is less than 24 hours. But CONVERT() isn't a good solution for this.
create table test (
id integer not null,
ts datetime not null
);
insert into test values (1, '2012-01-01 08:00');
insert into test values (1, '2012-01-01 09:00');
insert into test values (1, '2012-01-01 08:30');
insert into test values (2, '2012-01-01 08:30');
insert into test values (2, '2012-01-01 10:30');
insert into test values (2, '2012-01-01 09:00');
insert into test values (3, '2012-01-01 09:00');
insert into test values (3, '2012-01-02 12:00');
Values were chosen in such a way that for
id = 1, elapsed time is 1 hour
id = 2, elapsed time is 2 hours, and
id = 3, elapsed time is 3 hours.
This SELECT statement includes one column that calculates seconds, and one that uses CONVERT() with subtraction.
select t.id,
min(ts) start_time,
max(ts) end_time,
datediff(second, min(ts),max(ts)) elapsed_sec,
convert(varchar, max(ts) - min(ts), 108) do_not_use
from test t
group by t.id;
ID START_TIME END_TIME ELAPSED_SEC DO_NOT_USE
1 January, 01 2012 08:00:00 January, 01 2012 09:00:00 3600 01:00:00
2 January, 01 2012 08:30:00 January, 01 2012 10:30:00 7200 02:00:00
3 January, 01 2012 09:00:00 January, 02 2012 12:00:00 97200 03:00:00
Note the misleading "03:00:00" for the 27-hour difference on id number 3.
Function to format elapsed time in SQL Server
UPDATED:
Correctly calculate a timespan in SQL Server, even if more than 24 hours:
-- Setup test data
declare #minDate datetime = '2012-12-12 20:16:47.160'
declare #maxDate datetime = '2012-12-13 15:10:12.050'
-- Get timespan in hh:mi:ss
select cast(
(cast(cast(#maxDate as float) - cast(#minDate as float) as int) * 24) /* hours over 24 */
+ datepart(hh, #maxDate - #minDate) /* hours */
as varchar(10))
+ ':' + right('0' + cast(datepart(mi, #maxDate - #minDate) as varchar(2)), 2) /* minutes */
+ ':' + right('0' + cast(datepart(ss, #maxDate - #minDate) as varchar(2)), 2) /* seconds */
-- Returns 18:53:24
Edge cases that show inaccuracy are especially welcome!
DECLARE #EndTime AS DATETIME, #StartTime AS DATETIME
SELECT #StartTime = '2013-03-08 08:00:00', #EndTime = '2013-03-08 08:30:00'
SELECT CAST(#EndTime - #StartTime AS TIME)
Result: 00:30:00.0000000
Format result as you see fit.
The best and simple way:
Convert(varchar, {EndTime} - {StartTime}, 108)
Just like Anri noted.
Use the DATEDIFF to return value in milliseconds, seconds, minutes, hours, ...
DATEDIFF(interval, date1, date2)
interval REQUIRED - The time/date part to return. Can be one of the following values:
year, yyyy, yy = Year
quarter, qq, q = Quarter
month, mm, m = month
dayofyear = Day of the year
day, dy, y = Day
week, ww, wk = Week
weekday, dw, w = Weekday
hour, hh = hour
minute, mi, n = Minute
second, ss, s = Second
millisecond, ms = Millisecond
date1, date2 REQUIRED - The two dates to calculate the difference between
select convert(varchar, Max(Time) - Min(Time) , 108) from logTable where id=...
See if this helps. I can set variables for Elapsed Days, Hours, Minutes, Seconds.
You can format this to your liking or include in a user defined function.
Note: Don't use DateDiff(hh,#Date1,#Date2). It is not reliable! It rounds in unpredictable ways
Given two dates...
(Sample Dates: two days, three hours, 10 minutes, 30 seconds difference)
declare #Date1 datetime = '2013-03-08 08:00:00'
declare #Date2 datetime = '2013-03-10 11:10:30'
declare #Days decimal
declare #Hours decimal
declare #Minutes decimal
declare #Seconds decimal
select #Days = DATEDIFF(ss,#Date1,#Date2)/60/60/24 --Days
declare #RemainderDate as datetime = #Date2 - #Days
select #Hours = datediff(ss, #Date1, #RemainderDate)/60/60 --Hours
set #RemainderDate = #RemainderDate - (#Hours/24.0)
select #Minutes = datediff(ss, #Date1, #RemainderDate)/60 --Minutes
set #RemainderDate = #RemainderDate - (#Minutes/24.0/60)
select #Seconds = DATEDIFF(SS, #Date1, #RemainderDate)
select #Days as ElapsedDays, #Hours as ElapsedHours, #Minutes as ElapsedMinutes, #Seconds as ElapsedSeconds
Hope this helps you in getting the exact time between two time stamps
Create PROC TimeDurationbetween2times(#iTime as time,#oTime as time)
As
Begin
DECLARE #Dh int, #Dm int, #Ds int ,#Im int, #Om int, #Is int,#Os int
SET #Im=DATEPART(MI,#iTime)
SET #Om=DATEPART(MI,#oTime)
SET #Is=DATEPART(SS,#iTime)
SET #Os=DATEPART(SS,#oTime)
SET #Dh=DATEDIFF(hh,#iTime,#oTime)
SET #Dm = DATEDIFF(mi,#iTime,#oTime)
SET #Ds = DATEDIFF(ss,#iTime,#oTime)
DECLARE #HH as int, #MI as int, #SS as int
if(#Im>#Om)
begin
SET #Dh=#Dh-1
end
if(#Is>#Os)
begin
SET #Dm=#Dm-1
end
SET #HH = #Dh
SET #MI = #Dm-(60*#HH)
SET #SS = #Ds-(60*#Dm)
DECLARE #hrsWkd as varchar(8)
SET #hrsWkd = cast(#HH as char(2))+':'+cast(#MI as char(2))+':'+cast(#SS as char(2))
select #hrsWkd as TimeDuration
End

Calculating time difference between 2 dates in minutes

I have a field of time Timestamp in my MySQL database which is mapped to a DATE datatype in my bean. Now I want a query by which I can fetch all records in the database for which the difference between the current timestamp and the one stored in the database is > 20 minutes.
How can I do it?
What i want is:
SELECT * FROM MyTab T WHERE T.runTime - now > 20 minutes
Are there any MySQL functions for this, or any way to do this in SQL?
If you have MySql version above 5.6 you could use TIMESTAMPDIFF(unit,datetime_expr1,datetime_expr2) something like
select * from MyTab T where
TIMESTAMPDIFF(MINUTE,T.runTime,NOW()) > 20
MySql version >=5.6
I am using below code for today and database date.
TIMESTAMPDIFF(MINUTE,T.runTime,NOW()) > 20
According to the documentation, the first argument can be any of the following:
MICROSECOND
SECOND
MINUTE
HOUR
DAY
WEEK
MONTH
QUARTER
YEAR
ROUND(time_to_sec((TIMEDIFF(NOW(), "2015-06-10 20:15:00"))) / 60);
Try this one:
select * from MyTab T where date_add(T.runTime, INTERVAL 20 MINUTE) < NOW()
NOTE: this should work if you're using MySQL DateTime format. If you're using Unix Timestamp (integer), then it would be even easier:
select * from MyTab T where UNIX_TIMESTAMP() - T.runTime > 20*60
UNIX_TIMESTAMP() function returns you current unix timestamp.
You can try this:
SELECT * FROM MyTab T WHERE CURRENT_TIMESTAMP() > T.runTime + INTERVAL 20 MINUTE;
The CURRENT_TIMESTAMP() is a function and returns the current date and time. This function works From MySQL 4.0
If you have MySql version prior than 5.6 you don't have TIMESTAMPDIFF. So,I wrote my own MySql function to do this. Accets %i or %m for minutes and %h for hours. You can extend it.
Example of usage:
SELECT MYTSDIFF('2001-01-01 10:44:32', '2001-01-01 09:50:00', '%h')
Here goes the function. Enjoy:
DROP FUNCTION IF EXISTS MYTSDIFF;
DELIMITER $$
CREATE FUNCTION `MYTSDIFF`( date1 timestamp, date2 timestamp, fmt varchar(20))
returns varchar(20) DETERMINISTIC
BEGIN
declare secs smallint(2);
declare mins smallint(2);
declare hours int;
declare total real default 0;
declare str_total varchar(20);
if date1 > DATE_ADD( date2, interval 30 day) then
return '999999.999'; /* OUT OF RANGE TIMEDIFF */
end if;
select cast( time_format( timediff(date1, date2), '%s') as signed) into secs;
select cast( time_format( timediff(date1, date2), '%i') as signed) into mins;
select cast( time_format( timediff(date1, date2), '%H') as signed) into hours;
set total = hours * 3600 + mins * 60 + secs;
set fmt = LOWER( fmt);
if fmt = '%m' or fmt = '%i' then
set total = total / 60;
elseif fmt = '%h' then
set total = total / 3600;
else
/* Do nothing, %s is the default: */
set total = total + 0;
end if;
select cast( total as char(20)) into str_total;
return str_total;
END$$
DELIMITER ;