.net client server with different timezones - c#

I have a very strange behavior on an application. The server is in New York(-5 GMT timezone) and the client - me, in Romania(+2 GMT timezone) so there is a 7 hour discrepancy. The problem I'm facing is when I try to save a date, let's say 12:00(day doesn't matter), the client is sending a request with the date 12:00, the 12:00 reaches the database but when it returns the severs returns the hour 19:00. I tried to debug on local to see who messes up the date but since I have the same date on server and on client there is no discrepancy.
This is the parameter sent to server &startDate=07/25/2012%2012:00:00
And this is the result: 1343232000000 - the seconds from the epoch(if you use a converter - http://www.epochconverter.com/ - you will see that the date is in fact Wed Jul 25 2012 19:00:00
here are some code snippets :
public static void GetProfessionalsHours(List<long> ids, out List<SalonProfessional> professionals)
{
professionals = new List<SalonProfessional>();
using (SqlConnection conn = new SqlConnection(DbConfig.ConnectionString))
{
using (
SqlCommand command = new SqlCommand("GetProfessionalsHours", conn) { CommandType = CommandType.StoredProcedure })
{
conn.Open();
command.Parameters.AddWithValue("professionalIDs", ids.CommaSeparated());
using (IDataReader reader = command.ExecuteReader())
{
//get normal schedule
while (reader.Read())
{
professionals.Add(SalonProfessional.GetSalonProfessional(reader));
}
reader.NextResult();
while (reader.Read())
{
professionals.Find(p => p.ID == reader.GetInt64(1)).Hours.Add(ProfessionalHours.GetProfessionalHour(reader));
}
//get overriden hours
reader.NextResult();
while (reader.Read())
{
professionals.Find(p => p.ID == reader.GetInt64(1)).OverriddenHours.Add(ProfessionalOverriddenHour.GetProfessionalOverriddenHour(reader));
}
}
}
}
}
public static ProfessionalOverriddenHour GetProfessionalOverriddenHour(IDataReader reader)
{
return new ProfessionalOverriddenHour()
{
ID = reader.GetInt64(0),
ProfessionalId = reader.GetInt64(1),
StartDate = reader.GetDateTime(2),
EndDate = reader.GetDateTime(3),
};
}
public JsonResult CalendarData(List<long> professionalIDs, CalendarData calendarData)
{
AjaxResponse response = new AjaxResponse();
response.Success = true;
CalendarDataResponseObject responseData = new CalendarDataResponseObject();
response.Content = responseData;
try
{
List<SalonProfessional> professionals = null;
CalendarOperations.GetProfessionalsHours(professionalIDs, out professionals);
responseData.Professionals = professionals;
}
catch (Exception ex)
{
response.Success = true;
response.ErrorMessage = "Could not retrieve calendar data";
ExceptionsOperations.LogException(ex, "Could not retrieve calendar data");
}
return Json(response, JsonRequestBehavior.AllowGet);
}
The problem is on StartDate and EndDate from the ProfessionalOverriddenHour object.

You could send the offset (z) or agree on UTC
Console.WriteLine(DateTime.Now.ToString("hh mm ss z"));
Console.WriteLine(DateTime.Now.ToUniversalTime().ToString());

Try storing and retrieving date string after converting with reference to UTC first.
Here is a excerpt from Scott Hanselman blog post
Phrased differently, don't use DateTime.Now for ANY date calculations
or to store anything. Use DateTime.UTCNow and be aware that some
methods will freak out if you send them future dates, as they should.
Avoid doing ANYTHING in local time until that last second when you
show the DateTime to the user.
Also check out Daylight saving time and time zone best practices

Like already suggested, always use UTC when storing dates (in databases, files, etc.), and let the client itself decide on what timezone should be used when displaying that date (and only then!)
You can of course get it working by just including the timezone data in the date string, but it makes everything more complex (imho), stick to the simple case where dates are always UTC, unless you're displaying it to the users.

Thanks a lot for help guys!
The problem was that both the server and the client were converting the date to their local time. So the solution was to get the hours difference on server and add them to the date and on javascript to work with utc time. Basically when you don't need time zones, work with UTC everywhere.

Related

Get data using Date and Time from sql in C#

I have a simple console application and this application gets data from the SQL server. I have to search data using date and time from the SQL server. This below code works if I enter only the year for example if I enter 2017 or 2018, then it gets data of all that year but if I try to enter in 2017-07-22, then it doesn't get any data. My SQL server has date format of year-month-day hh-mm-ss. I am kind of stuck here. Any suggestions?
using (var context = new Model1())
{
Console.WriteLine("Enter Date");
DateTime dateTime;
var s = dateTime.ToShortDateString();
s = Console.ReadLine();
var result = context.Databases.
Where(x => x.RecordedTime.Value.ToString().
Contains(s)).ToList(); ;
foreach (var item in result)
{
Console.WriteLine($"{item.RecordedTime.Value.ToShortDateString()}, {item.Temperature}");
}
}
You don't need to convert to string, you need to only parse it. To parse with an exact format you can use DateTime.TryParseExact like this, based in the format you provided:
s = Console.ReadLine();
DateTime dt;
DateTime.TryParseExact(s,
"yyyy-MM-dd HH-mm-ss",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out dt);
//... do linq stuff with variable dt

How to get country wise / timezone wise date & time from internet server

i have to show date & time to user as per the user timezone id. i can not rely on user pc date time and setting. i was searching Google for the way and got a below code. code seems will query many external server for date & time but one thing not clear to me what kind of date & time i can expect from the below code.
some time i need india time. some time i need london time and some time i need other country local time. few county has many timezone that is why i want to send timezone id/name and want to get datetime based on timezone id/name.
so just guide me how to customize the below code where i can send user's side timezone id and routine will return right local time based on timezone id even if user pc datetime setting is wrong. looking for good help. thanks
public static DateTime GetFastestNISTDate()
{
var result = DateTime.MinValue;
// Initialize the list of NIST time servers
// http://tf.nist.gov/tf-cgi/servers.cgi
string[] servers = new string[] {
"nist1-ny.ustiming.org",
"nist1-nj.ustiming.org",
"nist1-pa.ustiming.org",
"time-a.nist.gov",
"time-b.nist.gov",
"nist1.aol-va.symmetricom.com",
"nist1.columbiacountyga.gov",
"nist1-chi.ustiming.org",
"nist.expertsmi.com",
"nist.netservicesgroup.com"
};
// Try 5 servers in random order to spread the load
Random rnd = new Random();
foreach (string server in servers.OrderBy(s => rnd.NextDouble()).Take(5))
{
try
{
// Connect to the server (at port 13) and get the response
string serverResponse = string.Empty;
using (var reader = new StreamReader(new System.Net.Sockets.TcpClient(server, 13).GetStream()))
{
serverResponse = reader.ReadToEnd();
}
// If a response was received
if (!string.IsNullOrEmpty(serverResponse))
{
// Split the response string ("55596 11-02-14 13:54:11 00 0 0 478.1 UTC(NIST) *")
string[] tokens = serverResponse.Split(' ');
// Check the number of tokens
if (tokens.Length >= 6)
{
// Check the health status
string health = tokens[5];
if (health == "0")
{
// Get date and time parts from the server response
string[] dateParts = tokens[1].Split('-');
string[] timeParts = tokens[2].Split(':');
// Create a DateTime instance
DateTime utcDateTime = new DateTime(
Convert.ToInt32(dateParts[0]) + 2000,
Convert.ToInt32(dateParts[1]), Convert.ToInt32(dateParts[2]),
Convert.ToInt32(timeParts[0]), Convert.ToInt32(timeParts[1]),
Convert.ToInt32(timeParts[2]));
// Convert received (UTC) DateTime value to the local timezone
result = utcDateTime.ToLocalTime();
return result;
// Response successfully received; exit the loop
}
}
}
}
catch
{
// Ignore exception and try the next server
}
}
return result;
}
EDIT
var wc = GetFastestNISTDate();
var pattern = InstantPattern.CreateWithInvariantCulture("dd/MM/yyyy HH:mm:ss");
var parseResult = pattern.Parse(wc.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture));
if (!parseResult.Success)
throw new InvalidDataException("...whatever...");
var instant = parseResult.Value;
var timeZone = DateTimeZoneProviders.Tzdb["Europe/London"];
var zonedDateTime = instant.InZone(timeZone);
var bclDateTime = zonedDateTime.ToDateTimeUnspecified();
timezone translation is not working. i got the right date from this function GetFastestNISTDate(); and next i try to get local date and time of different timezone based on my first utc time but code return wrong time for London. i guess i am making mistake the code. can anyone see & help. thanks
DateTime tzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, TimeZone);
Hope this helps.
The timeservers will report UTC time (that's why the variable is named utcDateTime).
The result = utcDateTime.ToLocalTime(); line converts that UTC time from the timeserver to the local time according to the timezone your computer is in. If you want a different timezone, you need to change that line.
As amit mentioned, you can use TimeZoneInfo.ConvertTimeFromUtc to convert to some specified timezone. See the example on that page.
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);

How Convert UTC Date & time to local time using different timezone Nodatime

i am using a function which is taking date time over the internet from external server.
here is the function which i am using to get date and time without depend on user pc date time settings.
using NodaTime;
using NodaTime.Text;
using System.IO;
using System.Globalization;
public static DateTime GetFastestNISTDate()
{
var result = DateTime.MinValue;
DateTime utcDateTime = DateTime.MinValue;
// Initialize the list of NIST time servers
// http://tf.nist.gov/tf-cgi/servers.cgi
string[] servers = new string[] {
"nist1-ny.ustiming.org",
"nist1-nj.ustiming.org",
"nist1-pa.ustiming.org",
"time-a.nist.gov",
"time-b.nist.gov",
"nist1.aol-va.symmetricom.com",
"nist1.columbiacountyga.gov",
"nist1-chi.ustiming.org",
"nist.expertsmi.com",
"nist.netservicesgroup.com"
};
// Try 5 servers in random order to spread the load
Random rnd = new Random();
foreach (string server in servers.OrderBy(s => rnd.NextDouble()).Take(5))
{
try
{
// Connect to the server (at port 13) and get the response
string serverResponse = string.Empty;
using (var reader = new StreamReader(new System.Net.Sockets.TcpClient(server, 13).GetStream()))
{
serverResponse = reader.ReadToEnd();
}
// If a response was received
if (!string.IsNullOrEmpty(serverResponse))
{
// Split the response string ("55596 11-02-14 13:54:11 00 0 0 478.1 UTC(NIST) *")
string[] tokens = serverResponse.Split(' ');
// Check the number of tokens
if (tokens.Length >= 6)
{
// Check the health status
string health = tokens[5];
if (health == "0")
{
// Get date and time parts from the server response
string[] dateParts = tokens[1].Split('-');
string[] timeParts = tokens[2].Split(':');
// Create a DateTime instance
utcDateTime = new DateTime(
Convert.ToInt32(dateParts[0]) + 2000,
Convert.ToInt32(dateParts[1]), Convert.ToInt32(dateParts[2]),
Convert.ToInt32(timeParts[0]), Convert.ToInt32(timeParts[1]),
Convert.ToInt32(timeParts[2]));
// Convert received (UTC) DateTime value to the local timezone
result = utcDateTime.ToLocalTime();
//return result;
return utcDateTime;
// Response successfully received; exit the loop
}
}
}
}
catch
{
// Ignore exception and try the next server
}
}
//return result;
return utcDateTime;
}
this variable result has local date time but i need to use Nodatime library where i will put my local date time variable result and also specify different timezone and Noda libraray will return local date and time of that timezone.
just guide me how to achieve it. i visit this url but still not clear how to incorporate Nodatime library and local time got from external server together to get another datetime based on different timezone.
looking for help with bit of sample code
thanks
EDIT
var wc = GetFastestNISTDate();
var pattern = InstantPattern.CreateWithInvariantCulture("dd/MM/yyyy HH:mm:ss");
var parseResult = pattern.Parse(wc.ToString("dd/MM/yyyy HH:mm:ss", CultureInfo.InvariantCulture));
if (!parseResult.Success)
throw new InvalidDataException("...whatever...");
var instant = parseResult.Value;
var timeZone = DateTimeZoneProviders.Tzdb["Europe/London"];
var zonedDateTime = instant.InZone(timeZone);
var bclDateTime = zonedDateTime.ToDateTimeUnspecified();
timezone translation is not working. i got the right date from this function GetFastestNISTDate(); and next i try to get local date and time of different timezone based on my first utc time but code return wrong time for London. i guess i am making mistake the code. can anyone see & help. thanks
EDIT 2
the samething i want to achieve by Nodatime library.
var wc = GetFastestNISTDate();
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(wc, cstZone);
the above code is giving more or less right time. just tell me how to replace my last 2 line using nodatime library. thanks
Edit 3
var wc = GetFastestNISTDate();
Instant now = Instant.FromDateTimeUtc(wc);
var timeZone = DateTimeZoneProviders.Tzdb["Europe/London"];
var zonedDateTime = instant.InZone(timeZone);
var bclDateTime = zonedDateTime.ToDateTimeUnspecified();
#John just tell me the above code is ok because u said
Don't convert the UTC DateTime to a local version - it's pointless and confusing
Use Instant.FromDateTimeUtc to convert a UTC DateTime to an instant
GetFastestNISTDate() returning datetime instance and here we just create noda instance from utc datetime using like this code `Instant now = Instant.FromDateTimeUtc(wc);`
does it solve the issue.
EDIT 4
#Matt Johnson : thanks a lot for redirecting me to a good library.
i would definitely like to work with that library to achieve my task. before
use your library i have some question.
Point 1
what was wrong you notice in this routine GetFastestNISTDate(); the routine was query few NIST time servers and get the utctime.
utcDateTime = new DateTime(
Convert.ToInt32(dateParts[0]) + 2000,
Convert.ToInt32(dateParts[1]), Convert.ToInt32(dateParts[2]),
Convert.ToInt32(timeParts[0]), Convert.ToInt32(timeParts[1]),
Convert.ToInt32(timeParts[2]));
this routine GetFastestNISTDate(); was returning utcDateTime....was not a utc time ?
Point 2
when i was calling GetFastestNISTDate(); routine i notice some time this routine was returning DateTime.MinValue which was not expected result. i could understand why it was happening because NIST time servers was busy or blocked or timeout occured at that time.
Point 3
if i use your current code/library NodaTime.NetworkClock then i like to know which NTP server it will query by default?
if i use NodaTime.NetworkClock then is there any chance that some time i may get wrong date or null date due to NTP server is busy/block or timeout occur?
EDIT 5
var instant = NetworkClock.Instance.Now;
var timeZone = DateTimeZoneProviders.Tzdb["Europe/London"];
var zonedDateTime = instant.InZone(timeZone);
lbldate.Text = zonedDateTime.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
lbltime.Text = zonedDateTime.ToString("hh:mm:ss", CultureInfo.InvariantCulture);
Your GetFastestNISTDate function uses the daytime protocol - which is essentially deprecated and NOT meant for machine interaction because its results are in no specific format. Even the docs from NIST strongly encourage users to use NTP instead of daytime.
You can find a simple C# implementation of an NTP client here.
To make things easier, I've implemented this client as a NodaTime.IClock. The code is on GitHub here. Simply install it from NuGet:
Install-Package NodaTime.NetworkClock
Then you can use it just like you would use the SystemClock:
var instant = NetworkClock.Instance.Now;
var timeZone = DateTimeZoneProviders.Tzdb["Europe/London"];
var zonedDateTime = instant.InZone(timeZone);
You shouldn't be converting the DateTime to a string and back - but your current problem is that you're converting the UTC value you get back from the server into a local DateTime for no obvious reason. Ideally, I'd suggest changing GetFastestNISTDate() to return an Instant, but assuming you can't do that:
Don't do the parsing yourself. Take the appropriate substring from the response, then use DateTime.ParseExact, specifying CultureInfo.InvariantCulture and DateTimeStyles.AssumeUniversal
Don't convert the UTC DateTime to a local version - it's pointless and confusing
Use Instant.FromDateTimeUtc to convert a UTC DateTime to an instant
The final part of your code (the last three lines) is okay, but why do you need a DateTime at all? If you can make as much of your code as possible use Noda Time, you'll get the greatest benefits in terms of code clarity.

Trouble with DateTime.ParseExact

I am working on a reminder application. The applications stores the reminder Date, Time and DateLastShown (in different fields) in the database and pulls them out to performs checks.
All dates are in "d/MM/yyyy" format. My problem is that when i pull the dates from the DB and try to store back into DateTime format they are still being shown in "M/d/yyyy" format which is not how the app needs to be.
I essentially need to pull the values from the DB do some checks to determine if it's time to show the reminder and do so. It seems rather straight forward, maybe i am making some small error.
Below is my code with comments.
Any help really appreciated.
public void CheckReminders()
{
IQueryable<Reminder> reminders;
DateTime reminderDate;
DateTime reminderTime;
DateTime reminderLastShown;
DateTime todayDate;
DateTime timeNow;
while (true)
{
try
{
db = new StudioManagementEntities();
reminders = from r in db.Reminders
select r;
foreach (Reminder r in reminders)
{
if (r.Enabled == 1)
{
if (r.Recurring == 1)
{
// This is the code i was using before when the date was in "M/d/yyyy" format
// which seems to be default.
reminderTime = DateTime.Parse(r.Time);
timeNow = DateTime.Parse(DateTime.Now.ToLongTimeString());
if (r.DateLastShown != DateTime.Today.ToShortDateString() && timeNow >= reminderTime)
{
FrmReminder frmReminder = new FrmReminder(r.Id, true);
frmReminder.ShowDialog();
r.DateLastShown = DateTime.Today.ToShortDateString();
}
}
else
{
// Now i need to pass in "d/M/yyyy" format but the
// code seems to return in "M/d/yyyy" format.
reminderDate = DateTime.ParseExact(r.Date, "d/MM/yyyy", null);
// Even this returns in wrong format
reminderDate = DateTime.ParseExact("24/01/2013", "d/MM/yyyy", null);
// Have tried with CultureInfo.InvariantCulture too.
MessageBox.Show(reminderDate.ToString());
return;
if (
r.DateLastShown != DateTime.Today.Date.ToShortDateString() //&&
//r.Date == DateTime.ParseExact(DateTime.Today, "d/MM/yyyy", CultureInfo.InvariantCulture).ToString() //&&
//now.TimeOfDay.TotalSeconds >= reminderTime.TimeOfDay.TotalSeconds
)
{
FrmReminder frmReminder = new FrmReminder(r.Id, true);
frmReminder.ShowDialog();
r.DateLastShown = DateTime.Today.ToShortDateString();
}
}
}
}
db.SaveChanges();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
// Check every minute
Thread.Sleep(60000);
}
}
And the DB table.
If the parsing into the date object is not erroring out, you are just having a problem with your output when you call .ToString().
From the docs:
The ToString method returns the string representation of the date and
time in the calendar used by the current culture.
If you need something other than the user's current culture settings, you can specify that using a format string in the overloaded ToString() method:
var reminderDate = DateTime.ParseExact("24/01/2013", "d/MM/yyyy", null);
MessageBox.Show(reminderDate.ToString("d/MM/yyyy"));
Also, as others have stated in comments, if possible you should be using the date data type in your database instead of storing the values as strings.

Converting UTC to local time returns strange result

I have a solution of three projects:
Core
Outlook Add-In
ASP.NET Website
Both, the Outlook Add-In and the Website use the same methods from Core project to get data from SQL Server. When I write my data into database, I convert all DateTime values of two tables into UTC time:
POLL_START POLL_END
2013-07-31 12:00:00.000 2013-08-01 12:00:00.000
and
PICK_DATE
2013-07-31 12:00:48.000
2013-07-31 13:00:12.000
When I get the data in my Outlook Add-In, this is the correct result:
When opening the same in my website, the picks are fine:
But my start and end time are "broken" - the offset is added, bute the wrong hours are used:
Here's the code for my converting, that both, Outlook and the website, use:
private static void ConvertToLocalTime(POLL item)
{
item.POLL_START = item.POLL_START.FromUTC();
item.POLL_END = item.POLL_END.FromUTC();
}
private static void ConvertToLocalTime(PICK pick)
{
if (pick.PICK_DATE != null) pick.PICK_DATE = ((DateTime)pick.PICK_DATE).FromUTC();
}
And the implementation of DateTime.FromUtc():
public static DateTime FromUTC(this DateTime value)
{
var local = TimeZoneInfo.Local;
return TimeZoneInfo.ConvertTime(value, TimeZoneInfo.Utc, local);
}
I had the same result with DateTime.ToLocalTime().
Anyone an idea?
EDIT 1:
This is how the start and end gets displayed on the website (end with End instead of Start):
var startCell = new TableCell
{
Text = String.Format(
#"<a href='{0}' title='{2}' target='_blank'>{1:dd.MM.yyyy HH:mm \U\T\Czzz}</a>",
Common.GetTimeAndDateHyperlink(_poll.Start, "Vote Start"),
_poll.Start,
ConvertToLocalTimeZone),
CssClass = "InfoContent"
};
And the picks:
answerCell = new TableCell
{
Text = String.Format(
#"<a href='{0}' title='{2}' target='_blank'>{1}</a>",
Common.GetTimeAndDateHyperlink(ao.Time, ao.RealAnswer),
ao.RealAnswer,
ConvertToLocalTimeZone)
};
ao.RealAnswer returns the formated DateTime string:
return String.Format(WholeTime == true ? "{0:d}" : #"{0:dd.MM.yyyy HH:mm \U\T\Czzz}", Time);
I solved the issue now. The DateTime values for start and end didn't get correctly converted: The values weren't casted to local time.
The reason, why the website displayed the time as local time is, that the SQL server stores every DateTime value as DateTimeKind.Unspecified instead of keeping the specified data (e.g. DateTimeKind.Utc) during the insert. When reading the data from the server, all Kinds are DateTimeKind.Unspecified, so the .ToString() of DateTime uses the local kind. This results into the UTC time + local UTC offset.

Categories