I was always under the impression given a datetime data type as 2019-07-06 was always 6th July 2019, regardless of locale and regional settings, ie this is a universal datetime format.
However, I've ran into a situation where I am trying to query some data from our database, and the string 2019-07-06 does not return the expected results. However 2019-06-07 will.
I have always had the understanding that YYYY-MM-DD format was based on ISO-8601.
Given this was on Friday 7th June where I was inserting the data, and today I am querying that data, I see:
Using the query
select
b.ID
, b.UserId
, b.EntryDate
, day(b.EntryDate) as 'day'
, month(b.EntryDate) as 'month'
from [dbo].[SomeTable] b
where b.UserId = 236328
But when I change the query:
select
b.ID
, b.UserId
, b.EntryDate
, day(b.EntryDate) as 'day'
, month(b.EntryDate) as 'month'
from [dbo].[SomeTable] b
where b.UserId = 236328
and b.EntryDate > '2019-06-07'
This does not yield any results. However changing EntryDate > '2019-07-06' will return my data.
NOTE: The query is entered using SSMS v18 on my local machine.
Server Configuration
The current verison of SQL Server is Microsoft SQL Server 2012 (SP4-GDR) (KB4057116) - 11.0.7462.6 (X64) Jan 5 2018 22:11:56 Copyright (c) Microsoft Corporation Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: )
The sql server is configured to use:
|------------------|------------------------------|
| Setting | Value |
|------------------|------------------------------|
| Language | English (United States) |
| Default Language | British English |
| Server Collation | SQL_Latin1_General_CP1_CI_AS |
Database Configuration
The database is configured to use:
|---------------------|-----------------------|
| Setting | Value |
|---------------------|-----------------------|
| Collation | Latin1_General_CI_AS |
| Compatability Level | SQL Server 2012 (110) |
| Default Language | British English |
Question is, what should be the expected behaviour of date time queries with strings with format YYYY-MM-dd? I cannot recall this behaviour I am seeing in the last 20 years.
Update
For the record, if I enter the datetime in the query as 2019-06-07T00:00:00 then this DOES return the expected data.
With the DATETIME type, the literal 2019-06-07 could be 7th June, or 6th July, depending on the current DATEFORMAT settings:
SET DATEFORMAT DMY;
SELECT FORMAT(CONVERT(DATETIME, '2019-06-07'), 'dd MMM yy');
--Returns "06 Jul 19"
SET DATEFORMAT MDY;
SELECT FORMAT(CONVERT(DATETIME, '2019-06-07'), 'dd MMM yy');
-- Returns "07 Jun 19"
You should not rely on your default server settings for this, the best way to avoid this ambiguity is to use the format yyyyMMdd, this is always interpreted the same way regardless of settings:
SET DATEFORMAT DMY;
SELECT FORMAT(CONVERT(DATETIME, '20190607'), 'dd MMM yy');
--Returns "07 Jun 19"
SET DATEFORMAT MDY;
SELECT FORMAT(CONVERT(DATETIME, '20190607'), 'dd MMM yy');
-- Returns "07 Jun 19"
Alternatively, do an explicit conversion, and use the style parameter to ensure consistent conversion:
SET DATEFORMAT DMY;
SELECT FORMAT(CONVERT(DATETIME, '2019-06-07', 101), 'dd MMM yy');
-- Returns "07 Jun 19"
SET DATEFORMAT MDY;
SELECT FORMAT(CONVERT(DATETIME, '2019-06-07', 101), 'dd MMM yy');
-- Returns "07 Jun 19"
As an aside there is no ambiguity with this format when working with DATE or DATETIME2, but this ambiguity has always existed for DATETIME and SMALLDATETIME. Aaron Bertrand blogged about this in his Bad habits to kick series: mis-handling date / range queries
Related
My database has this table
| Name | Score | Date_time |
---------------------------------
| A | 100 | 20200601000000 |
| B | 120 | 20200615000000 |
| C | 110 | 20200629000000 |
| B | 150 | 20200701000000 |
...
I want get 'Name' and 'Score' by 'Date_time' week day.
Example, when week day is Monday(= 2), I get two data.
| A | 100 |
| B | 120 |
And I tried to use the following sql statement.
select Name, Score
from SCORE_DATA
where
datepart(dw, format(cast(Date_time as bigint),'####-##-## ##:##:##')) = 2
converting
20200601000000 to 2020-06-01 00:00:00 and get week day (dw) and compare is it 2.
But I get an error:
'format' is not a recognized built-in function name.
I can't understand why.
https://learn.microsoft.com/en-us/sql/t-sql/functions/format-transact-sql?view=sql-server-ver15&viewFallbackFrom=sql-server-2014
It explain format function.
Doesn't it apply in SQL Server 2014? What can I do?
Technically, Gabriele's answer is correct - He is explaining why you're getting the error message you're getting.
However, there is a better way to get your results, that doesn't involve Format.
First thing's first: You should seriously consider converting the [Date_Time] column you have now from (What I guess based on the code in the question is) a string to a proper DateTime.
That will solve not only this specific problem but a bunch of many other problems, some of them you probably have encountered before.
Even if this involves a lot of work it will be worth it in the long run, trust me.
However, considering that's not an option, I would suggest a couple of improvements to your existing code:
Use cast to convert the first 8 chars directly to a date, instead of converting the entire thing to a bigint and then using format and implicit conversion like your code is attempting to do now.
Use WeekDay instead of dw in the DatePart function. It's just more readable.
Calculate the week day number based on the ##DateFirst value - because SQL Server does exactly that, meaning if someone changes the date first settings your current code will produce the wrong results.
Having said all that, let's see how that looks like in code.
First, create and populate sample table (Please save us this step in your future questions):
CREATE TABLE SCORE_DATA (
[Name] varchar(1),
[Score] int,
[Date_time] char(14)
);
INSERT INTO SCORE_DATA ([Name], [Score], [Date_time]) VALUES
('A', 100, '20200601000000'),
('B', 120, '20200615000000'),
('C', 110, '20200629000000'),
('B', 150, '20200701000000');
The query (with explanatory comments):
SELECT [Name]
, [Score]
FROM SCORE_DATA
-- using full name for readability
WHERE (DATEPART(WeekDay,
-- ISO8601 format is unambiguous and will always be converted correctly
CAST(
-- A string representation of date in ISO8601 Format: yyyyMMdd
LEFT([Date_Time], 8)
AS Date) -- You don't need DateTime, just the date...
-- taking datefirst settings into consideration to get a fixed number
) + ##DATEFIRST) % 7 = 2
Results:
Name Score
A 100
B 120
C 110 -- June 29th 2020 was a Monday too...
You should check your compatibility level as below:
SELECT compatibility_level
FROM sys.databases
WHERE name = 'YourDb';
GO
110 is SQL Server 2012
120 is SQL Server 2014
130 is SQL Server 2016
140 is SQL Server 2017
150 is SQL Server 2019
To change it you can use the following script:
ALTER DATABASE YourDb
SET COMPATIBILITY_LEVEL = 120;
GO
FORMAT function require compatibility level >= 110
When I extract a timestamp column from SQL Server, it comes across like this:
Thu Jan 26 2017 19:00:00 GMT-0500 (Eastern Standard Time)
I need to get it into an acceptable Redshift format. For example:
2017-01-26 19:00:00
How do I do this kind of conversion?
For a timestamp column X, use the FORMAT() function while converting to DATETIME to return a VARCHAR value:
SELECT FORMAT(CAST(X AS DATETIME), 'yyyy-MM-dd HH:MM:ss')
Or, you can also use CONVERT() to return a DATETIME value:
SELECT CONVERT(DATETIME, X, 120)
I need a SQL server query to convert date to Mon DD, YYYY HH:MM:SS AM/PM
for e.g. the date is :-
2016-11-21 16:58:57.797
I need the SQL output as
Nov 21 2016 4:58:57 PM
I tried --> CONVERT(VARCHAR(19),GETDATE(),109)
but it is displaying results like --> Nov 21 2016 4:58:5
Increase the length of VARCHAR in your statement like below
select CONVERT(VARCHAR(30),GETDATE(),109)
This is giving me result as Nov 21 2016 12:55:31:390PM
Hope this should work out for you.
For mysql you can do this:
SELECT DATE_FORMAT(NOW(),'%b %d %Y %h:%i %p');
For ms sql you can do this:
SELECT CONVERT(VARCHAR(19),GETDATE())
Reference:
MySQL DATE_FORMAT() Function
SQL Server CONVERT() Function
Use SUBSTRING and CHARINDEX to get the left part of the string excluding the milliseconds part. Then concatenate the last AM/PM with that.
Query
declare #date as varchar(30) = convert(varchar(30),getdate(),109);
select substring(#date, 1, len(#date) - charindex(':', reverse(#date), 1))
+ ' ' + right(#date, 2) as [datetime];
you can use this
select FORMAT(CAST(GETDATE() AS DATETIME),'MMM dd yyyy hh:mm:ss tt') AS DateTimeAMPM
I have a requirement of converting a record of time w.r.to timezone and compare it with current time.
For this, I want to convert datetime of a timezone to GMT timezone in SQL server.
i.e. (Jan 12 2015 11:30 A.M +5:30--->GMT standard time
Also is it possible to find out client's time zone from sql server?
If your datetime is stored as a datetimeoffset (or convertible to it) you can simply convert to a datetime2 (assuming you want to keep the precision of the datetimeoffset):
declare #dt datetimeoffset
select #dt = 'Jan 12 2015 11:30 AM +05:30'
select convert(datetime2, #dt, 1)
Which returns the time in UTC:
2015-01-12 06:00:00.0000000
This has nothing to do with the users' timezone, as it is simply doing the timezone to UTC calculation based on your provided offset.
SqlFiddle
I am retrieving date and time using this:
SELECT convert(varchar, getdate())
and it shows me output as:
Jul 3 2012 9:34PM
but client want that there should be space between time and AM/PM, means output should be like this:
Jul 3 2012 9:34 PM
Thanks in advance.
For one, don't use varchar without length. And you can use STUFF here, e.g.
SELECT STUFF(CONVERT(VARCHAR(19), GETDATE()), 18, 0, ' ');
Results:
Jul 3 2012 12:48 PM
Note that this can look different depending on language and regional settings.
In SQL Server 2012 this is a little more intuitive, however the extra space between month and day when the day is < 10 is tricky to work around (or my understanding of .NET's format is lacking):
SELECT FORMAT(GETDATE(), 'MMM d yyyy hh:mm tt');