Sql Server: culture changed once i moved to another server. c# .NET - c#

Recently I decided to move to another server. Now my application runs on different servers with different culture (IT and EN).
Everything worked fine but now i am facing many problems with date and numbers.
The main problem seems to be SQL Server. In fact, SQL SERVER throws errors.
I solved the problem with date using the method ParseExact:
e.Command.Parameters["#Expiry"].Value =
DateTime.ParseExact("31/12/2099", "dd/MM/yyyy", null);
For decimal numbers i have to swap "." and "," (depending of the culture) if i want the application to work:
Latitude.Value = Latitude.Value.Replace(".", ","); //ONLY for ITALIAN CULTURE
e.Command.Parameters["#Latitude"].Value = Latitude.Value;
I repeat: the errors are generated by SqlServer.
Is there any way to set the culture once for all?
PS: the EN server is GoDaddy Hosting.
UPDATE:
The problem is pure Sql Server.
In fact, checking on my servers, I found a ',' on the first one and a '.' on the second one as separators for money and decimals.I found:
ALTER LOGIN 'MYDBLOGIN' WITH DEFAULT_LANGUAGE = Italian; GO
With the previous query i was able to change the culture on sql server. However, the problem is still there.

What does this return?
select ##LANGID, ##LANGUAGE
If it says Italian,
set language us_english
(or whatever...)

Rather than every time changing the SQL server culture why don't you use
Convert.ToDecimal(Latitude, CultureInfo.InvariantCulture);

DateTime myDate;
DateTime.TryParse(yourdate, new CultureInfo("en-US"), DateTimeStyles.None, out myDate);
Or
DateTime datet1=new DateTime(2012,5,1);
string startdate = datet1.ToString("d", DateTimeFormatInfo.InvariantInfo);
You can change your database Collate:
ALTER DATABASE test2 -- put your database name here
COLLATE Latin1_General_CS_AS -- replace with whatever collation you need
Your problem is not of sqlserver, you make you modifed in your code while inserting/fetching datetime according to the CultureInfo

Related

Sql server 2008 forcing date from dd/MM/yyyy to MM/dd/yyyy

I have a weird problem with sql server 2008. I am trying to save date with dd/MM/yyyy format into sql server 2008, But after inserting date it automatically get converted into MM/dd/yyyy.
Note : my computer clock format is dd/MM/yyyy
My report viewer date text box properties
enter image description here
Date from my database table
enter image description here
my c# code
lbldate.Text = DateTime.Today.ToShortDateString();
date on report
05/04/2017
SQL Server is the Data Layer and as such there is no formatting available; it stores a date as a 4 byte number which is relative to days with 0 = 01/01/1900.
The Application Layer DateTime type is generally an ODBC Canonical representation which basically looks like a class with integer properties for each component (year, month, date, hours, minutes, seconds, milliseconds).
The Presentation Layer is what you actually see, and that is where you should be concerned. When your application calls the ToShortDateString() method, it is calling the display format from the threads current culture, which may or may not reflect the systems settings for Region & Language or Date & Time.
Solution number one is to set the threads current culture, but this would just go to that particular cultures standard display
Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
Solution number 2 is to just use a custom DateTime format string
lbldate.Text = DateTime.Today.ToString("dd/MM/yyyy");
I would not say this is a "problem" so to speak. This is how SQL handles dates. Your computer clock format is not relevant. To change the format, use CONVERT in your queries. Ex:
SELECT CONVERT(varchar, GETDATE(), 103)
Results: 04/05/2017
SELECT CONVERT(varchar, GETDATE(), 101)
Results: 05/04/2017
The codepage arguments are listed here: https://learn.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql
edit per your new update: Your C# should look something like this:
DateTime.Now.ToString("dd/mm/yyyy")
What you're seeing is how the query tool presents results and has nothing to do with how Sql Server stored the data. Sql Server actually stores dates in a binary (not readable) format.
This is a good thing. Let Sql Server store dates (and other data) how it wants. You only need to worry about how you show the data to users after you retrieve it, and most of the time the best place to worry about that formatting isn't even in the server at all, but in your client language.

What dictates the datetime format of DB when ADO.Net runs query?

I have a simple test query run against a SQL Server database.
SELECT IsDate('1' + '/' + '25' + '/' + '1993')
When I run it against a database with
set dateformat dmy
It correctly returns 0
When I run it against a database with
set dateformat mdy
It correctly returns 1
Now the problem is when I'm running this query from a SqlCommand object in .Net I don't get the result I expect.
The rub is that I'm setting my thread's culture info and datetime format to d/m/y. Even when my thread is running in a d/m/y format AND my database is set to d/m/y I still get 1 back from my query when run from SqlCommand.
Sample code: (note: QuickQuery is just a wrapper method which runs a SqlCommand against my selected database)
string query = $" SELECT IsDate('1' + '/' + '25' + '/' + '1993')";
var dt = QuickQuery(query);
return $"{dt.Rows[0][0]}" + $" {new DateTime(1993, 1, 25)}";
The output of this = "1 25/01/1993 00:00:00"
What is determining that the SqlCommand is running in a context of m/d/y when my actual database and current thread are set to d/m/y?
I have confirmed my database setting with
DBCC USEROPTIONS
Edit 1:
Just a quick note - I appreciate the input about doing things a better way, that is valuable. For this particular case I don't get to pick the context of the problem sadly, I just get to fix it. I have a varchar column for each value month, day, and year. They can be null, or text. From that I have to create date time comparisons with actual datetime columns with the ability to work with any datetime format on the server and on the running thread!
Essentially: avoid the problem completely. Never talk about dates as strings. Use parameters, which are well defined and typed.
Essentially (switching to Dapper syntax, since it supports parameters):
DateTime date = ...
var dt = connection.QuerySingle<DateTime>("select #date + 2", new {date});
The same goes for other data - you get similar issues with numbers and decimal separators and group separators, and the way to get it right is not to learn the format that SQL Server wants: it is to not use strings, but to pass parameterized values. It'll also make it harder to accidentally fall into SQL Injection vulnerabilities.

C# Program want to select data <= 23:59:59 but ends up selecting data with 00:00:00 timestamp as well

this is my first question so pardon any mistakes that might occurs :)
I made a C# program that collects data from SQL Server Database using Datatables, and then export the results to Excel spreadsheets using Interop.
The program itself runs well and doing as it should; however, I found some bugs when it tries to select data with Date columns less than or equal to i.e. 2014-05-31 23:59:59.
Supposed I tried to get all data up to May 1st 2014.
My code first initiates the "Start Date" parameter for the SQL Command later used like this:
var firstDay = new DateTime(today.Year, today.Month, 1); //2014-05-01 00:00:00`
based on firstDay, it initiates the date for the parameter
var periodTo = firstDay.AddSeconds(-1);`
I debugged and got the time I wanted: 2014-04-30 23:59:59
After adding some more parameters for the data criteria, it executes the method to run the query using the parameters supplied.
queryResult = medicore.GenerateRegister(ConfigurationManager.AppSettings["queryDir"], ConfigurationManager.AppSettings["queryName"]);`
The periodTo parameter will be mapped to #EDate variable in the SQL Script. #EDate is declared as Datetime. The #Edate comes into play here:
Select columns
From tables
Where Voucher.Date <= #EDate
which I suppose, the script will be looks like Where Voucher.Date <= '2014-04-30 23:59:59'
The problem is, the result in the Excel file generated also consists of data from '2014-05-01', which is not supposed to be there...at least based on the criteria I set.
Is there some kind of rounding happened between C# and SQL Server?
Thanks!
The reason for this is probably that Voucher.Date is a SMALLDATETIME, therefore you are implicitly converting '2014-04-30 23:59:59' to a SMALLDATETIME:
SET DATEFORMAT MDY;
SELECT CONVERT(SMALLDATETIME, '2014-04-30 23:59:59')
Which gives '2014-05-01'.
Why not just use the Less than operator, instead of less than or equal to?
SET DATEFORMAT MDY;
SELECT ...
WHERE Voucher.Date < '2014-05-01';
N.B I have explcilty stated the DATEFORMAT because yyyy-MM-dd (despite being an ISO standard) is not culture invariant for the DATETIME and SMALLDATETIME data types in SQL Server, and if (like me) you are in a country where the default date format is DMY then SELECT CONVERT(SMALLDATETIME, '2014-04-30') will give you a conversion error. yyyyMMdd is the only culture invariant date format for these two types.
An excellent, and very relevant article to read is Aaron Bertrand's Bad habits to kick : mis-handling date / range queries

Change the date format in SQL Server 2012

I have a SQL Server 2012 Express database that has been installed on a server in Germany. I created a database and have now realised the date formats are incorrect. I need to show each date as dd/mm/yyyy.
When I run dbcc useroptions (after making some changes to the server), I get the following -
language dateformat
-------------------------
British dmy
When I run select GetDate() in a new query, it shows the date as follows -
2014-08-28 13:53:10.550
The bottom line issue is when I enter 28/08/2014 in to a textbox on a web forms project, it errors
String was not recognized as a valid DateTime.
selP.StartDate = Convert.ToDateTime(tbStartDate.Text);
Any ideas why this is happening? I have created a new user since changing the settings to British and dmy, which still produces the same error.
SQL Server doesn't store a DateTime in any string format - it's stored as an 8 byte numerical value.
The various settings (language, date format) only influence how the DateTime is shown to you in SQL Server Management Studio - or how it is parsed when you attempt to convert a string to a DateTime.
There are many formats supported by SQL Server - see the MSDN Books Online on CAST and CONVERT. Most of those formats are dependent on what settings you have - therefore, these settings might work some times - and sometimes not.
The way to solve this is to use the (slightly adapted) ISO-8601 date format that is supported by SQL Server - this format works always - regardless of your SQL Server language and dateformat settings.
The ISO-8601 format is supported by SQL Server comes in two flavors:
YYYYMMDD for just dates (no time portion); note here: no dashes!, that's very important! YYYY-MM-DD is NOT independent of the dateformat settings in your SQL Server and will NOT work in all situations!
or:
YYYY-MM-DDTHH:MM:SS for dates and times - note here: this format has dashes (but they can be omitted), and a fixed T as delimiter between the date and time portion of your DATETIME.
This is valid for SQL Server 2000 and newer.
If you use SQL Server 2008 or newer and the DATE datatype (only DATE - not DATETIME!), then you can indeed also use the YYYY-MM-DD format and that will work, too, with any settings in your SQL Server.
Don't ask me why this whole topic is so tricky and somewhat confusing - that's just the way it is. But with the YYYYMMDD format, you should be fine for any version of SQL Server and for any language and dateformat setting in your SQL Server.
The recommendation for SQL Server 2008 and newer is to use DATE if you only need the date portion, and DATETIME2(n) when you need both date and time. You should try to start phasing out the DATETIME datatype if ever possible
The proper way to achieve that is to set the culture of your web application.
How to: Set the Culture and UI Culture for ASP.NET Web Page Globalization
IN SQL, you need to cast that string as a DATETIME before inserting or updating the database.
CAST('28/08/2014' AS DATETIME)
You can change the format a date is displayed in using the CONVERT. For example, the following will display the date in UK short format (dd/mm/yyyy)
SELECT CONVERT(varchar(50), GetDate(), 103)
If you are doing this in C#, you need to detect the local culture and cast the string to a datetime as approporate.
//You can set the culture on the current thread:
Thread.CurrentThread.CurrentCulture = CultureInfo.InstalledUICulture; // or new CultureInfo("en-GB"); //dd/MM/yyyy
//or you can pass it to the DateTime.Parse method. Something like this:
DateTime startDate = DateTime.Parse(tbStartDate.Text, CultureInfo.InstalledUICulture);
DateTime startDate = DateTime.ParseExact(tbStartDate.Text,"dd/MM/yyyy",System.Globalization.CultureInfo.CurrentUICulture.DateTimeFormat)
Actually the GETDATE() function returns the system date and time in the format 'yyyy-mm-dd hh:mi:ss.mmm' irrespective of the Dateformat.Date format for SQL server is in U.S. date format MM/DD/YY, unless a localized version of SQL Server is installed which seems to be the case here.
Use
SET DATEFORMAT <format>
which sets the order of the date parts (month/day/year) for entering datetime or smalldatetime data. Valid parameters include mdy, dmy, ymd, ydm, myd, and dym. The U.S. English default is mdy.
This method allows you use a date format for dates sent to SQL Server of d/m/y, but it is connection dependent. If a new connection is made to SQL Server or if the server is stopped and restarted, the date format will go back to dmy which is default in your case.
selP.StartDate=tbStartDate.Text.ToString("dd/MM/yyyy")
SELECT CONVERT(varchar(50), GetDate(), 103)
SELECT CONVERT(varchar(50), JoiningDate, 103)from Employee where EmpId='1001'

DateTime and culture

SQL:
select *
from tvideoconference
where del = 'false'
and iduserpatient = 0 and startdate >= N'18.02.2013 20:37:07'
order by startdate
Error:
The conversion of a nvarchar data type to a datetime data type resulted in an out-of-range value.
I got this error, when I tried to use method below in de-DE session culture. What is more, in pl-PL and en-US culture, this methods works perfect.
public static DataSet getSpecialistConfs(int iduserspecialist)
{
DateTime? today = DateTime.Now;
today = today.Value.AddHours(-today.Value.Hour).AddMinutes(-(today.Value.Minute + 1));
string sql = "select * from tvideoconference where del='false' and startdate >=N'" + today.Value + "' and iduserspecialist=" + iduserspecialist;
sql += " order by startdate ";
return Tools.SQLTools.getDataSet(sql);
}
How can I resolve it? I tried with many solutions (substrings, date format), with the same effect..
How can I resolve it?
Use parameterized SQL in the first place. Don't include the values in your query itself; use parameters and set the values of those parameters.
It's unclear what Tools.SqlTools is, but you really, really should use parameterized SQL. That way you won't be converting the DateTime value into a string to start with, so cultures and formatting can't get in the way. Additionally, you won't be vulnerable to SQL injection attacks...
(Additionally, it's not at all clear why you're using DateTime? instead of DateTime - it's not like DateTime.Now can be null... and you should consider using DateTime.Today instead... or DateTime.UtcNow.Date.)
The various settings (language, date format) only influence how the DateTime is shown to you in SQL Server Management Studio - or how it is parsed when you attempt to convert a string to a DateTime.
There are many formats supported by SQL Server - see the MSDN Books Online on CAST and CONVERT. Most of those formats are dependent on what settings you have - therefore, these settings might work some times - and sometimes not.
The way to solve this is to use the (slightly adapted) ISO-8601 date format that is supported by SQL Server - this format works always - regardless of your SQL Server language and date format settings.
The ISO-8601 format is supported by SQL Server comes in two flavors:
YYYYMMDD for just dates (no time portion); note here: no dashes!, that's very important! YYYY-MM-DD is NOT independent of the dateformat settings in your SQL Server and will NOT work in all situations!
or:
YYYY-MM-DDTHH:MM:SS for dates and times - note here: this format has dashes (but they can be omitted), and a fixed T as delimiter between the date and time portion of your DATETIME.
This is valid for SQL Server 2000 and newer.
If you use SQL Server 2008 or newer and the DATE datatype (only DATE - not DATETIME!), then you can indeed also use the YYYY-MM-DD format and that will work, too, with any settings in your SQL Server.
Don't ask me why this whole topic is so tricky and somewhat confusing - that's just the way it is. But with the YYYYMMDD format, you should be fine for any version of SQL Server and for any language and dateformat setting in your SQL Server.

Categories

Resources