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

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);

Related

How to convert Server Date time to Indian Standard Time?

I have WebApp deployed on US server. I have used DateTime.Now in order to capture User Date and Time on certain Action by the User.
Localy it works fine and gets the Date time correct. But post the deployment function is saving the date time for the Server Date time and not the User.
Users are in India hence it should capture IST and not MST as what it is doing now.
Here is my Code I have used so far with no success:
//Getting the current UTC Time
DateTime UTCTime = System.DateTime.UtcNow;
//Adding the time difference 5.5 hours to the utc time
DateTime IndianTime = UTCTime.AddHours(5.5);
dto.ChatCreateDateTime = IndianTime;
Using TimeZone Class did not work either.
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
DateTime timeUTC = DateTime.UtcNow;
DateTime result = TimeZoneInfo.ConvertTimeFromUtc(timeUTC, timeZone);
dto.ChatCreateDateTime = result;
I did try searching online and tried many fix like TimeZone Class, and other but none worked for me.
Use the below code but no correct datetime. Time shows as behind by 30 mins.
DateTime dateTime = DateTime.Now;
DateTime utcTime = dateTime.ToUniversalTime();
TimeZoneInfo istZone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
DateTime yourISTTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, istZone);
model.ChatCreateDateTime = yourISTTime;
Chat dto = new Chat();
//dto.CustEmail = model.CustEmail;
dto.CustName = model.CustName;
dto.ChatStartDateTime = model.ChatStartDateTime;
// Gets current local date
// Returns 04/09/12 11:30 in my case
dto.ChatStartDateTime = model.ChatStartDateTime;
Thank you in advance.
If you want to convert time from UTC to any specific Time Zone
you should try follwing way.
DateTime dateTime = DateTime.Now; // I am getting date time here
DateTime utcTime = dateTime.ToUniversalTime(); // From current datetime I am retriving UTC time
TimeZoneInfo istZone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time"); // Now I am Getting `IST` time From `UTC`
DateTime yourISTTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime, istZone); // Finally converting it
var hourIST = yourISTTime.Hour; // More granular extraction.
Output:
Note:
I am trying this way and perfectly working for me. If you require
further modification and granularity you could check our official document here.

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.

How to get DateTime with a UTC datetime and a particular timezone?

My data in SQL database looks like this:
PubDateUTC PubDateUTCOffset
----------------------- --------------------
2011-08-04 10:02:50.000 +8:00:00
2012-04-23 02:32:25.287 +8:00:00
2010-09-26 04:23:00.000 +8:00:00
What I want is to get a DateTime based on PubDateUTC and PubDateUTCOffset, for example:
2011-08-04 10:02:50.000, +8:00:00 should result in 2011-08-04 18:02:50:000
I have tried with TimeZoneInfo class, but I don't know hot to create a instance of TimeZoneInfo with a string like "+8:00:00", which would be the CreateTimeZoneInfo method below
var tz = CreateTimeZoneInfo(post.PubDateUTCOffset);
return TimeZoneInfo.ConvertTimeFromUtc(post.PubDateUTC, tz);
Is there anyway to do this?
Note: I cannot change the data in SQL database.
You could try something like:
var date = post.PubDateUTC.Add(
TimeSpan.Parse(post.PubDateUTCOffset.Replace("+", ""))
);
The .Replace("+", "") is because TimeSpan will handle -01:00:00 but will choke on +01:00:00
I think you need to use DateTimeOffset class. This thread may be helpful.
http://msdn.microsoft.com/en-us/library/bb546101.aspx
This works, remove any leading "+" from the offset ( "-" are ok)
var d = new DateTimeOffset(DateTime.Parse("2011-08-04 10:02:50.000"),
TimeSpan.Parse("08:00:00"));
d.DateTime - the time in db = 10:02:50
d.LocalDateTime - the time according to your servers timezone
d.UtcDateTime - the time at GMT = 02:02:50
I'm not sure you want 18:02:50 since it is the time at GMT+16 (+16:00:00), unless of course that is how it's encoded in the db, then just ignore this post :)
You should change your post class to have one property:
public DateTimeOffset Published { get; set; }
Then when you read from the database (assuming you have datetime and varchar types in your database):
DateTime utc = DateTime.SpecifyKind(
(DateTime) reader["PubDateUTC"], DateTimeKind.Utc);
TimeSpan offset = TimeSpan.Parse(
((string) reader["PubDateUTCOffset"]).Replace("+", ""))
post.Published = new DateTimeOffset(utc).ToOffset(offset);
Then when you need to consume it, you have all of the options of a full DateTimeOffset:
DateTime local = post.Published.DateTime; // with your offset applied
DateTime utc = post.Published.UtcDateTime; // the original utc value
string s = post.Published.ToString("o"); // 2011-08-04T18:02:50.0000000+08:00

Parsing user input including tz database time zone name

I'm attempting to parse user input with Noda Time.
Input:
Date in the form of YYYY-MM-DD
Hour
Minute
tz database time zone name (returned from Google's Time Zone API)
I need to convert this data to UTC and to other time zones, also based on a tz database time zone name.
Currently I'm trying to make sense of the LocalDateTime and ZonedDateTime differences, but perhaps someone is able to show how to do this before I'd (hopefully) figure this out.
Your answer is pretty close to what I'd do - but if you have the date, hour and minute in separate strings, I'd use:
var zoneProvider = DateTimeZoneProviders.Tzdb;
var sourceZone = zoneProvider.GetZoneOrNull("Europe/Brussels");
var targetZone = zoneProvider.GetZoneOrNull("Australia/Melbourne");
if (sourceZone == null || targetZone == null)
{
Console.WriteLine("Time zone not found");
return;
}
var dateParseResult = LocalDatePattern.IsoPattern.Parse(date);
int hourValue, minuteValue;
if (!dateParseResult.Success ||
!int.TryParse(hour, out hourValue) ||
!int.TryParse(minute, out minuteValue))
{
Console.WriteLine("Parsing failed");
return;
}
var localDateTime = dateParseResult.Value + new LocalTime(hour, minute);
var zonedDateTime = localDateTime.InZoneStrictly(sourceZone);
Console.WriteLine(zonedDateTime.ToInstant());
Console.WriteLine(zonedDateTime);
Console.WriteLine(zonedDateTime.WithZone(targetZone));
The only significant difference here is the parsing - I wouldn't stick all the bits together; I'd just parse the strings separately. (I also prefer "early outs" for failures :)
You should note the meaning of InZoneStrictly though - do you definitely want to fail if the input local date/time is ambiguous?
http://msmvps.com/blogs/jon_skeet/archive/2012/02.aspx has great information, and while it's slightly outdated it's easy to find the relevant method names in the official documentation.
Below is some demonstration code.
string date = "2013-01-22";
string hour = "13";
string minute = "15";
var result = LocalDateTimePattern.ExtendedIsoPattern.Parse(date + "T" + hour + ":" + minute + ":00");
if (result.Success == true)
{
DateTimeZone source_zone = DateTimeZoneProviders.Tzdb.GetZoneOrNull("Europe/Brussels");
DateTimeZone target_zone = DateTimeZoneProviders.Tzdb.GetZoneOrNull("Australia/Melbourne");
if (source_zone != null && target_zone != null)
{
ZonedDateTime source_zoned_dt = result.Value.InZoneStrictly(source_zone);
Console.WriteLine(source_zoned_dt.ToInstant());
Console.WriteLine(source_zoned_dt);
Console.WriteLine(source_zoned_dt.WithZone(target_zone));
}
else
{
Console.WriteLine("time zone not found");
}
}
else
{
Console.WriteLine("parsing failed");
}

.net client server with different timezones

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.

Categories