I want to store UTC time in a column in Azure SQL so that I can localize the date time for users of my mobile app regardless of their time zone. I was using SQL Server 2014 on my local desktop to develop the database which I intend to migrate to Azure SQL.
Now I tried using the type datetimeoffset(7) for my column, however when I insert the date, I see values like this in management studio (with my own local offset value)
2016-03-13 18:00:00.0000000 -04:00
Which is a bit confusing because there should be no offset, UTC is always the reference point -00:00 Is this a UTC value or not? Or is SQL Management studio converting them for display to my local time zone?
Furthermore, is my C# code providing the value as UTC or as an offset value?
My C# code used to pass the parameter to my stored procedure looks like this
string dtFormat = "yyMMdd HHmm";
DateTimeOffset dtOut;
bool result = DateTimeOffset.TryParseExact(CurrentUTC.date + " " + CurrentUTC.time, dtFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out dtOut);
command.Parameters.Add("#datetime", SqlDbType.DateTimeOffset).Value = dtOut;
For my Azure apps, I just use a datetime field in Azure SQL and then in C# use DateTime.UtcNow for the value of that field.
When reading it back out, I use TimeZoneInfo.ConvertTimeFromUtc() with the local user's timezone string.
Related
Im using a C# query that automatically uses the date_trunc with timezone function, however when trying to run the function in postgres it doesnt work. I receive this error:
ERROR: function date_trunc(unknown, timestamp with time zone, unknown) does not exist
According to the Postgres documentation. It should support:
date_trunc(field, source [, time_zone ])
For example I can call,
SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40+00');
But not,
SELECT date_trunc('day', TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40+00', 'Australia/Sydney');
Is this optional time_zone field new and my postgres out of date? Currently running version PostgreSQL 11.14.
Specifying the time zone in date_trunc is not supported in Postgresql 11.
Take a look at AT TIME ZONE described just below date_trunc in the link above, you could use something like
date_trunc('day', TIMESTAMP '2001-02-16 20:38:40+00' AT TIME ZONE 'Australia/Sydney')
HTH
I have a very strange problem, I have an application that connects to a local server with postgresql, the application is programmed with visual studio 2019, c # and npgsql driver, what the application does is ask for the time zone of a column timestamp from the database. So far so good, it gives me time zone values -3 and -4 which is what I expect. Then I take the same application with the same framework, version of the postgresql server and driver, but when I run this on the server that has windows server 2019 it always returns the timezone with value 8 no matter what I do, the time zone of my computer and windows server 2019 are the same and both are located in the same country, the operating system of both is updated to the latest version.
This is the code for the main method of the class.
static void Main(string[] args)
{
PgSqlConnection pgSqlConnection1 = new PgSqlConnection();
pgSqlConnection1.Host = "127.0.0.1";
pgSqlConnection1.Port = 5432;
pgSqlConnection1.UserId = "postgres";
pgSqlConnection1.Password = "230169";
pgSqlConnection1.Database = "biotime";
pgSqlConnection1.Open();
PgSqlCommand command = pgSqlConnection1.CreateCommand();
command.CommandText = "SELECT EXTRACT(TIMEZONE FROM now())/3600.0 as zona;";
PgSqlDataReader reader = command.ExecuteReader();
PgSqlDataAdapter adaptador = new PgSqlDataAdapter(command);
DataTable tabla = new DataTable();
adaptador.Fill(tabla);
Console.WriteLine(tabla.Rows[0][0].ToString());
Console.ReadKey();
}
I'm using DEVART connector form postgresql but same issues with NPGSQL
I think there's some baseline misunderstanding of PG time storage here. Timestamps in Postgres do not "store a timezone" so you can't get PG to "give you a stored timezone".
With respect to datatypes:
timestamp stores whatever time you give it, or whatever time it is in whatever timezone the db is set to if you use now() as the value. If you give it a time of '15:00' it stores 15:00. If you give it a time with an offset such as 15:00-0500, it discards the offset and stores the 15:00. If it's 3pm in Chicago right now and you told the db it lives in Chicago, and you insert now() then 15:00 is stored.
When you ask for it back the time you get is the time as stored, even if you changed the timezone of the db since
the column is a timestamp
the db is in -8 (in a location that doesn't observe DST, to make things simple) and you store the time 15:00 (either by inserting a value '15:00' or by using the now() function when it's exactly 3pm in a -8 zone)
querying the db reports the time as 15:00
you change the db to a -5 (non DST) zone
querying the table still gives the time as 15:00
timestamptz takes whatever timestamp with offset you give it and converts it to UTC. If you get the time from now() then the time is the current time in the declared zone, converted to its UTC equivalent. The UTC time is stored. The offset you provided (or the offset of the timezone active at the point you used the now() function) is NOT stored. When you ask for it back the db converts the stored time according to the currently configured zone and presents it as the time in that zone
the column is a timestamptz
the db is in -8 (non DST) and you store the time 15:00 (either by inserting a value '15:00' or by inserting a value '15:00-0800' or by inserting a value '16:00-0700' or by inserting a value '17:00-0600' or by ... or by using the now() function when it's exactly 3pm in a -8 zone)
querying the table gives the time as '15:00-0800' (even if you inserted '16:00-0700' it is stored as '23:00+0000' and converted to '15:00-0800' upon query because the db is in -8
you change the db to a -5 (non DST) zone
querying the table now gives the time as '18:00-0500'; same moment in time, same stored value of '23:00+0000', different presentation
So, EXTRACT TIMEZONE FROM somestoredtimestamp is really just a synonym for "what is the applicable offset of this stored moment, in the timezone you're set to?", it's not extracting a timezone from anything - it's giving an offset from UTC for that time in the current known timezone. If the db is set to Chicago (observes DST) then you'll get -5 or -6 out of it depending on what time of year the date is. If the db was set to a location that didn't observe DST then you'd get a consistent offset out of it regardless the date. Offsets are not time zones so "extract timezone" is a misnomer.
The time zone PG uses can be set in a variety of places - the PostgreSQL config file, the TZ environment variable, the connection string, per session by SET TIMEZONE TO ..., or it might even use the windows control panel region settings if it wasn't set anywhere else
You're getting +8 from your EXTRACT TIMEZONE command because PG believes it lives in a zone that is +8 and has no DST (like Singapore)
I have a search model that sends a date range to a stored procedure. The stored procedure returns back results. This works fine where I am in Central Time.
However we have users in India and they could input valid dates of lets say '08/15/2017 23:00' and in the table for them the date is '08/14/2017' so they don't get any data returned.
If they input 08/14/2017 they get the wrong data. Data from 08/13/2017
How can I address the issue of time zone in c# before sending it to the stored procedure?
I have tried this with no luck
public DateTime AdjustForTimezone(DateTime date)
{
TimeZoneInfo timeInfo = TimeZoneInfo.FindSystemTimeZoneById(TimeZone.CurrentTimeZone.StandardName);
var newDate = TimeZoneInfo.ConvertTimeToUtc(date);
return newDate;
}
SqlCommand cmd = new SqlCommand("getTableData", connection);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
SqlCommandBuilder.DeriveParameters(cmd);
cmd.Parameters[1].Value = AdjustForTimezone(dateModel.FromDate);
cmd.Parameters[2].Value = AdjustForTimezone(dateModel.toDate);
Client to Server
The clients should send date time instances to the server with a UTC value or with the current offset from UTC.
The database should persist the DateTime (or DateTimeOffset) as DateTime/2 (or use DateTimeOffset).
Server to Client
The server should send the date time information to the client with the UTC value (or offset from UTC). It is the client's responsibility to apply the client's desired offset when the date time is presented (ie. do it in the presentation layer as late as possible).
Serialization
If you have to serialize your date times use ISO8601 notation.
By applying the above rules you now have stored your date time values in a way that they are comparable and unambiguous. They can now be filtered, sorted, etc.
If you are filtering be sure to take the date time filter parameters from the client and apply the same rules. Searching in eastern USA time zone for records that fall on the date 2017-02-06 should be translated into records with a date range between 2017-02-06T05:00:00 and 2017-02-07T05:00:00 as that time zone is UTC−05:00 at that point in time.
Side Notes
That there are exceptions to the rule like storing a birth date.
Personally I prefer storing DateTime/2 as UTC over DateTimeOffset both in code and in the data store.
I have a C# MVC Web application hosted in a remote server. I don't know the exact location of that.
The users of that application are all from (UTC + 06.00) Dhaka. When a user inserts a new record, I want the inserted datetime from his local time e.i (UTC + 06.00) Dhaka.
How can I do it?
The following code solves my problem-
DateTime utcTime = DateTime.UtcNow;
TimeZoneInfo BdZone = TimeZoneInfo.FindSystemTimeZoneById("Bangladesh Standard Time");
DateTime localDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, BdZone);
You can follow below approach:
Step 1:
You can store UTC time in database. If you are using SQL then you can use GETUTCDATE() to get UTC date.
Step 2
Please use Javascript to set a cookie, storing the browser timezone. (You can use scripts like jsTimeZoneDetect to get timezone name)
Step 3
Backend C# code:
Pull timezone from cookie.
Get the inserted utcTime from database and store in local variable(utcTime is the local variable name i used).
Use below mentioned code to convert UTC time to local time.
TimeZoneInfo tzoneinfo = TimeZoneInfo.FindSystemTimeZoneById("browser timezone name");
DateTime localTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, tzoneinfo);
Finally localtime is the end result. :)
Hope this will help you
Thank you
You should use global time zone of your ASP.NET application. Check this. This will work unless you use only C# datatime function. Once you have some complex code in SQL Server which will use GETTIME function. You will also rely on SQL Server timezone.
You should handle the internal datetime in UTC and convert the timezone only in UI.
I am debugging a query that is getting built in C# maybe with EntityFrameWork - not sure - but it doesn't return any records although it should.
The query has some DateTime fields and they are like this:
personStartDate {4/3/2013 12:00:00 AM}
The value for Date is getting from user interface date picker but I guess it also defaults the time part to 12:00:00 AM somehow.
Then I go to SQL Server and view the table rows and values on their datatime field data looks like this example: '2013-04-23 09:20:38.897'
Do you see any obvious problem right there?
Also I am trying to take the generated SQL from my breakpoint in C# and post it to SQL Server to see what does it return so for a value like {4/3/2013 12:00:00 AM} I am replacing it with 2013-04-03 12:00:00.000 Is that even correct?
Formatting is irrelevant. Internally it won't be in a text format at all, and I'd hope that the query doesn't end up sending the query value to the database as text either.
If you're only interested in the date part, you need to say that in the query:
where foo.Start.Date == personStartDate
(for example - we don't know what your query looks like).
If your field in the database is logically just a Date but is currently a DateTime, you should consider changing your schema to match your logical data model. It'll make things simpler.
If you create a DateTime using DateTime.Today then the time part will default to midnight. That is what the date picker is doing.
Your database contains a time portion too. If that is incorrect you can convert it in sql: Best approach to remove time part of datetime in SQL Server
2013-04-03 12:00:00.000 is noon is 12:00:00 PM. You want 12:00:00 AM which is midnight. You should use 2013-04-03 00:00 in your test or 2013-04-03 or '3 April 2013'. Again, the time portion will default to 00:00.
To get the query to work in c# with the "bad" data in the database, make the query less precise by doing "less than tomorrow more than or equal to today" rather than "equals". Or make the database more precise by dropping the time part - then you can use "equals". If you are using Entity Framework and Linq-to-Entities you may need to use EF's DbFunctions
Ideally you should track down the inserts and updates that are setting the time in the database and stop that happening, then fix the existing data. Then you could change the data type in the database from DateTime to Date.
A Sql Server DateTime value is a pair of 32-bit integers. The first is the count of days from the SQL Server calendar's epoch (1 Jan 1900 00:00:00.000); the second is the count of milliseconds since start of day.
The string representation of that is dependent on (A) the default language setting for your SQL Server instance, (B) the current language setting for the session, (C) the current set dateformat setting, and probably a few other options I've forgotten.
If you care about the string representation, explicitly convert it to a string using convert(varchar(X),your-datetime-value-here,style) using the style of your choice.
Note that SQL Server Date and DateTime values are converted to/from System.DateTime values by the runtime.