SQL - Convert INT to Date - sql

I am trying to convert INT (YYYYMM) value to DATE.
I have read articles which mention that converts from char to date format. So I am curious to know - which of the foll. is a good approach?
Example:
DECLARE #PERIOD INT ='201806'
SELECT CAST(CONCAT(#Period,'01') AS DATE) SQLCAST1
,CAST(CAST(#Period AS varchar(6))+'01' AS DATE) SQLCAST2
Which is the ideal approach and why? Do we have other better approach?

I am not a fan of implicit data type conversions, so I would phrase the first as:
select convert(date, convert(varchar(6), #PERIOD ) + '01')
Or use datefromparts() which is a built-in function for constructing dates:
select datefromparts( #PERIOD / 100, #PERIOD % 100, 1)

Apparently concat is the most efficient method.
https://raresql.com/2013/03/12/sql-server-string-concatenation-faster-method/
Cast also appears to be the most efficient method for parsing a standard date string (see the try_cast times for DateTime)
SQL - Convert INT to Date
Your first method is most efficient.

Here is another method, First you have to convert to char then convert to date time,
declare #intValue int
select #intValue = 201907
select convert(date, convert(varchar(6), #intValue ) + '01')

Related

SQL Convert data time format (yyyy-mm-dd 00:00:00.000) to yyyymmdd as int

It must be very simple, but I don't know SQL language very well.
I need to filter data by date which is in this format:
How to do it right to filter data this way?
FROM [TableName] where
FileDate>=20220505
I've already tried the command LEFT and CAST but with no success
Something like this may work:
declare #now Datetime = getdate();
declare #intNow int = cast(cast(datepart(year, #now) as varchar(4)) + RIGHT('00'+CAST(datepart(month, #now) AS VARCHAR(2)),2) + RIGHT('00'+CAST(datepart(day, #now) AS VARCHAR(2)),2) as int)
Although if you have your date to check against in the right format e.g. using:
declare #dateToCheck Datetime = cast(cast(20220505 as varchar) as datetime)
And then
FileDate>= #dateToCheck
it should work
You can create an integer representation of your datetime by multiplying and adding the date parts:
year * 10000 20220000
month * 100 500
day 5
-------------------------
20220505
...
FROM [TableName]
WHERE (DATEPART(year, [FileDate]) * 10000) + (DATEPART(month, [FileDate]) * 100) + (DATEPART(day, [FileDate])) >= 20220505
However I'd still look into fixing the condition input format instead.
Credit to #Rangani in Yesterday's date in SSIS package setting in variable through expression for "multiply and add instead of string concat" trick

Combining (concatenating) date and time into a datetime

Using SQL Server 2008, this query works great:
select CAST(CollectionDate as DATE), CAST(CollectionTime as TIME)
from field
Gives me two columns like this:
2013-01-25 18:53:00.0000000
2013-01-25 18:53:00.0000000
2013-01-25 18:53:00.0000000
2013-01-25 18:53:00.0000000
.
.
.
I'm trying to combine them into a single datetime using the plus sign, like this:
select CAST(CollectionDate as DATE) + CAST(CollectionTime as TIME)
from field
I've looked on about ten web sites, including answers on this site (like this one), and they all seem to agree that the plus sign should work but I get the error:
Msg 8117, Level 16, State 1, Line 1
Operand data type date is invalid for add operator.
All fields are non-zero and non-null. I've also tried the CONVERT function and tried to cast these results as varchars, same problem. This can't be as hard as I'm making it.
Can somebody tell me why this doesn't work? Thanks for any help.
Assuming the underlying data types are date/time/datetime types:
SELECT CONVERT(DATETIME, CONVERT(CHAR(8), CollectionDate, 112)
+ ' ' + CONVERT(CHAR(8), CollectionTime, 108))
FROM dbo.whatever;
This will convert CollectionDate and CollectionTime to char sequences, combine them, and then convert them to a datetime.
The parameters to CONVERT are data_type, expression and the optional style (see syntax documentation).
The date and time style value 112 converts to an ISO yyyymmdd format. The style value 108 converts to hh:mi:ss format. Evidently both are 8 characters long which is why the data_type is CHAR(8) for both.
The resulting combined char sequence is in format yyyymmdd hh:mi:ss and then converted to a datetime.
The simple solution
SELECT CAST(CollectionDate as DATETIME) + CAST(CollectionTime as DATETIME)
FROM field
An easier solution (tested on SQL Server 2014 SP1 CU6)
Code:
DECLARE #Date date = SYSDATETIME();
DECLARE #Time time(0) = SYSDATETIME();
SELECT CAST(CONCAT(#Date, ' ', #Time) AS datetime2(0));
This would also work given a table with a specific date and a specific time field. I use this method frequently given that we have vendor data that uses date and time in two separate fields.
Cast it to datetime instead:
select CAST(CollectionDate as DATETIME) + CAST(CollectionTime as TIME)
from field
This works on SQL Server 2008 R2.
If for some reason you wanted to make sure the first part doesn't have a time component, first cast the field to date, then back to datetime.
DECLARE #ADate Date, #ATime Time, #ADateTime Datetime
SELECT #ADate = '2010-02-20', #ATime = '18:53:00.0000000'
SET #ADateTime = CAST (
CONVERT(Varchar(10), #ADate, 112) + ' ' +
CONVERT(Varchar(8), #ATime) AS DateTime)
SELECT #ADateTime [A nice datetime :)]
This will render you a valid result.
Solution (1): datetime arithmetic
Given #myDate, which can be anything that can be cast as a DATE, and #myTime, which can be anything that can be cast as a TIME, starting SQL Server 2014+ this works fine and does not involve string manipulation:
CAST(CAST(#myDate as DATE) AS DATETIME) + CAST(CAST(#myTime as TIME) as DATETIME)
You can verify with:
SELECT GETDATE(),
CAST(CAST(GETDATE() as DATE) AS DATETIME) + CAST(CAST(GETDATE() as TIME) as DATETIME)
Solution (2): string manipulation
SELECT GETDATE(),
CONVERT(DATETIME, CONVERT(CHAR(8), GETDATE(), 112) + ' ' + CONVERT(CHAR(8), GETDATE(), 108))
However, solution (1) is not only 2-3x faster than solution (2), it also preserves the microsecond part.
See SQL Fiddle for the solution (1) using date arithmetic vs solution (2) involving string manipulation
Concat date of one column with a time of another column in MySQL.
SELECT CONVERT(concat(CONVERT('dateColumn',DATE),' ',CONVERT('timeColumn', TIME)), DATETIME) AS 'formattedDate' FROM dbs.tableName;
drop table test
create table test(
CollectionDate date NULL,
CollectionTime [time](0) NULL,
CollectionDateTime as (isnull(convert(datetime,CollectionDate)+convert(datetime,CollectionTime),CollectionDate))
-- if CollectionDate is datetime no need to convert it above
)
insert test (CollectionDate, CollectionTime)
values ('2013-12-10', '22:51:19.227'),
('2013-12-10', null),
(null, '22:51:19.227')
select * from test
CollectionDate CollectionTime CollectionDateTime
2013-12-10 22:51:19 2013-12-10 22:51:19.000
2013-12-10 NULL 2013-12-10 00:00:00.000
NULL 22:51:19 NULL
This works in SQL 2008 and 2012 to produce datetime2:
declare #date date = current_timestamp;
declare #time time = current_timestamp;
select
#date as date
,#time as time
,cast(#date as datetime) + cast(#time as datetime) as datetime
,cast(#time as datetime2) as timeAsDateTime2
,dateadd(dayofyear,datepart(dayofyear,#date) - 1,dateadd(year,datepart(year,#date) - 1900,cast(#time as datetime2))) as datetime2;
dealing with dates, dateadd must be used for precision
declare #a DATE = getdate()
declare #b time(7) = getdate()
select #b, #A, GETDATE(), DATEADD(day, DATEDIFF(day, 0, #a), cast(#b as datetime2(0)))
I am using SQL Server 2016 and both myDate and myTime fields are strings. The below tsql statement worked in concatenating them into datetime
select cast((myDate + ' ' + myTime) as datetime) from myTable
SELECT CONVERT(DATETIME, CONVERT(CHAR(8), date, 112) + ' ' + CONVERT(CHAR(8), time, 108))
FROM tablename

convert date to YYMM format in sql for given date

How can we convert date format to YYMM(ex:1208) for the given date 25/08/2012.
Use convert with style 12 and pick the first four characters.
select convert(char(4), getdate(), 12)
try this:
declare #date date='08/25/2012'
select CONVERT(varchar(4),#date,12)
You did not specify the datatype for the value 25/08/2012.
declare #dt char(10)
set #dt = '25/08/2012'
select right(#dt, 2) + substring(#dt, 4, 2)
If you don't like remembering the string convert formulas, you can also use:
declare #date date=CURRENT_TIMESTAMP
select right(CAST(year(#date) as varchar(4)), 2) + RIGHT('0'+cast(month(#date) as varchar(2)), 2)
It is a bit more cumbersome, but saves a trip to the help pages.

Convert INT to DATETIME (SQL)

I am trying to convert a date to datetime but am getting errors. The datatype I'm converting from is (float,null) and I'd like to convert it to DATETIME.
The first line of this code works fine, but I get this error on the second line:
Arithmetic overflow error converting expression to data type datetime.
CAST(CAST( rnwl_efctv_dt AS INT) AS char(8)),
CAST(CAST( rnwl_efctv_dt AS INT) AS DATETIME),
you need to convert to char first because converting to int adds those days to 1900-01-01
select CONVERT (datetime,convert(char(8),rnwl_efctv_dt ))
here are some examples
select CONVERT (datetime,5)
1900-01-06 00:00:00.000
select CONVERT (datetime,20100101)
blows up, because you can't add 20100101 days to 1900-01-01..you go above the limit
convert to char first
declare #i int
select #i = 20100101
select CONVERT (datetime,convert(char(8),#i))
Try this:
select CONVERT(datetime, convert(varchar(10), 20120103))
use a where clause on that field to ignore nulls and zero values
update
table
set
BDOS= CONVERT(datetime, convert(char(8), field))
where
isnull(field,0)<>0
A simpler, and possibly faster solution is to use DATEFROMPARTS and a bit of arithmetic.
DECLARE #v bigint = 20220623;
SELECT DATEFROMPARTS(#v / 10000, #v / 100 % 100, #v % 100);
Result
2022-06-23
db<>fiddle
Convert(VARCHAR(10), CAST(CONVERT(char(8), "Replace with you date") as date), 101) "Your alias"

How can I compare time in SQL Server?

I'm trying to compare time in a datetime field in a SQL query, but I don't know if it's right. I don't want to compare the date part, just the time part.
I'm doing this:
SELECT timeEvent
FROM tbEvents
WHERE convert(datetime, startHour, 8) >= convert(datetime, #startHour, 8)
Is it correct?
I'm asking this because I need to know if 08:00:00 is less or greater than 07:30:00 and I don't want to compare the date, just the time part.
Thanks!
Your compare will work, but it will be slow because the dates are converted to a string for each row. To efficiently compare two time parts, try:
declare #first datetime
set #first = '2009-04-30 19:47:16.123'
declare #second datetime
set #second = '2009-04-10 19:47:16.123'
select (cast(#first as float) - floor(cast(#first as float))) -
(cast(#second as float) - floor(cast(#second as float)))
as Difference
Long explanation: a date in SQL server is stored as a floating point number. The digits before the decimal point represent the date. The digits after the decimal point represent the time.
So here's an example date:
declare #mydate datetime
set #mydate = '2009-04-30 19:47:16.123'
Let's convert it to a float:
declare #myfloat float
set #myfloat = cast(#mydate as float)
select #myfloat
-- Shows 39931,8244921682
Now take the part after the comma character, i.e. the time:
set #myfloat = #myfloat - floor(#myfloat)
select #myfloat
-- Shows 0,824492168212601
Convert it back to a datetime:
declare #mytime datetime
set #mytime = convert(datetime,#myfloat)
select #mytime
-- Shows 1900-01-01 19:47:16.123
The 1900-01-01 is just the "zero" date; you can display the time part with convert, specifying for example format 108, which is just the time:
select convert(varchar(32),#mytime,108)
-- Shows 19:47:16
Conversions between datetime and float are pretty fast, because they're basically stored in the same way.
convert(varchar(5), thedate, 108) between #leftTime and #rightTime
Explanation:
if you have varchar(5) you will obtain HH:mm
if you have varchar(8) you obtain HH:mm ss
108 obtains only the time from the SQL date
#leftTime and #rightTime are two variables to compare
If you're using SQL Server 2008, you can do this:
WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), #startTime)
Here's a full test:
DECLARE #tbEvents TABLE (
timeEvent int IDENTITY,
startHour datetime
)
INSERT INTO #tbEvents (startHour) SELECT DATEADD(hh, 0, GETDATE())
INSERT INTO #tbEvents (startHour) SELECT DATEADD(hh, 1, GETDATE())
INSERT INTO #tbEvents (startHour) SELECT DATEADD(hh, 2, GETDATE())
INSERT INTO #tbEvents (startHour) SELECT DATEADD(hh, 3, GETDATE())
INSERT INTO #tbEvents (startHour) SELECT DATEADD(hh, 4, GETDATE())
INSERT INTO #tbEvents (startHour) SELECT DATEADD(hh, 5, GETDATE())
--SELECT * FROM #tbEvents
DECLARE #startTime datetime
SET #startTime = DATEADD(mi, 65, GETDATE())
SELECT
timeEvent,
CONVERT(time(0), startHour) AS 'startHour',
CONVERT(time(0), #startTime) AS '#startTime'
FROM #tbEvents
WHERE CONVERT(time(0), startHour) >= CONVERT(time(0), #startTime)
Just change convert datetime to time that should do the trick:
SELECT timeEvent
FROM tbEvents
WHERE convert(time, startHour) >= convert(time, #startHour)
if (cast('2012-06-20 23:49:14.363' as time) between
cast('2012-06-20 23:49:14.363' as time) and
cast('2012-06-20 23:49:14.363' as time))
One (possibly small) issue I have noted with the solutions so far is that they all seem to require a function call to process the comparison. This means that the query engine will need to do a full table scan to seek the rows you are after - and be unable to use an index. If the table is not going to get particularly large, this probably won't have any adverse affects (and you can happily ignore this answer).
If, on the other hand, the table could get quite large, the performance of the query could suffer.
I know you stated that you do not wish to compare the date part - but is there an actual date being stored in the datetime column, or are you using it to store only the time? If the latter, you can use a simple comparison operator, and this will reduce both CPU usage, and allow the query engine to use statistics and indexes (if present) to optimise the query.
If, however, the datetime column is being used to store both the date and time of the event, this obviously won't work. In this case if you can modify the app and the table structure, separate the date and time into two separate datetime columns, or create a indexed view that selects all the (relevant) columns of the source table, and a further column that contains the time element you wish to search for (use any of the previous answers to compute this) - and alter the app to query the view instead.
Using float does not work.
DECLARE #t1 datetime, #t2 datetime
SELECT #t1 = '19000101 23:55:00', #t2 = '20001102 23:55:00'
SELECT CAST(#t1 as float) - floor(CAST(#t1 as float)), CAST(#t2 as float) - floor(CAST(#t2 as float))
You'll see that the values are not the same (SQL Server 2005). I wanted to use this method to check for times around midnight (the full method has more detail) in which I was comparing the current time for being between 23:55:00 and 00:05:00.
Adding to the other answers:
you can create a function for trimming the date from a datetime
CREATE FUNCTION dbo.f_trimdate (#dat datetime) RETURNS DATETIME AS BEGIN
RETURN CONVERT(DATETIME, CONVERT(FLOAT, #dat) - CONVERT(INT, #dat))
END
So this:
DECLARE #dat DATETIME
SELECT #dat = '20080201 02:25:46.000'
SELECT dbo.f_trimdate(#dat)
Will return
1900-01-01 02:25:46.000
Use Datepart function: DATEPART(datepart, date)
E.g#
SELECT DatePart(#YourVar, hh)*60) +
DatePart(#YourVar, mi)*60)
This will give you total time of day in minutes allowing you to compare more easily.
You can use DateDiff if your dates are going to be the same, otherwise you'll need to strip out the date as above
You can create a two variables of datetime, and set only hour of date that your need to compare.
declare #date1 datetime;
declare #date2 datetime;
select #date1 = CONVERT(varchar(20),CONVERT(datetime, '2011-02-11 08:00:00'), 114)
select #date2 = CONVERT(varchar(20),GETDATE(), 114)
The date will be "1900-01-01" you can compare it
if #date1 <= #date2
print '#date1 less then #date2'
else
print '#date1 more then #date2'
SELECT timeEvent
FROM tbEvents
WHERE CONVERT(VARCHAR,startHour,108) >= '01:01:01'
This tells SQL Server to convert the current date/time into a varchar using style 108, which is "hh:mm:ss". You can also replace '01:01:01' which another convert if necessary.
I believe you want to use DATEPART('hour', datetime).
Reference is here:
http://msdn.microsoft.com/en-us/library/ms174420.aspx
I don't love relying on storage internals (that datetime is a float with whole number = day and fractional = time), but I do the same thing as the answer Jhonny D. Cano. This is the way all of the db devs I know do it. Definitely do not convert to string. If you must avoid processing as float/int, then the best option is to pull out hour/minute/second/milliseconds with DatePart()
I am assuming your startHour column and #startHour variable are both DATETIME; In that case, you should be converting to a string:
SELECT timeEvent
FROM tbEvents
WHERE convert(VARCHAR(8), startHour, 8) >= convert(VARCHAR(8), #startHour, 8)
below query gives you time of the date
select DateAdd(day,-DateDiff(day,0,YourDateTime),YourDateTime) As NewTime from Table
#ronmurp raises a valid concern - the cast/floor approach returns different values for the same time. Along the lines of the answer by #littlechris and for a more general solution that solves for times that have a minute, seconds, milliseconds component, you could use this function to count the number of milliseconds from the start of the day.
Create Function [dbo].[MsFromStartOfDay] ( #DateTime datetime )
Returns int
As
Begin
Return (
( Datepart( ms , #DateTime ) ) +
( Datepart( ss , #DateTime ) * 1000 ) +
( Datepart( mi , #DateTime ) * 1000 * 60 ) +
( Datepart( hh , #DateTime ) * 1000 * 60 * 60 )
)
End
I've verified that it returns the same int for two different dates with the same time
declare #first datetime
set #first = '1900-01-01 23:59:39.090'
declare #second datetime
set #second = '2000-11-02 23:56:39.090'
Select dbo.MsFromStartOfDay( #first )
Select dbo.MsFromStartOfDay( #second )
This solution doesn't always return the int you would expect. For example, try the below in SQL 2005, it returns an int ending in '557' instead of '556'.
set #first = '1900-01-01 23:59:39.556'
set #second = '2000-11-02 23:56:39.556'
I think this has to do with the nature of DateTime stored as float. You can still compare the two number, though. And when I used this approach on a "real" dataset of DateTime captured in .NET using DateTime.Now() and stored in SQL, I found that the calculations were accurate.
TL;DR
Separate the time value from the date value if you want to use indexes in your search (you probably should, for performance). You can: (1) use function-based indexes or (2) create a new column for time only, index this column and use it in you SELECT clause.
Keep in mind you will lose any index performance boost if you use functions in a SQL's WHERE clause, the engine has to do a scan search. Just run your query with EXPLAIN SELECT... to confirm this. This happens because the engine has to process EVERY value in the field for EACH comparison, and the converted value is not indexed.
Most answers say to use float(), convert(), cast(), addtime(), etc.. Again, your database won't use indexes if you do this. For small tables that may be OK.
It is OK to use functions in WHERE params though (where field = func(value)), because you won't be changing EACH field's value in the table.
In case you want to keep use of indexes, you can create a function-based index for the time value. The proper way to do this (and support for it) may depend on your database engine. Another option is adding a column to store only the time value and index this column, but try the former approach first.
Edit 06-02
Do some performance tests before updating your database to have a new time column or whatever to make use of indexes. In my tests, I found out the performance boost was minimal (when I could see some improvement) and wouldn't be worth the trouble and overhead of adding a new index.