Problems with postgresql, c# and windows server 2019 - c#

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)

Related

Date randomly changed in different time zone in asp.net

I am facing a weird scenario that the date of a textbox (which is fetched by sql database) is changed randomly by date (-1)day
My WebApp is deployed in USA on two servers *(the both servers have time difference on 1 hour due to UTC-5, UTC-6) and i am in Timezone UTC+5.
Inside SQL Table there is a date '05/31/2020' but sometimes it shows '05/30/2020' on front end.
The column type in SQL is Date. Then i get it DataSet, and on code behind this line is used Convert.ToDateTime(DataSet.Tables[0].Rows[0]["Date"])).ToShortDateString()
When i debug this code locally the date is correct every time.
I suspect that somewhere you have an issue with local and UTC time.
With you on UTC+5 and your servers on UTC-5 and UTC-6 its possible for them to be a day behind you e.g. your local time is before 10am Friday they will still be on Thursday.
How does your back end handle the date? It should always be in UTC, you then load your SQL DATE value into a DateTime type and use DateTime.ToLocalTime to convert to your UI and DateTime.ToUniversalTime when passing from UI to back end SQL.

Timezone issue when searching SQL Server from C#

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.

Saving user selected date as utc and query against db with utc fields

I am a little bit confused what is the correct approach.
My app will be a global app meaning places (owners of events) with different timezones will be interacting with it and I want to keep things simple.
My app allows places(owner of events) to create events on a calendar (by obviously picking datetime) and then save to db. (StartDateTime, EndDateTime)
Then users (event attendees) will view events happening near them.
What I have done so far is create 2 fields called StartDateTimeUTC, EndDateTimeUTC in my table and I have for each user allowed them to have a default timezoneid set.
When creating new events, i read their timezone, convert the datetime they have selected to UTC
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); //gotten from db
DateTime startDateTimeUserSelected = new DateTime(2016, 4, 14, 2, 15, 0); //user picked from a datetimepicker
DateTime endDateTimeUserSelected = new DateTime(2016, 4, 14, 4, 15, 0); //user picked from a datetimepicker
var starDateTimeUTC = TimeZoneInfo.ConvertTimeToUtc(startDateTimeUserSelected, tz);
var endDateTimeUTC = TimeZoneInfo.ConvertTimeToUtc(endDateTimeUserSelected, tz);
Then I save those to to my db fields, great now i got my user selected date as utc and saved to db.
Now I want to query the db for all events that happen today but I need to get the LOCAL TIME for the current user (based on their timezone)
var currentTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tz); //tz being read from db for particular user
And then I can use the currentTime to find and query my db for all events happening today.
Just of the app
Place creates events for their users (place can be anywhere in the world) using the backend, users using app on their mobile will view what events are happening at different places around them (same timezone)
Question
Is this the correct way to deal with timezones without having to worry about daylight savings? or do I have to do more for an app that shows events to user based on their local time, and keeping everything in sync.
or should i just store everything as none UTC and determine user's current datetime from browser for places (owner of events) to query against db, and edit/add events. And determine users (attendees)'s time from the mobile device.
If I go with UTC i have keep track of timezone both for the Places and attendees and make sure all comparisons are done via UTC.
If i just enter everything as NONE utc, i dont have to worry about any conversion other than the fact that I need to read users CURRENT DATETIME from either browser/mobile device.
Have i missed anything?
When I was working with Azure Table Storage (NOSQL) I encountered this same roadblock since ATS always store all date time fields as UTC.
On the database table I had 3 fields:
TerminalUtcTime DATETIME
TerminalTimezone CHAR(6)
TerminalLocalTime CHAR(12)
The goal is to NEVER compute the terminal's local time using UTC and timezone. Because the effects of daylight
savings time (summer time), etc. is not reflected on the timezone as
well as UTC time.
On my experience, we had to forward the terminal's local time as is to some bank web service which is very strict. We had to send data as accurate as possible.
On the client:
DateTime terminalUtcTime = DateTime.Now.ToUniversalTime();
string terminalTimeZone = // Get from TimeZoneInfo.Local and format to ±hh:mm like +08:45 or -10:00 (format varies on how you may want it to be)
// Getting the timezone can be tricky because the hh and mm separator can be changed in the control panel so I had to use substrings instead
DateTime terminalLocalTime = DateTime.Now.ToLocalTime();
On the server:
You just need to save the terminalUtcTime as TerminalUtcTime,
terminalTimezone as TerminalTimezone and the terminalLocalTime as string.
terminalLocalTime.ToString("yyyyMMddHHmmssfff"); // Saves up to the milliseconds
Now, if needed, you can retrieve the DateTime instance of the terminal's local time. No need to compute, etc. I use DateTime.ParseExact(var, "yyyyMMddHHmmssfff");
Yes, you have to add a new field on the table but it saves you all the worries. This is the approach on a database that only allows UTC time, but if you are using MySql, MSSQL, etc. that allows saving of non-UTC time then that may work for you as well and saves up all the trouble.

How to record UTC time in Azure SQL?

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.

Format of DateTime that SQL Server uses

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.

Categories