Is there a function like isdate() for datetime2? - sql-server-2008

I know there is a function called ISDATE to validate DATETIME columns, but it works only for the SMALLDATETIME and DATETIME types.
Is there a similar way to validate the new data type DATETIME2 in SQL Server 2008 and 2012?

In SQL Server 2012, you can use TRY_CONVERT:
SELECT TRY_CONVERT(DATETIME2, '2012-02-02 13:42:55.2323623'),
TRY_CONVERT(DATETIME2, '2012-02-31 13:42:55.2323623');
Results:
2012-02-02 13:42:55.2323623 NULL
Or TRY_PARSE:
SELECT TRY_PARSE('2012-02-02 13:42:55.2323623' AS DATETIME2),
TRY_PARSE('2012-02-31 13:42:55.2323623' AS DATETIME2);
(Same results.)
Sorry that I don't have a clever answer for you for < SQL Server 2012. You could, I guess, say
SELECT ISDATE(LEFT('2012-02-02 13:42:55.2323623', 23));
But that feels dirty.
TRY_CONVERT documentation on Microsoft Docs
TRY_PARSE documentation on Microsoft Docs

Be careful using the LEFT(..., 23) solution on database systems using another dateformat than mdy (and SQL-Server 2008). You can see the dateformat of the current session using the DBCC USEROPTIONS command.
On a database system using the german dateformat (dmy) the LEFT(..., 23) solution isn't working (detected on dates with day > 12). See the following test case:
-- test table using a DATETIME and DATETIME2 column.
CREATE TABLE dt_vs_dt2 (
dt DATETIME,
dt2 DATETIME2
);
-- set a datetime values with a day > 12.
DECLARE #date_value AS DATETIME = DATEADD(DAY, 18 - DAY(GETDATE()), GETDATE());
-- insert the current date into both columns using GETDATE.
-- note: using the following on a day > 12
INSERT INTO dt_vs_dt2 VALUES (#date_value, #date_value);
-- let's have a look at the values.
-- the values look the same (the datetime2 is more precise as expected).
SELECT dt, dt2 FROM dt_vs_dt2;
-- now we expect both values are valid date values.
-- to validate the datetime2 value, the LEFT(..., 23) solution is used.
SELECT ISDATE(dt), ISDATE(LEFT(dt2, 23))
FROM dt_vs_dt2;
How to solve that?
You can use a CAST(column_name AS DATETIME) instead of the LEFT(..., 23) to make this work:
-- using a CAST(... AS DATETIME) instead of `LEFT(..., 23)` seems to work.
SELECT dt, CAST(dt2 AS DATETIME) AS dt2
FROM dt_vs_dt2;
-- now both values are valid dates.
SELECT ISDATE(dt) AS dt, ISDATE(CAST(dt2 AS DATETIME)) AS dt2
FROM dt_vs_dt2;
demo on dbfiddle.uk (using dmy) / demo on dbfiddle.uk (using mdy)
On SQL Server 2012 and later you should use the TRY_PARSE / TRY_CONVERT solution described in #Aaron Bertrand answer. The CAST(... AS DATETIME) solution explained in this answer should also work.

Related

SQL Server Compact Edition 12 hour time format

Been searching anywhere but I cant find any solution to my problem. I am working with SQL Server Compact Edition, Im using SQL Management Studio 2008 and dealing with time formats.
I want a datetime datatype returns a 12hour format. So far, I have this one:
SELECT
CONVERT(nvarchar(10), StartTime, 108) as timein
FROM TicketSales
It gives this result : 14:43:05
How can I achieve a 12 Hour format for this ? any help please?
Note: For SQL Server Compact Edition 2008
The closest I could come to an answer uses format mask 109:
SELECT
GETDATE() AS timestamp,
RIGHT(CONVERT(nvarchar(26), GETDATE(), 109), 14) AS time;
If you don't want those fractional seconds, then we can try using substring and concatenation:
WITH cte AS (
SELECT CONVERT(nvarchar(26), GETDATE(), 109) AS time
)
SELECT
time,
SUBSTRING(time, 13, 8) + RIGHT(time, 2) AS time
FROM cte;
You must use the right style, like 100
declare #mytime as Time = '14:00'
select CONVERT(varchar(15),#mytime,100)
=> 2:00pm
Original Answer:
converting-a-time-into-12-hour-format-in-sql

Convert string yyyymmddhhmmss into hh:mm:ss format in SQL

With the string DATETIME yyyymmddhhmmss like 20160125173013, I would like to convert this string into hh:mm:ss (17:30:13) as a new column called "Time" in a table with sql update statement. However I am only able to convert it into 17:30 using the stuff function.
Is there any possible solution to convert?
In my statement
UPDATE db
SET Time =convert(time, stuff(substring(DATETIME,9,6),3,2,':'))
FROM db
WHERE Time IS NULL
Real Output=17:13:00.0000000
But my expected output is 17:13:00
Thanks a lot!
Here is the miracle for mysql:
SELECT time(str_to_date('20160125173013', '%Y%m%d%H%i%s'));
Do you have an actual DATETIME field? If so you can use DATE_FORMAT():
UPDATE mytable SET my_time=DATE_FORMAT(my_date, '%H:%i:%s')
If you don't have a native DATETIME field I hope you can convert it to one, as irregular, quirky formats cause trouble and introduce a lot of overhead when parsing to convert. STR_TO_DATE() can do the opposite of DATE_FORMAT() and convert from arbitrary strings to native DATE or DATETIME values.
Don't confuse STORAGE with PRESENTATION
Declare #YourTable table (DateTime varchar(25),Time time)
Insert Into #YourTable values
('20160125173013',null)
Update #YourTable
Set Time = stuff(left(right(DateTime,6),4),3,0,':')
Select *
,FormatedTime = Format(cast(Time as datetime),'HH:mm')
From #YourTable
Returns
DateTime Time FormatedTime
20160125173013 17:30:00.0000000 17:30
Based on the use of the STUFF function I believe this is Microsoft SQL Server, and not MySql.
Therefor, you can do something like this:
UPDATE db
SET [Time] = CAST(SUBSTRING([DATETIME], 9, 2) +':'+
SUBSTRING([DATETIME], 11, 2) +':'+
RIGHT([DATETIME], 2) As Time)
WHERE [Time] IS NULL
Your string is no format, SQL Server will cast implicitly
DECLARE #YourDateTimeString VARCHAR(100)='20160125173013';
The following query will cut the first 8 digits and cast them to DATE, which works implicitly (unseparated format). The time is cut from the right side, then the two :-signs are stuffed into the right places:
SELECT CAST(LEFT(#YourDateTimeString,8) AS DATE)
,CAST(STUFF(STUFF(RIGHT(#YourDateTimeString,6),5,0,':'),3,0,':') AS TIME);
The result
2016-01-25 17:30:13.0000000
If you need this as string without the trailing .0000000 (which is a pure output format question and should be done in your presentation layer!) you can just use LEFT(). The input of this function is string (again implicitly casted), the output is a text which looks like a time.
SELECT CAST(LEFT(#YourDateTimeString,8) AS DATE)
,LEFT(CAST(STUFF(STUFF(RIGHT(#YourDateTimeString,6),5,0,':'),3,0,':') AS TIME),8);
The result
2016-01-25 17:30:13
If you ar eusing SQL server then use Convert function
Declare #VarCharDate varchar(max)
Declare #VarCharDate1 varchar(max)
--Declare
set #VarCharDate = '20160125173013' --- YYYYMMDDHHMMSS
--Convert
set #VarCharDate1 =(select SUBSTRING(#VarCharDate,0,5) + '/' +
SUBSTRING(#VarCharDate,5,2) + '/' + SUBSTRING(#VarCharDate,7,2)
+ ' ' + SUBSTRING(#VarCharDate,9,2)
+':'+SUBSTRING(#VarCharDate,11,2) +':' + RIGHT(#VarCharDate,2))
select #VarCharDate1
select Convert(varchar(8),convert(datetime, #VarCharDate1, 120),114)

SQL Change date format from yyyy-mm-dd to dd-mm-yyyy

I have created MySQL table :
CREATE TABLE EMP(
EMPID INTEGER NOT NULL (5),
SURNAME VARCHAR(25),
SAL INTEGER(5),
JON VARCHAR(25),
START_DATE DATE,
END_DATE DATE,
DEPNO INTEGER(5)
);
with following records:
INSERT INTO EMP
(EMPID,SURNAME,SALARY,JOB,START_DATE,END_DATE,DEPNO)
VALUES
('1','Vorosila','500000','COO','20150101',null,'1');
however I need to change date format from 2015 01 01 to 01 01 2015
Can anybody show me or tell me how to do that ?
THANK YOU IN ADVANCE
DATE values do not have a "format", they are objects that represent instants in time (or entire days, but still independent of formatting).
Formats are applied on input and output, so you just need to apply the correct format, which you can find in the MySQL manual, to the SELECT statement.
You cannot change the default date format in mysql.
I once hoped for the default date to be editable so I wouldn't have to jump through these hoops to get the date I actually wanted, mysql even has a date format system variable, but it is unused. Date Format Mysql - link
What you should really do is store it as the default format Year-Month-Date and then convert it on select.
The first thing I'd suggest is having your date columns as date types, which would give your dates the following format '2015-01-01'.
If you do this then you can use DATE_FORMAT - link - the second value in the DATE_FORMAT function allows you to customise the returned date, and there are many different thing you can do with this if you look at the link:
SELECT
DATE_FORMAT(`START_DATE`,'%d-%m-%Y')
AS `START_DATE`
FROM ...
The other option you have is to store your dates in the format that you already want as a char or varchar column.
HOWEVER, as should be obvious, this column will not be treated as storing dates, and so will not give you the correct comparisons in a where clause when using > < BETWEEN or the correct ordering in an order by clause. It is after all just a string of numbers in this case.
However you can then use STR_TO_DATE - link if you did need to use a where or order by on this column to change it back to a date within the query - in this case the second value is the custom format of your 'dates' in the column. Keep in mind with a where you will need to compare it with the correct mysql format as shown below:
SELECT
`START_DATE`
FROM table
WHERE STR_TO_DATE(`START_DATE`,'%d-%m-%Y') BETWEEN '2015-01-01' and '2016-01-01'
In MySQL you can change the format of a date using DATE_FORMAT method which is similar to to_char in Oracle.
DATE_FORMAT(SYSDATE(), '%DD-%MM-%YYYY');
For more information about specifiers check this thread http://www.sqlines.com/oracle-to-mysql/to_char_datetime
You can do what you probably want by creating a view and referring to that instead of the (underlying) table.
CREATE VIEW emp_view AS
SELECT empid,
surname,
sal,
jon,
date_format(start_date, '%d-%m-%Y') as start_date,
date_format(end_date, '%d-%m-%Y') as end_date,
depno
FROM emp;
Note that this changes the type of the date columns to varchar, so comparisons will no longer work as expected:
SELECT * FROM emp_view WHERE start_date > '01-12-1924'; // fails!

Incorrect date comparison results in SQL Server 2008 R2

I have a LINQ 2 SQL query that's getting me a list of results for the month of February 2012. The resulting where clause is
DECLARE #p0 DateTime = '2012-02-01 00:00:00.000'
DECLARE #p1 DateTime = '2012-02-29 23:59:59.999'
....
WHERE (CONVERT(DATE, [t0].[DatePlaced]) >= #p0) AND (CONVERT(DATE, [t0].[DatePlaced]) <= #p1)
When this runs I'm getting results for 3/1/2012 showing up as well as all the results for 2/2012.
If I change the where clause to use BETWEEN then the results only contain dates for February.
WHERE [t0].[DatePlaced] BETWEEN #p0 AND #p1
I'm using .net 4 and SQL Server 2008 R2 with and without SP1.
Switching the dates to 3/1/2011 and my query's end date to '2011-02-28 23:59:59.999' yielded the same results.
Is there another way to get the results for just 2/2012 aside from using BETWEEN which LINQ 2 SQL doesn't support?
.999 rounds up to midnight of the next day. You can check this:
DECLARE #p1 DateTime = '2012-02-29 23:59:59.999';
SELECT #p1;
What do you get?
Instead of trying to figure out the last instant of today (which will be different depending on the data type and precision), what you want instead is an open-ended date range:
DECLARE #p0 DATE = '2012-02-01',
#p1 DATE = '2012-03-01';
....
WHERE [t0].[DatePlaced] >= #p0
AND [t0].[DatePlaced] < #p1
Even easier would be to just pass in the starting date and say:
DECLARE #p0 DATE = '2012-02-01';
....
WHERE [t0].DatePlaced >= #p0
AND [t0].DatePlaced < DATEADD(MONTH, 1, #p0)
For some elaborate ideas about datetime best practices:
Bad habits to kick : mis-handling date / range queries
For some info on why BETWEEN (and by extension >= AND <=) is evil:
What do BETWEEN and the devil have in common?
If you need to select by month often, you could consider adding two computed columns to your table - one for the month, one for the year:
ALTER TABLE dbo.YourTable
ADD DatePlacedYear AS YEAR(DatePlaced) PERSISTED
ALTER TABLE dbo.YourTable
ADD DatePlacedMonth AS MONTH(DatePlaced) PERSISTED
Those two new columns are automatically computed by SQL Server, they're persisted (e.g. part of the table's storage), and you can even put an index on them, if that makes sense for you.
With those in place, you could now use a query like:
SELECT (columns)
FROM dbo.YourTable
WHERE DatePlacedYear = 2012 AND DatePlacedMonth = 2
to get all data from February 2012.
It's a classic space-vs-speed trade-off - by storing the two extra columns for each row, you need more space - but in return, querying gets easier and if you have an index on (DatePlacedYear, DatePlacedMonth), your queries should (ideally) be quite fast.
Instead of using AddMilliseconds(-1) try use AddMilliseconds(-3)
See this question how SQL Server treats the milliseconds

Converting a date string which is before 1970 into a timestamp in MySQL

Not a very good title, so my apologies.
For some reason, (I wasn't the person who did it, i digress) we have a table structure where the field type for a date is varchar. (odd).
We have some dates, such as:
1932-04-01 00:00:00 and 1929-07-04 00:00:00
I need to do a query which will convert these date strings into a unix time stamp, however, in mySQL if you convert a date which is before 1970 it will return 0.
Any ideas?
Thanks so much!
EDIT: Wrong date format. ooops.
Aha! We've found a solution!
The SQL to do it:
SELECT DATEDIFF( STR_TO_DATE('04-07-1988','%d-%m-%Y'),FROM_UNIXTIME(0))*24*3600 -> 583977600
SELECT DATEDIFF( STR_TO_DATE('04-07-1968','%d-%m-%Y'),FROM_UNIXTIME(0))*24*3600 -> -47174400
This could be useful for future reference.
You can test it here: http://www.onlineconversion.com/unix_time.htm
I've adapted the DATEDIFF workaround to also include time not just days. I've wrapped it up into a stored function, but you can just extract the SELECT part out if you don't want to use functions.
DELIMITER |
CREATE FUNCTION SIGNED_UNIX_TIMESTAMP (d DATETIME)
RETURNS BIGINT
DETERMINISTIC
BEGIN
DECLARE tz VARCHAR(100);
DECLARE ts BIGINT;
SET tz = ##time_zone;
SET time_zone = '+00:00';
SELECT DATEDIFF(d, FROM_UNIXTIME(0)) * 86400 +
TIME_TO_SEC(
TIMEDIFF(
d,
DATE_ADD(MAKEDATE(YEAR(d), DAYOFYEAR(d)), INTERVAL 0 HOUR)
)
) INTO ts;
SET time_zone = tz;
return ts;
END|
DELIMITER ;
-- SELECT UNIX_TIMESTAMP('1900-01-02 03:45:00');
-- will return 0
-- SELECT SIGNED_UNIX_TIMESTAMP('1900-01-02 03:45:00');
-- will return -2208888900
convert these date strings into a
unix time stamp
Traditional Unix timestamps are an unsigned integer count of seconds since 1-Jan-1970 therefore can't represent any date before that.
At best you will have mixed results depending on the system you are using to represent the timestamp.
From wikipedia
There was originally some controversy
over whether the Unix time_t should
be signed or unsigned. If unsigned,
its range in the future would be
doubled, postponing the 32-bit
overflow (by 68 years). However, it
would then be incapable of
representing times prior to 1970.
Dennis Ritchie, when asked about this
issue, said that he hadn't thought
very deeply about it, but was of the
opinion that the ability to represent
all times within his lifetime would be
nice. (Ritchie's birth, in 1941, is
around Unix time −893 400 000.) The
consensus is for time_t to be signed,
and this is the usual practice. The
software development platform for
version 6 of the QNX operating system
has an unsigned 32-bit time_t, though
older releases used a signed type.
It appears that MySQL treats timestamps as an unsigned integer, meaning that times before the Epoc will all resolve to 0.
This being the case, you always have the option to implement your own unsigned timestamp type and use that for your calculations.
If its feasible for your problem, you could shift all your mysql times by, say 100 years, and then work with those adjusted timestamps or re calculate the negative timestamp value.
As some have said, make sure your system is using 64bits to represent the timestamp otherwise you'll hit the year 2038 problem.
I have not tried the above solutions but this might in case you are not able to retrieve the date value from the MySQL database in the form of timestamp, then this operation can also be tried
SELECT TIMESTAMPDIFF(second,FROM_UNIXTIME(0),'1960-01-01 00:00:00');
To get the max. Range +/- wise use this query on your birthday field, in my case "yyyy-mm-dd" but you can change it to your needs
select name, (#bday:=STR_TO_DATE(birthday,"%Y-%m-%d")),if(year(#bday)<1970,UNIX_TIMESTAMP(adddate(#bday, interval 68 year))-2145916800,UNIX_TIMESTAMP(#bday)) from people
I feel like we're making this much too difficult...
Use my functions below so you can convert anything to and from unix timestamps, much like you do in a browser.
Call functions like this:
select to_unix_time('1776-07-04 10:02:00'),
from_unix_time(-6106024680000);
By compiling these:
delimiter $$
create function to_unix_time (
p_datetime datetime
) returns bigint
deterministic
begin
declare v_ret bigint;
select round(timestampdiff(
microsecond,
'1970-01-01 00:00:00',
p_datetime
) / 1000, 0)
into v_ret;
return v_ret;
end$$
create function from_unix_time (
p_time bigint
) returns datetime(6)
deterministic
begin
declare v_ret datetime(6);
select '1970-01-01 00:00:00' +
interval (p_time * 1000) microsecond
into v_ret;
return v_ret;
end$$
Use Date instead of timestamps. Date will solve your Problems.
check this link