Utc Date saving as Local date in Sqlite - c#

I have an Sql database which contains a date field.
I use Dapper to update the database as follows:
const string sql = "UPDATE AdminDb.Users " +
"SET IsLoggedOn = 1, LastLoggedOn = #LastLoggedOn " +
"WHERE Username = #username";
var date = DateTime.UtcNow;
DatabaseConnectionBase.DatabaseConnection.Execute(sql, new { username, LastLoggedOn = date });
I am finding to my great annoyance when breaking before the actual update, the date variable reads 30/3/2015 9:32:54 however when I run the update the database saves the date as 30/3/2015 10:32:54
As the UK yesterday changed from GMT to BST (UTC +1) I am sure that the database seems to be trying to compensate for this as this issue never came up before.
I thought I had averted this sort of issue by using the DateTime.UtcNow property to save my date.
This is causing serious issues when validating users.
I am sure it is not my code as the date is correct going into the Dapper Execute method.
I can't see why Dapper would try to compensate as most developers would be screaming at such functionality
Which leads me to the conclusion that it must be something in Sqlite that is causing this issue. Perhaps there is a pragma I need to run?
As per a suggestion from another site I tried formatting the date as follows:
var date = DateTime.UtcNow.ToString("o");
The intention being to force the date into ISO-8601 format but I had no luck with that.
Has anyone got any ideas?

Thomas Levesque has the solution here:
// You just need to specify DateTimeKind=Utc in your connection string:
string connectionString = #"Data Source=D:\tmp\testSQLiteDate.db;DateTimeKind=Utc";

This happened to me too.
What I did was serialize the datetime to a string myself before adding it as a parameter.
internal const string DateTimeFormat = "yyyy-MM-dd HH:mm:ss";
cmd.Parameters.Add("#Threshold", DbType.DateTime).Value = threshold.ToString(DateTimeFormat);

If you do the same thing with pure ADO.NET, does the same thing happen? I wonder if this is a database thing or a provider thing, rather than a library thing. Dapper has to ToLocalTime() or ToUniversalTime() calls - it passes the time through unaltered. On SQL Server, the following works fine in a BST setting:
public void SO29343103_UtcDates()
{
const string sql = "select #date";
var date = DateTime.UtcNow;
var returned = connection.Query<DateTime>(sql, new { date }).Single();
var delta = returned - date;
Assert.IsTrue(delta.TotalMilliseconds >= -1 && delta.TotalMilliseconds <= 1);
}

Related

Problem with converting time according to timezone in C#

I am trying to convert a DateTime into UTC from a source timezone. Date, time and timezone are taken as inputs from a user (presented as dropdown menu options).
Following is a portion of the code utilized for conversion:
string inputDateString = "2019-11-12T09:00:00.000"; //Taken as input from user
string inputTimeZoneString = "(UTC-03:00) Brasilia"; // Taken as input from user
DateTime dtStartdatetime = DateTime.Parse(inputDateString);
string sourceTimeZone = string.Empty;
foreach (TimeZoneInfo a in TimeZoneInfo.GetSystemTimeZones())
{
if (a.DisplayName == objCalendar.timezone)
{
sourceTimeZone = a.Id;
}
string strTimeZone = a.DisplayName.Substring(a.DisplayName.IndexOf(')') + 1);
string strTimeZone1 = objCalendar.timezone.Substring(objCalendar.timezone.IndexOf(')') + 1);
if (strTimeZone.Trim() == strTimeZone1.Trim())
{
sourceTimeZone = a.Id;
}
}
DateTime utc_time_start = TimeZoneInfo.ConvertTimeToUtc(dtStartdatetime, TimeZoneInfo.FindSystemTimeZoneById(sourceTimeZone));
Console.WriteLine(utc_time_start.ToString("yyyyMMddTHHmmssZ"));
The problem is that this piece of code gives 20191112T120000Z as output when run on Dev system (based in IST timezone) whereas same code results in 20191112T110000Z as output when run on server (based in EST). Is this behavior due to difference in timezone of the systems on which it is being run? What is could be a possible solution for this situation? A particular time from a particular timezone should result in same UTC time irrespective of the machine where the code executes.
The time zone that your server is running in does not impact this code.
The difference is due to the end of DST for Brazil in 2019.
Windows released an update in July 2019 to cover this scenario. Specifically, this change is addressed by KB4507704 and Windows 10 Build 17763.652. Your dev environment has this update, the server does not. You should ensure your server is receiving Windows Updates. If it's missing this (5 months after release), it's probably missing more critical security updates as well.
Additionally, I strongly discourage matching time zone by display name for a few reasons:
The display names are localized by the primary language of the operating system, so they will be different, for example, on a server set for English than on a server set for Portuguese. (The globalization and localization settings in .NET are not used for this.)
The display names are potentially volatile. That is, if there is a reason to change the display name in a future update, the string will change from what you previously had used.
Instead, pass the Id of the time zone as an input to TimeZoneInfo.FindSystemTimeZoneById, and skip the matching bit in the middle entirely.
You are not leaving your loop after you found a source time zone.
In your second part you search for a partial string of the time zone. Most probably this part finds a second time zone on your server. This can happen if the OS or .net versions differ.
Try:
string inputDateString = "2019-11-12T09:00:00.000"; //Taken as input from user
string inputTimeZoneString = "(UTC-03:00) Brasilia"; // Taken as input from user
var dtStartdatetime = DateTime.Parse(inputDateString);
string sourceTimeZone = string.Empty;
foreach (TimeZoneInfo a in TimeZoneInfo.GetSystemTimeZones())
{
if (a.DisplayName == inputTimeZoneString)
{
sourceTimeZone = a.Id;
break;
}
string strTimeZone = a.DisplayName.Substring(a.DisplayName.IndexOf(')') + 1);
string strTimeZone1 = inputTimeZoneString.Substring(inputTimeZoneString.IndexOf(')') + 1);
if (strTimeZone.Trim() == strTimeZone1.Trim())
{
sourceTimeZone = a.Id;
break;
}
}
DateTime utc_time_start = TimeZoneInfo.ConvertTimeToUtc(dtStartdatetime, TimeZoneInfo.FindSystemTimeZoneById(sourceTimeZone));
Console.WriteLine(utc_time_start.ToString("yyyyMMddTHHmmssZ"));

Comparing two datetimes to check for a clash but seems to be confusing MM/DD with DD/MM C# ASP.NET

I am trying to check my database for a clash, I am reading up using a reader and calling the value down. My value is 10/12/2018 15:00:00 So I have stored this as #moduleStartTime
My next query checks the database using the above datetime and if it is between any other dates entered.
The issue I am encountering is that there are no clashes, so this shouldn't flag up that there are. I have found that the clash it is returning has a datetime of 12/10/2018 15:00:00
It appears as though somewhere in the search, it is reversing DD/MM
Here is my code
//Reading to get all modules student is enrolled on
string checkclash = "SELECT * FROM cModuleTimes INNER JOIN cStudentModule ON cModuleTimes.ModuleID = cStudentModule.ModuleID WHERE cStudentModule.StudentID=#studentid AND #date BETWEEN[StartTime] AND[EndTime] AND ModTimeID <> #modtimeid";
SqlCommand myCommandclash = new SqlCommand(checkclash, myConnectionclash);
myCommandclash.Parameters.AddWithValue("#date", moduleStartTime);
myCommandclash.Parameters.AddWithValue("#courseid", courseid);
myCommandclash.Parameters.AddWithValue("#studentid", user);
myCommandclash.Parameters.AddWithValue("#modtimeid", moduletocompareid);
//create a sqldatareader object that asks for dats from a table
SqlDataReader rdrreadclash = myCommandclash.ExecuteReader();
if (rdrreadclash.HasRows)
{
while (rdrreadclash.Read())
{
string getname = rdrreadclash["ModTimeID"].ToString();
string gettime = rdrreadclash["StartTime"].ToString();
Warning.Text = "There appears to be a clash with this event..<br><br> <br> <b>Would you like to continue?</b> <br><br>";
}
ViewClash.Visible = true;
YesContinue.Visible = true;
FinishMod.Visible = false;
}
myConnectionclash.Close();
I have tried a couple of conversions but am receiving an issue with string not recognised as a DateTime.
If anyone has any answers on how I would prevent this clash from appearing, I would be very grateful.
Thank you.
moduleDateTime is currently a string, you need to parse it in to a DateTime object where the parsing operation has the proper MM/DD order you want.
DateTime dateAsDateTime = DateTime.ParseExact(moduleStartTime, "dd/MM/yyyy HH:mm:ss", null);
myCommandclash.Parameters.AddWithValue("#date", dateAsDateTime);
You then must format the returned date time back to a string in the format you want.
string gettime = ((DateTime)rdrreadclash["StartTime"]).ToString("dd/MM/yyyy HH:mm:ss ");

Datetime function converting one date older time

string date = "2017-01-05T00:00:00+00:00";
string time = Convert.ToDateTime(date).ToString("MM/dd/yyyy");
I am getting the above date from my client database, i am trying to convert that time to string but when i executed it was returning 01/04/2017 . why this is converting one day before ?
Ok my bad. Here goes:
Yes I agree its a timezone offset issue, but this will work anyways:
string date = "2017-01-05T00:00:00+00:00";
string time = DateTimeOffset.Parse(date).DateTime.ToString("MM/dd/yyyy");

how to compare the time and date using mysql and c#

I have a table logout with columns
logout_id
logout_datetime values format like this(2011-09-08 11:09:09)
and i want to compare the logout_datetime with today date and time also....
for that i have done like this....
string dtStartString = DateTime.Today.ToString("yyyy-MM-dd");
string timeonly = DateTime.Now.ToShortTimeString();
string sql = #"select logout_id";
sql+= string.Format("where logout_datetime = '{0}'",dtStartString );
but it will compares only date in logoutdatetime ,its wrong i want to compare the time also
how can i do this..
would any one pls help on this...
Of course your code is only comparing the date because you are passing only dtStartString which does not have a time part.
try to pass this:
string dtStartString = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
Use Parameters.
string sql = "select logout_id from TableName
where logout_datetime=#logout_datetime";
...
cmd.Parameters.Add("#logout_datetime",MySql.Data.MySqlClient.MySqlDbType.Datetime)
.Value=DateTime.Now; // you may assign any value of DateTime type.
You could use the date-format, or extract function.
You should read more about date time functions

Conversion of a Varchar Datatype to a datetime resultant in an out of range

I have problem. I can' identify my mistake...
int dt = Convert.ToInt32(Items.Rows[T1]["F14"].ToString().Trim());
int mn = Convert.ToInt32(Items.Rows[T1]["F15"].ToString().Trim());
int yr = Convert.ToInt32(Items.Rows[T1]["F16"].ToString().Trim());
string DtString = mn.ToString().Trim() + "/" + dt.ToString().Trim() + "/" + yr.ToString().Trim();
DateTime RegExp = Convert.ToDateTime(DtString);
exp_date is datetime field in sqlserver.
string MyDtQry = "UPDATE MyTable SET exp_date='" + RegExp + "' where MyTable.id_no='" + AlmIDNo + "'";
But I'am getting the error:
Conversion of a Varchar Datatype to a datetime resultant in an out of range
Well, I would approach the task very differently:
After getting the day, month and year as integers I definitely wouldn't stick them back together and parse them. Just use:
// Note the meaningful variable names here, btw...
DateTime date = new DateTime(year, month, day);
When updating the database, I wouldn't put the value directly into the SQL statement. Use a parameterized SQL statement instead, and set the parameter to date. That way you don't need to worry about the database expecting a different date format to the one you provide. In general, you should always use parameterized SQL rather than embedding the values directly into the SQL - as well as helping with this kind of situation, it avoids SQL injection attacks.
Now, after doing all of that, if you're still getting an error, you should check what actual data you're trying to insert. Maybe the data in Items really is out of range for SQL Server.
It is hard to see exactly since you don't show any of your inputs; however, the following is clearly dangerous:
DateTime RegExp = Convert.ToDateTime(DtString);
string MyDtQry = "UPDATE MyTable SET exp_date='" + RegExp + "' where MyTable.id_no='" + AlmIDNo + "'";
Even if we gloss over the fact that you should be using parameters (you really should), you would need to format this date in the way that SQL server expects - which could be very different to the local format.
However; don't bother formatting it! Use a parameter for this, and it'll go away. This doesn't need to be hard - for example with dapper:
DateTime RegExp = new DateTime(yr, mn, dt);
connection.Execute("UPDATE MyTable SET exp_date=#exp where MyTable.id_no=#id",
new { exp = RegExp, id = AlmIDNo });
and done; fully safe from both injection and the (more likely in this case) issue of formatting data as strings.
This must be problem of the format you are specifying, like instead of month column you might be saving date value column.

Categories

Resources