I have a SQL Server server running on AWS, since yesterday the GETDATE() function has been returning the hour with one more hour as if it were in time zone -02:00. I have already checked on Linux and the date and time is correct and the time zone is set to America/Sao_Paulo.
Executing the following command EXEC MASTER.dbo.xp_regread 'HKEY_LOCAL_MACHINE', 'SYSTEM\CurrentControlSet\Control\TimeZoneInformation', 'TimeZoneKeyName' returns E. South America Standard Time, which in table sys.time_zone_info is with following values:
+-----------------------------+
| CURRENT_UTC_OFFSET | -02:00 |
| IS_CURRENTLY_DST | 1 |
+-----------------------------+
How can I correct this time difference?
As Larnu mentioned, it would appear that the OS hosting your SQL Server has not been updated for Brazil's end to DST.
For Linux, ensure that the tzdata package is current. (This change was made in IANA TZDB 2019b.)
For Windows, ensure that the updates mentioned in this article from Microsoft have been applied.
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
The getDate() statement always returns the same value anywhere in one statement.
However, in one SQL Server 2017, I'm seeing otherwise.
To set this up, create a table and put two rows into it:
CREATE TABLE Test
(
TestDate datetime2(0) NULL,
OtherValue varchar(5) NULL
)
INSERT INTO Test (OtherValue) VALUES ('x')
INSERT INTO Test (OtherValue) VALUES ('x')
Then run this query a number of times:
SELECT
CASE
WHEN GETDATE() < COALESCE(TestDate, GETDATE())
THEN 'less'
WHEN GETDATE() > COALESCE(TestDate, GETDATE())
THEN 'greater'
ELSE 'same'
END [Compare]
FROM
Test
Both rows always return matching results.
When I do this in SQL Server 2008 R2 (v10.50) and other SQL Server 2017 machines, the result is always 'same'.
However, on one of my SQL Server 2017 instances, it varies randomly between 'same', 'less' and 'greater':
Why is this happening? Is there a server setting that can cause this?
Edit:
Using SYSDATETIME in place of GETDATE works as expected on the 'bad' server, always returning 'same'.
Edit #2:
If I test GETDATE as above on a column defined as DATETIME (which is what GETDATE() generates), then it works as expected. So it seems to be related to converting between DATETIME and DATETIME2.
Interesting enough question.
The behaviour in your example can be explaned by the following:
Since SQL Server 2016, datetime rounding have been changed. In short: since 2016 SQL Server, value doesn't round before comparison and comparison executes with raw value. Before 2016 SQL Server, value is rounded and then compare.
By default, comparison datetime and datetime2 performs with conversion datetime to datetime2(7). You can see that in execution plan.
datetime variable with 3 at the end - for example .003 - gets converted in .0033333. 007 gets converted in .0066667.
And the most interest part: nanoseconds. During comparison SQL Server uses 8 (or more!) digits in fractional part. I just show two examples to explane.
DECLARE #DateTime datetime = '2016-01-01T00:00:00.003';
DECLARE #DateTime2 datetime2(7) = #DateTime;
select datepart(NANOSECOND,#DateTime) as "DateTimeRes",
datepart(nanosecond,#DateTime2) as "DateTime2Res"
go
DECLARE #DateTime datetime = '2016-01-01T00:00:00.007';
DECLARE #DateTime2 datetime2(7) = #DateTime;
select datepart(NANOSECOND,#DateTime) as "DateTimeRes",
datepart(nanosecond,#DateTime2) as "DateTime2Res"
Results:
+-------------+--------------+
| DateTimeRes | DateTime2Res |
+-------------+--------------+
| 3333333 | 3333300 |
+-------------+--------------+
+-------------+--------------+
| DateTimeRes | DateTime2Res |
+-------------+--------------+
| 6666666 | 6666670 |
+-------------+--------------+
I took it all from this article.
Also, there is a similar question on SO.
I believe this behaviour is independent of your server repformance (virtual machine or etc).
Good luck!
Turns out the behaviour of getdate changed from SQL 2000 to SQL 2005.
See https://stackoverflow.com/a/3620119/32429 explaining the old behaviour:
In practice, GETDATE() is only evaluated once for each expression
where it is used -- at execution time rather than compile time.
However, Microsoft puts rand() and getdate() into a special category,
called non-deterministic runtime constant functions.
and the following discussion:
In SQL 2000 if you did something like this
INSERT INTO tbl (fields, LOADDATE) SELECT fields, GETDATE() FROM tblb
you would get the same date/time for all records inserted.
This same command In SQL 2005, reruns GETDATE() for every single
record selected from tblb and gives you potentially unique values for
each record. Also causes HUGE performance problems if you are
inserting say, 17 million rows at a time.
This has caused me many a headache, as we use this code to do batch
date/times in many tables. This was a very simple way to back out a
"batch" of transactions, because everything had the same date/time.
Now in 2005, that is not true.
When I get TODAY in SELECT in PB, it returns 1900/1/1
date var
Select TODAY() Into :var From DUMMY
But when I assign to variable TODAY(), it works as expected
date var
var = today()
I use MS SQL Server 2016 and PowerBuilder 12.5.
I've supposed that the problem is in different date formats, but I have changed date format at my Windows locale in the way, that PB TODAY() returns 2018-10-08 and MSSQL GetDate() returns 2018-10-08 18:25:23.207
So date parts have the same formats.
The problem is not in DUMMY table since I have created MS SQL DUMMY table and inserted 1 row in it.
Also I'm wondering if there are any difference in SELECT TODAY() and var = TODAY()?
I suppose that 1st variant returns MS SQL server time but 2nd returns local time. Is not is?
Try below SQL.
Select getdate() into :var From DUMMY;
You provided your own answer: Today() is a PowerScript function, GetDate() is the function on MS SQL. If you’re executing SQL, it needs to be a valid SQL statement for the server you’re executing against (except for the INTO :var part), and can’t include a PowerScript function.
Two other things:
“FROM DUMMY” is an Oracle thing, and I’m pretty sure it won’t work on MS. (You’re capturing your error codes after executing the SQL, right?)
I won’t say this is likely a critical problem, but as you point out, GetDate returns a datetime; I’d recommend that as your data type for the capture variable.
And yes, GetDate() will be your server’s date/time, Today() will be based on the local workstation.
Good luck.
SQL Server 2005
SELECT TOP 10 * FROM abc WHERE aDate = '2014-01-20'
When querying the above in SSMS it would normally return results where aDate is 20 January 2014. However for another user on the same server, it returns a date conversion error and only works when running the following query:
SELECT TOP 10 * FROM abc WHERE aDate = '2014-20-01'
I've checked regional language settings on the local machine and it's exactly the same as mine. Any ideas welcomed.
It is not the regional language settings on the machine that count in this case but the one defined on the database's options.
Anyway, to avoid having to rely on the regional language settings when parsing datetime in queries I would encourage you to use an invariant ISO date format : {d 'yyyy-MM-dd'}. Note there is also one for specifying the hours (ts).
It was account specific, the setting was stored as 'British - English' as opposed to 'English'. Changing this to 'English' resolved the problem. Thank you for your responses.
This error occurred as the SQL server tries parse the date value 20 as month and it causes error as 20 is not a valid month .Always It is good practice to use the date format 'dd-MMM-yyyy' which will work with any type of SQL COLLATION and regional language settings.
Is it possible to get the name of the current time zone, such as "Eastern Standard Time" or "EST" in SQL code on SQL Server 2008 R2 ? I know I can determine numeric local time offset by calculating difference between getdate() and getutcdate(), but that's not what I need. I simply need TZ name from the underlying operating system.
Without any defined table, if you just want to read the time zone information from the System Information, then it can be read from the system registry.
declare #TZName varchar(50)
exec master.dbo.xp_regread 'HKEY_LOCAL_MACHINE',
'SYSTEM\CurrentControlSet\Control\TimeZoneInformation',
'TimeZoneKeyName',#TZName OUT
select #TZName
Raj