How do I stop SQL Server swapping the month and day? - sql

I have the following query:
DECLARE #someDateTime DATETIME = '2019-12-01 00:00:00.000'; -- 1st December 2019
SELECT #someDateTime;
Result
2019-01-12 00:00:00.000
I expected the result to be 2019-12-01 00:00:00.000 (1st December 2019) - The month and the date swap for some unknown reason.
Until recently, I never had an issue with this format.
How do I enter the date in the format "YYYY-MM-DD HH:mm:ss.000", and have it maintain that format once assigned to a variable/displayed in a select?
What setting determines this format that may have changed?
Potentialy useful information
dbcc useroptions
Result:
Set Option | Value
---------- -----
...
language | British
dateformat | dmy
...
Things I tried:
Query 1
Chaning the date to something that would be invalid if swapped
DECLARE #someDateTime DATETIME = '2019-12-20 00:00:00.000';
SELECT #someDateTime;
Result:
Msg 242, Level 16, State 3, Line 4
The conversion of a varchar data type to a datetime data type resulted in an out-of-range value.
Query 2
Setting the variable after it's been declared
DECLARE #someDateTime DATETIME;
SET #someDateTime = '2019-12-01 00:00:00.000';
SELECT #someDateTime;
Result - UNDESIRED:
2019-01-12 00:00:00.000
Query 3
Inserting the variable into a table variable
DECLARE #someDateTime DATETIME = '2019-12-01 00:00:00.000';
DECLARE #someTable TABLE (someDateTimeColumn DATETIME);
INSERT #someTable VALUES (#someDateTime);
SELECT * FROM #someTable
Result - UNDESIRED:
someDateTimeColumn
------------------
2019-01-12 00:00:00.000
Query 4
Inserting the data directly into a table variable
DECLARE #someTable TABLE (someDateTimeColumn DATETIME);
INSERT #someTable VALUES ('2019-12-01 00:00:00.000');
SELECT * FROM #someTable
Result: UNDESIRED
someDateTimeColumn
------------------
2019-01-12 00:00:00.000
Query 5
Changing the format of the entered string
DECLARE #someDateTime DATETIME = '01/12/2019';
SELECT #someDateTime;
Result - DESIRED
2019-12-01 00:00:00.000
Query 6
Changing the format of the entered string
DECLARE #someDateTime DATETIME = '2019-12-01T00:00:00.00';
SELECT #someDateTime;
Result - DESIRED:
2019-12-01 00:00:00.000
Query 7
Changing the format of the entered string
DECLARE #someDateTime DATETIME = '2019-12-01';
SELECT #someDateTime;
Result - UNDESIRED:
2019-01-12 00:00:00.000
Query 8
Using SET DATEFORMAT
SET DATEFORMAT ymd
DECLARE #someDateTime DATETIME = '2019-12-01';
SELECT #someDateTime;
Result - DESIRED
2019-12-01 00:00:00.000

You may use the literal format YYYYMMDD which is always intepreted as year-month-day, regardless of the locale settings of your SQL Server:
DECLARE #someDateTime DATETIME = '20191201 00:00:00.000';

One solution is to use the full ISO8601 format, ie 2019-12-01T00:00:00.000, another to use the unseparated date format, ie 20191201 00:00:00.000. A better solution though would be to switch to datetime2.
datetime2 was introduced 15 (or was it 11) years ago to get rid of datetime's quirks, like the millisecond inaccuracy, arbitrary precision, weird arithmetic and ... parsing idiosyncrasies. For example, datetime2's parsing of the ISO8601 format isn't affected by DATEFORMAT :
SET DATEFORMAT ydm
DECLARE #someDateTime DATETIME2(0) = '2019-12-01 00:00:00.000'
select #someDateTime
------
2019-12-01 00:00:00
This secures your code from unfortunate server setting modifications

After reading this article from #SMor's comment, a comment my colleague made from a google search, and remembering something I did a few months ago, I think I've worked out what's happening and what's changed.
My db user was, by default, set to:
language | us_english
dateformat | mdy
So when reading the string '2019-12-01' SQL Server was expecting mm-dd-yyyy.
SQL server is clever though. It sees the first part 2019 and realises that it's actually the year, so it shifts the year to the end, then tries again.*
It now has 12-01-2019 which matches the format it's expecting.
When you open your account properties in SSMS, the language drop down defaults to the first language in the list (Arabic).
I happend to be in there a few months ago for something unrelated and decided, to make sure I didn't accidently set it to Arabic, I'd change that as well.
I chose British.
My db user is now set to:
language | British
dateformat | dmy
So when reading the string '2019-12-01' SQL Server is expecting dd-mm-yyyy.
Once it's shifted the year, it becomes 12-01-2019 which it interprets as dd-mm-yyyy thus leaving me with January 12th 2019 instead of December 1st 2019
Today has been a long day.
*Please note this is a rather simplified explanation of how I understand this issue. This may not be how it actually functions in reality but works to satisfy my curiosity on this issue.

Related

Compare 2 dates with diff datatypes

I have a temp_table where I have to update status to Invalid date if Create_date is a future date.
Following is the update statement I am using :
Set dateformat dmy
UPDATE [Temp_table]
SET [Status]= 'InvalidCreateDate-Rejected'
WHERE CAST(Create_date AS DATETIME) >=getdate() and isdate(create_date)=1
But whenever I execute it I get error message as:
Msg 242, Level 16, State 3, Line 1 The conversion of a varchar data
type to a datetime data type resulted in an out-of-range value. The
statement has been terminated.
I tried converting Getdate and Create_date in diff formats and then compared still the same issue.
Sample Create_Dates:
05/15/1800
04/06/2011
23/04/2015
13/08/2016
02/21/2017
15/06/2017
Any solution on this?
your cast of create_date is coming across an invalid date and causing the error. the is_date function is a good idea, but it isn't going to prevent the cast from hitting an error earlier.
Set dateformat dmy
UPDATE [Temp_table]
SET [Status]= 'InvalidCreateDate-Rejected'
WHERE CAST(case when isdate(create_date)=1 then Create_date else null AS DATETIME) >=getdate()
You can use a date purposefully in the past instead of the null if the null causes issues, but casting a null to date and comparing it to a date should result in a false and have it removed from results
However, you could use case expression which could handle your different date formats
SELECT CONVERT(DATETIME, Create_Dates,
CASE
WHEN CAST(SUBSTRING(Create_Dates, 4, 2) AS INT) > 12
THEN 101
ELSE 103
END);
Result :-
1800-05-15 00:00:00.000
2011-06-04 00:00:00.000
2015-04-23 00:00:00.000
2016-08-13 00:00:00.000
2017-02-21 00:00:00.000
2017-06-15 00:00:00.000

SQL Server 2014 insert/update smalldatetime value with seconds

I'm having a strange issue with the smalldatetime data type in SQL Server.
I have a very basic table
create table datetest (
value smalldatetime not null
)
And when I run the following
insert into datetest
values ('2016-12-29 21:30:00');
I see the value is 2016-12-29 21:30:00
Then when I run the following
update datetest
set value = '2016-12-29 21:31:30'
I see the value is 2016-12-29 21:31:00
It did not include the seconds. Why is this?
This is happening because precision of smalldatetime is 1 minute. It discards any seconds in datetime value by rounding off. For e.g:
'2014-10-10 12:13:29' is rounded off to '2014-10-10 12:13:00' and '2014-10-10 12:13:30' is rounded off to '2014-10-10 12:14:00'
This is one of the characteristics of smalldatetime over datetime.
Microsoft documentation on smalldatetime
The main differentation is that it rounds to the nearest minute. If you want to see seconds (and milliseconds) then you need to consider the datetime data type.
In your example however, it should return the value 2016-12-29 21:32:00 because it rounds up from 30 seconds to the next minute. anything less than 30 seconds gets rounded down. Example;
CREATE TABLE #DateTest (ID int, DateValue smalldatetime)
INSERT INTO #DateTest (ID, DateValue)
VALUES
(1,'2016-12-29 21:31:29')
,(2,'2016-12-29 21:31:30')
SELECT * FROM #DateTest
Output
ID DateValue
1 2016-12-29 21:31:00
2 2016-12-29 21:32:00
Some further reading links;
http://blog.sqlauthority.com/2010/06/01/sql-server-precision-of-smalldatetime-a-1-minute-precision/
http://sqlcoach.blogspot.co.uk/2007/08/sql-server-storing-time-coming-soon.html
http://sqlhints.com/2016/10/10/difference-between-smalldatetime-and-datetime-data-types-in-sql-server/
When the conversion is to datetime, the smalldatetime value is copied to the datetime value. The fractional seconds will make next nearest minutes. The following code shows the results of converting a smalldatetime value to a datetime value.
DECLARE #smalldatetime smalldatetime = '1955-12-13 12:43:10';
DECLARE #datetime datetime = #smalldatetime;
SELECT #smalldatetime AS '#smalldatetime', #datetime AS 'datetime';
--Result
--#smalldatetime datetime
------------------------- -----------------------
--1955-12-13 12:43:00 1955-12-13 12:43:00.000
Take a look MSDN Link
It rounds all seconds to minutes:
Time range:
00:00:00 through 23:59:59
2007-05-09 23:59:59 will round to
2007-05-10 00:00:00
see chapter smalldatetime Description: https://msdn.microsoft.com/en-us/library/ms182418(v=sql.120).aspx

convert to Date format in MM/YY?

I am converting date into MM/YY, but it is converted to varchar. How to change that back to datetime datatype?
select RIGHT(CONVERT(VARCHAR(8), e.[Start_Date], 3), 5) AS 'Month/Year'
from table1
I am converting date into MM/YY, but it is converted to varchar. How to change that back to datetime datatype?
does this mean you are updating back same field with varchar value.How this is possible ?
where is date field lost ?
Declare #i datetime =getdate()
select stuff(convert(varchar(10),#i,103),1,3,'')
My understanding is that you have a value like "01/13" (Jan 2013) and you want to produce a DATETIME from it.
DECLARE #mmyy VARCHAR(5) = '01/13';
SELECT CAST('20'+RIGHT(#mmyy, 2)+'-'+LEFT(#mmyy, 2)+'-01' AS DATETIME)
-- returns 2013-01-01 00:00:00.000
Of course since your year is 2 digit I have to make the assumption that it's in the 21st century.

Query: Assigning error datetime2

I want to assign '1392-04-31' using this code:
DECLARE #t DATETIME
SET #t = '92-04-31'
I see this error:
Conversion failed when converting date and/or time from character string.
Any one know why?
The solution is:
use datetime2!
DECLARE #t datetime2
SET #t = '1392-04-30'
Because you can't use datetime:
The minimum date stored in datetime is January 1, 1753. So 1392 is not storeable.
April has 30 days.
Using formatted date with datetime:
Second, when you write a date in Sql Server, the format I prefer is {d 'YYYY-MM-DD'}, so in your case becomes:
DECLARE #t DATETIME
SET #t = {d '1992-04-30'}
To complete this discussion, if you want use hh mm ss so you must use this format: {ts 'yyy-mm-dd hh:mm:ss.mmm'}
DECLARE #t DATETIME
SET #t = {ts '1992-04-30 23:59:59.123'}
try this :
declare #t DATETIME
set #t = '1992-04-30 10:54:30'
The date you are trying to set is probably invalid.
Also there are several ways of representing dates in SQL as a string, depending on Language, Dateformat and other setting. Typically the safest way to do this is to use the 'YYYYMMDD' format.
The article below will also answer the question : Why is 1753 the earliest date for datetime?
You should read this if you would like some detailed information:
http://karaszi.com/the-ultimate-guide-to-the-datetime-datatypes
First of all, April only has 30 days. I'm not going to take the time to look up historically whether that was the case in 1392, but either way I'm pretty sure the date 4/31/1392 is invalid for a SQL Server DATETIME.
Also, you should use the full year in the format '01-01-2013'.
Try the following and you'll get the output Jan 1 2013 12:00AM.
declare #t DATETIME
set #t = '01-01-2013'
PRINT #t
The above should work for any valid date.

Sql Convert Text Field To Date Field

I'm importing an access database to sql.
The original access database has a date field that imports nicely, but the time field is text (10:00 AM, for instance).
I have over 4000 records and assume there is a way to convert 10:00 AM to 10:00:00.000 (or 07:30 PM to 19:30:00.000, etc...) so that it can be combined with the pre-existing date field (which is now like 2011-11-11 00:00:00.000).
Also, if it's easy to do the conversion and concatenation in the same process, please note.
to convert the time from am or pm 10:00 PM format into time format 10:00:00.000:
select cast(timestring as time(7))
look this:
declare #timeField as varchar(10)
set #timeField = '07:30 PM'
declare #dateField as varchar(10)
set #dateField = '1900-01-01'
select CONVERT(datetime,#dateField + ' ' + CAST(CONVERT(time, #timeField ,121) AS VARCHAR(11)),121)
In your import scripts (I assume you use some sort of SQL to E.T.L your data from Access to SQL server), you can use the convert function as such:
declare #t as time = Convert(time, '10:00PM' )
print #t -- prints 22:00:00.0000000
OR
declare #t as time = Convert(time, '10:00AM' )
print #t -- prints 10:00:00.0000000
And of course if you want to control the precision as per your example:
Convert(time(3), '10:00PM' ) -- prints 22:00:00.000