I have a date column where the date is displayed in the format 2009-11-18 10:55:28.370.
I just want to get the date (not time) out of that value. How do I do that?
If you're using SQL Server 2008, there is now a DATE datatype. Makes it a lot more natural!
SELECT CONVERT(Date, GETDATE())
it is called "flooring a datetime", do it like this to remove just the time (this is the fastest method, faster than using CONVERT() or CAST() sting formatting):
DECLARE #datetime datetime;
SET #datetime = '2008-09-17 12:56:53.430';
SELECT DATEADD(day,DATEDIFF(day,0,#datetime),0)
OUTPUT:
-----------------------
2008-09-17 00:00:00.000
(1 row(s) affected)
here is how to do it for other parts of a datetime:
--Floor a datetime
DECLARE #datetime datetime;
SET #datetime = '2008-09-17 12:56:53.430';
SELECT '0 None', #datetime -- none 2008-09-17 12:56:53.430
UNION SELECT '1 Second',DATEADD(second,DATEDIFF(second,'2000-01-01',#datetime),'2000-01-01') -- Second: 2008-09-17 12:56:53.000
UNION SELECT '2 Minute',DATEADD(minute,DATEDIFF(minute,0,#datetime),0) -- Minute: 2008-09-17 12:56:00.000
UNION SELECT '3 Hour', DATEADD(hour,DATEDIFF(hour,0,#datetime),0) -- Hour: 2008-09-17 12:00:00.000
UNION SELECT '4 Day', DATEADD(day,DATEDIFF(day,0,#datetime),0) -- Day: 2008-09-17 00:00:00.000
UNION SELECT '5 Month', DATEADD(month,DATEDIFF(month,0,#datetime),0) -- Month: 2008-09-01 00:00:00.000
UNION SELECT '6 Year', DATEADD(year,DATEDIFF(year,0,#datetime),0) -- Year: 2008-01-01 00:00:00.000
ORDER BY 1
PRINT' '
PRINT 'Note that when you are flooring by the second, you will often get an arithmetic overflow if you use 0. So pick a known value that is guaranteed to be lower than the datetime you are attempting to floor'
PRINT 'this always uses a date less than the given date, so there will be no arithmetic overflow'
SELECT '1 Second',DATEADD(second,DATEDIFF(second,DATEADD(day,DATEDIFF(day,0,#datetime),0)-1,#datetime),DATEADD(day,DATEDIFF(day,0,#datetime),0)-1) -- Second: 2008-09-17 12:56:53.000
OUTPUT:
-------- -----------------------
0 None 2008-09-17 12:56:53.430
1 Second 2008-09-17 12:56:53.000
2 Minute 2008-09-17 12:56:00.000
3 Hour 2008-09-17 12:00:00.000
4 Day 2008-09-17 00:00:00.000
5 Month 2008-09-01 00:00:00.000
6 Year 2008-01-01 00:00:00.000
(7 row(s) affected)
Note that when you are flooring by the second, you will often get an arithmetic overflow if you use 0. So pick a known value that is guaranteed to be lower than the datetime you are attempting to floor
this always uses a date less than the given date, so there will be no arithmetic overflow
-------- -----------------------
1 Second 2008-09-17 12:56:53.000
(1 row(s) affected)
If i got your question right,
select convert(varchar, creation_date , 103) as creation_date from tablename
Look at CAST and CONVERT
Here:
SELECT creation_date
FROM risks
WHERE creation_date = GETDATE()
This will return all creation_date values stored in the risks table that are exactly the same as what is returned by the GETDATE() function. I am assuming that the data type of creation_date is Date.
You just need to include creation_date in your select clause like this:
select id, creation_date from risks where creation_date = getdate()
You can always use the month/day/year functions to return it:
declare #date datetime
set #date = '1/1/10 12:00 PM'
select cast(month(#date) as varchar) + '/' + cast(day(#date) as varchar) + '/' + cast(year(#date) as varchar) as theDate
Related
I have a query for calculating first and last date in the week, according to given date. It is enough to set #dDate and the query will calculate first (monday) and last date (sunday) for that week.
Problem is, that is calculating wrong and I don't understand why.
Example:
#dDate = 2019-10-03 (year-month-day).
Result:
W_START W_END
2019-09-25 2019-10-01
But it should be:
2019-09-30 2019-10-06
Why is that?
Query:
set datefirst 1
declare #dDate date = cast('2019-10-16' as date)
select #dDAte
declare #year int = (select DATEPART(year, #dDAte))
select #year
declare #StartingDate date = cast(('' + cast(#year as nvarchar(4)) + '-01-01') as date)
select #StartingDate
declare #dateWeekEnd date = (select DATEADD(week, (datepart(week, cast(#dDate as date)) - 1), #StartingDate))
declare #dateWeekStart date = dateadd(day, -6, #dateWeekEnd)
select #dateWeekStart W_START, #dateWeekEnd W_END
Days of the week are so complicated. I find it easier to remember that 2001-01-01 fell on a Monday.
Then, the following date arithmetic does what you want:
select dateadd(day,
7 * (datediff(day, '2001-01-01', #dDate) / 7),
'2001-01-01' -- 2001-01-01 fell on a Monday
)
I admit this is something of a cop-out/hack. But SQL Server -- and other databases -- make such date arithmetic so cumbersome that simple tricks like this are handy to keep in mind.
I apologize for the poorly worded title, I have been given a task beyond my limited skillset and was hoping someone might help.
We have employees who have 24/7 schedules for booking work and field assignments (over weekends as well) but this does not apply to vacation. Because of this I have been tasked to break a single date range up across weekends (and exclude them)
For Example:
Start Date: 30/04/2015 End Date: 13/05/2015
30/04/2015, 01/05/2015
04/05/2015, 05/05/2015, 06/05/2015, 07/05/2015, 08/05/2015,
11/05/2015, 12/05/2015, 13/05/2015,
Note: The weekends have been excluded and the date range has been split into three across the three weeks.
Preferably: Include the start and end points for each range like so
30/04/2015 - 01/05/2015 --(the same as it is the start and end dates)
04/05/2015 - 08/05/2015
11/05/2015 - 13/05/2015
I have no idea if this is even possible due to my very limited knowledge and hope I have explained enough so that some kind soul could potentially see if such a thing is even possible.
The database application we use is TSQL on SQL 2008.
Many thanks.
Thanks for the fun problem. Note: I use the standard date format, but the concept is the same.
DECLARE #StartDate DATE = '20150430', --April 30, 2015
#EndDate DATE = '20150513'; --May 13,2015
WITH CTE_Dates
AS
(
SELECT #StartDate dates
UNION ALL
SELECT DATEADD(DAY,1,dates)
FROM CTE_Dates
WHERE dates < #EndDate
),
CTE_weeks
AS
(
SELECT dates,
DATEPART(WEEK,dates) WeekID
FROM CTE_Dates
WHERE DATENAME(WEEKDAY,dates) NOT IN ('Saturday','Sunday') --doesn't include weekends
)
SELECT WeekID,
MIN(dates) StartDate,
MAX(dates) EndDate,
STUFF(list_dates,1,1,'') list
FROM CTE_weeks A
CROSS APPLY (
SELECT ',' + CAST(dates AS VARCHAR(100))
FROM CTE_weeks B
WHERE A.WeekID = B.WeekID
ORDER BY dates
FOR XML PATH('')
) CA(list_dates)
GROUP BY WeekID,STUFF(list_dates,1,1,'')
Results:
WeekID StartDate EndDate list
----------- ---------- ---------- ------------------------------------------------------------
18 2015-04-30 2015-05-01 2015-04-30,2015-05-01
19 2015-05-04 2015-05-08 2015-05-04,2015-05-05,2015-05-06,2015-05-07,2015-05-08
20 2015-05-11 2015-05-13 2015-05-11,2015-05-12,2015-05-13
This seems to work. It assumes you give it a start date that's a weekday:
declare #StartDate datetime = '20150430'
declare #EndDate datetime = '20150513'
; With Ord as (
select #StartDate as StartAt,#StartDate as EndAt
union all
select StartAt,DATEADD(day,1,EndAt)
from Ord where DATEPART(weekday,EndAt) != DATEPART(weekday,'20150710') --Known Friday
and EndAt < #EndDate
union all
select DATEADD(day,3,EndAt),DATEADD(day,3,EndAt)
from Ord where DATEPART(weekday,EndAt) = DATEPART(weekday,'20150710') --Still known Friday
and DATEADD(day,3,EndAt) <= #EndDate
)
select StartAt,MAX(EndAt) as EndAt
from Ord
group by StartAt
Result:
StartAt EndAt
----------------------- -----------------------
2015-04-30 00:00:00.000 2015-05-01 00:00:00.000
2015-05-04 00:00:00.000 2015-05-08 00:00:00.000
2015-05-11 00:00:00.000 2015-05-13 00:00:00.000
I do my comparisons about DATEPART using a "known good" (i.e. I just randomly selected one from a calendar) Friday so that this code works for any DATEFIRST setting.
I'm working on a Room Scheduling application. We have this Room Check Out Rule that we need follow. All
room check out should be 12:00 PM. If the check out date is after 12.00 PM it will be considered additional 1 day.
Below is my T-SQL code that returns 5 days.
SELECT DATEDIFF(day, '3/12/2013 12:00:00 PM', '3/17/2013 3:00:00 PM');
If you see the code above the end date is 3:00:00 PM. How can I tweak this code to return 6 days instead of 5?
What if I have this code?
SELECT CEILING(DATEDIFF(SECOND, '3/12/2013 02:00:00 PM' , '3/17/2013 12:50:36 PM') / (24.0 * 60 * 60))
The above code still returns 5 days instead of 6.
SELECT CEILING(DATEDIFF(SECOND, '3/12/2013 12:00:00 PM', '3/17/2013 12:00:01 PM') / (24.0 * 60 * 60))
The correct way is to subtract 12 hours from StartDate and EndDate, then take a day-diff + 1:
declare #dateStart as datetime, #dateEnd as datetime
set #dateStart = cast('20130301 11:59:59 AM' as datetime)
set #dateEnd = cast('20130301 12:01:01 PM' as datetime)
select
#dateStart,
#dateEnd
select days = 1 + datediff(d,#dateStart,#dateEnd)
select
days = 1 + datediff(d, dateadd(hh, -12, #dateStart), dateadd(hh, -12, #dateEnd))
returns this:
----------------------- -----------------------
2013-03-01 11:59:59.000 2013-03-01 12:01:01.000
days
-----------
1
days
-----------
2
Clearly the second formula is correct, not the first.
Perhaps you can count hours:
SELECT DATEDIFF(hour, '3/12/2013 12:00:00 PM', '3/17/2013 3:00:00 PM');
Therefore, 123 > 120 (or divided by 24 - 5.125 > 5) accounts for 6 days.
select *
from table
where date > '2010-07-20 03:21:52'
which I would expect to not give me any results... EXCEPT I'm getting a record with a datetime of 2010-07-20 03:21:52.577
how can I make the query ignore milliseconds?
You just have to figure out the millisecond part of the date and subtract it out before comparison, like this:
select *
from table
where DATEADD(ms, -DATEPART(ms, date), date) > '2010-07-20 03:21:52'
If you are using SQL Server (starting with 2008), choose one of this:
CONVERT(DATETIME2(0), YourDateField)
LEFT(RTRIM(CONVERT(DATETIMEOFFSET, YourDateField)), 19)
CONVERT(DATETIMEOFFSET(0), YourDateField) -- with the addition of a time zone offset
Try:
SELECT *
FROM table
WHERE datetime >
CONVERT(DATETIME,
CONVERT(VARCHAR(20),
CONVERT(DATETIME, '2010-07-20 03:21:52'), 120))
Or if your date is an actual datetime value:
DECLARE #date DATETIME
SET #date = GETDATE()
SELECT CONVERT(DATETIME, CONVERT(VARCHAR(20), #date, 120))
The conversion to style 120 cuts off the milliseconds...
select * from table
where DATEADD(ms, DATEDIFF(ms, '20000101', date), '20000101') > '2010-07-20 03:21:52'
You'll have to trim milliseconds before comparison, which will be slow over many rows
Do one of these to fix this:
created a computed column with the expressions above to compare against
remove milliseconds on insert/update to avoid the read overhead
If SQL Server 2008, use datetime2(0)
Use CAST with following parameters:
Date
select Cast('2017-10-11 14:38:50.540' as date)
Output: 2017-10-11
Datetime
select Cast('2017-10-11 14:38:50.540' as datetime)
Output: 2017-10-11 14:38:50.540
SmallDatetime
select Cast('2017-10-11 14:38:50.540' as smalldatetime)
Output: 2017-10-11 14:39:00
Note this method rounds to whole minutes (so you lose the seconds as well as the milliseconds)
DatetimeOffset
select Cast('2017-10-11 14:38:50.540' as datetimeoffset)
Output: 2017-10-11 14:38:50.5400000 +00:00
Datetime2
select Cast('2017-10-11 14:38:50.540' as datetime2)
Output: 2017-10-11 14:38:50.5400000
For this particular query, why make expensive function calls for each row when you could just ask for values starting at the next higher second:
select *
from table
where date >= '2010-07-20 03:21:53'
Use 'Smalldatetime' data type
select convert(smalldatetime, getdate())
will fetch
2015-01-08 15:27:00
There's more than one way to do it:
select 1 where datediff(second, '2010-07-20 03:21:52', '2010-07-20 03:21:52.577') >= 0
or
select *
from table
where datediff(second, '2010-07-20 03:21:52', date) >= 0
one less function call, but you have to be beware of overflowing the max integer if the dates are too far apart.
One more way I've set up SQL Server queries to ignore milliseconds when I'm looking for events from a particular second (in a parameter in "YYYY-MM-DD HH:TT:SS" format) using a stored procedure:
WHERE
...[Time_stamp] >= CAST(CONCAT(#YYYYMMDDHHTTSS,'.000') as DateTime) AND
...[Time_stamp] <= CAST(CONCAT(#YYYYMMDDHHTTSS,'.999') as DateTime)
You could use something similar to ignore minutes and seconds too.
Please try this
select substring('12:20:19.8470000',1,(CHARINDEX('.','12:20:19.8470000',1)-1))
(No column name)
12:20:19
I'm very late but I had the same issue a few days ago. None of the solutions above worked or seemed fit. I just needed a timestamp without milliseconds so I converted to a string using Date_Format and then back to a date with Str_To_Date:
STR_TO_DATE(DATE_FORMAT(your-timestamp-here, '%Y-%m-%d %H:%i:%s'),'%Y-%m-%d %H:%i:%s')
Its a little messy but works like a charm.
May be this will help..
SELECT [Datetime] = CAST('20120228' AS smalldatetime)
o/p:
2012-02-28 00:00:00
Review this example:
declare #now datetimeoffset = sysdatetimeoffset();
select #now;
-- 1
select convert(datetimeoffset(0), #now, 120);
-- 2
select convert(datetimeoffset, convert(varchar, #now, 120));
which yields output like the following:
2021-07-30 09:21:37.7000000 +00:00
-- 1
2021-07-30 09:21:38 +00:00
-- 2
2021-07-30 09:21:37.0000000 +00:00
Note that for (1), the result is rounded (up in this case), while for (2) it is truncated.
Therefore, if you want to truncate the milliseconds off a date(time)-type value as per the question, you must use:
declare #myDateTimeValue = <date-time-value>
select cast(convert(varchar, #myDateValue, 120) as <same-type-as-#myDateTimeValue>);
In SQL Server, how do I "floor" a DATETIME to the second/minute/hour/day/year?
Let's say that I have a date of 2008-09-17 12:56:53.430, then the output of flooring should be:
Year: 2008-01-01 00:00:00.000
Month: 2008-09-01 00:00:00.000
Day: 2008-09-17 00:00:00.000
Hour: 2008-09-17 12:00:00.000
Minute: 2008-09-17 12:56:00.000
Second: 2008-09-17 12:56:53.000
The key is to use DATEADD and DATEDIFF along with the appropriate SQL timespan enumeration.
declare #datetime datetime;
set #datetime = getdate();
select #datetime;
select dateadd(year,datediff(year,0,#datetime),0);
select dateadd(month,datediff(month,0,#datetime),0);
select dateadd(day,datediff(day,0,#datetime),0);
select dateadd(hour,datediff(hour,0,#datetime),0);
select dateadd(minute,datediff(minute,0,#datetime),0);
select dateadd(second,datediff(second,'2000-01-01',#datetime),'2000-01-01');
select dateadd(week,datediff(week,0,#datetime),-1); --Beginning of week is Sunday
select dateadd(week,datediff(week,0,#datetime),0); --Beginning of week is Monday
Note that when you are flooring by the second, you will often get an arithmetic overflow if you use 0. So pick a known value that is guaranteed to be lower than the datetime you are attempting to floor.
In SQL Server here's a little trick to do that:
SELECT CAST(FLOOR(CAST(CURRENT_TIMESTAMP AS float)) AS DATETIME)
You cast the DateTime into a float, which represents the Date as the integer portion and the Time as the fraction of a day that's passed. Chop off that decimal portion, then cast that back to a DateTime, and you've got midnight at the beginning of that day.
This is probably more efficient than all the DATEADD and DATEDIFF stuff. It's certainly way easier to type.
Expanding upon the Convert/Cast solution, in Microsoft SQL Server 2008 you can do the following:
cast(cast(getdate() as date) as datetime)
Just replace getdate() with any column which is a datetime.
There are no strings involved in this conversion.
This is ok for ad-hoc queries or updates, but for key joins or heavily used processing it may be better to handle the conversion within the processing or redefine the tables to have appropriate keys and data.
In 2005, you can use the messier floor: cast(floor(cast(getdate() as float)) as datetime)
I don't think that uses string conversion either, but I can't speak to comparing actual efficiency versus armchair estimates.
I've used #Portman's answer many times over the years as a reference when flooring dates and have moved its working into a function which you may find useful.
I make no claims to its performance and merely provide it as a tool for the user.
I ask that, if you do decide to upvote this answer, please also upvote #Portman's answer, as my code is a derivative of his.
IF OBJECT_ID('fn_FloorDate') IS NOT NULL DROP FUNCTION fn_FloorDate
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[fn_FloorDate] (
#Date DATETIME = NULL,
#DatePart VARCHAR(6) = 'day'
)
RETURNS DATETIME
AS
BEGIN
IF (#Date IS NULL)
SET #Date = GETDATE();
RETURN
CASE
WHEN LOWER(#DatePart) = 'year' THEN DATEADD(YEAR, DATEDIFF(YEAR, 0, #Date), 0)
WHEN LOWER(#DatePart) = 'month' THEN DATEADD(MONTH, DATEDIFF(MONTH, 0, #Date), 0)
WHEN LOWER(#DatePart) = 'day' THEN DATEADD(DAY, DATEDIFF(DAY, 0, #Date), 0)
WHEN LOWER(#DatePart) = 'hour' THEN DATEADD(HOUR, DATEDIFF(HOUR, 0, #Date), 0)
WHEN LOWER(#DatePart) = 'minute' THEN DATEADD(MINUTE, DATEDIFF(MINUTE, 0, #Date), 0)
WHEN LOWER(#DatePart) = 'second' THEN DATEADD(SECOND, DATEDIFF(SECOND, '2000-01-01', #Date), '2000-01-01')
ELSE DATEADD(DAY, DATEDIFF(DAY, 0, #Date), 0)
END;
END
Usage:
DECLARE #date DATETIME;
SET #date = '2008-09-17 12:56:53.430';
SELECT
#date AS [Now],--2008-09-17 12:56:53.430
dbo.fn_FloorDate(#date, 'year') AS [Year],--2008-01-01 00:00:00.000
dbo.fn_FloorDate(default, default) AS [NoParams],--2013-11-05 00:00:00.000
dbo.fn_FloorDate(#date, default) AS [ShouldBeDay],--2008-09-17 00:00:00.000
dbo.fn_FloorDate(#date, 'month') AS [Month],--2008-09-01 00:00:00.000
dbo.fn_FloorDate(#date, 'day') AS [Day],--2008-09-17 00:00:00.000
dbo.fn_FloorDate(#date, 'hour') AS [Hour],--2008-09-17 12:00:00.000
dbo.fn_FloorDate(#date, 'minute') AS [Minute],--2008-09-17 12:56:00.000
dbo.fn_FloorDate(#date, 'second') AS [Second];--2008-09-17 12:56:53.000
The CONVERT() function can do this as well, depending on what style you use.
Too bad it's not Oracle, or else you could use trunc() or to_char().
But I had similar issues with SQL Server and used the CONVERT() and DateDiff() methods, as referenced here
There are several ways to skin this cat =)
select convert(datetime,convert(varchar,CURRENT_TIMESTAMP,101))
DateAdd along with DateDiff can help to do many different tasks. For example, you can find last day of any month as well can find last day of previous or next month.
----Last Day of Previous Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE()),0))
LastDay_PreviousMonth
----Last Day of Current Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
LastDay_CurrentMonth
----Last Day of Next Month
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+2,0))
LastDay_NextMonth
Source
Since PostgreSQL is also a "SQL Server", I'll mention
date_trunc()
Which does exactly what you're asking gracefully.
For example:
select date_trunc('hour',current_timestamp);
date_trunc
------------------------
2009-02-18 07:00:00-08
(1 row)