Metro Apps TimeZoneInfo alternative - c#

I would like to make a simple calculation but not sure how to approach this using c# for metro apps since TimeZoneInfo does not have most of the functionality it used to for other type of applications not metro.
How can I convert my current machine time to UTC time? It is probably something simple that was now made complicated and I do not understand.
Was trying to use
TimeZoneInfo time = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
Which is where the server is, and then trying to convert my machine time to that, but no luck since I do not have that functionality. I checked out those WINRT something libraries, but I do not really like those. Is there an easier way? (keep in mind the current machine time could be in Australia, Europe, United States.
Maybe I can get the offset of utc from local (but how to I get the time in central?) and then the utc offset of central. I am not sure it is confusing.

You can get the local timezone with TimeZoneInfo.Local . What you can't get is arbitrary other timezones: only local and Utc.
TimeZoneInfo.BaseUtcOffset will give the time difference between the current time zone and UTC.
TimeZoneInfo local = TimeZoneInfo.Local;
TimeZoneInfo utc = TimeZoneInfo.Utc;
Debug.WriteLine("Local TimeZone is {0} offset from UTC:{2}", local,utc,local.BaseUtcOffset);
DateTime localTime = DateTime.Now;
DateTime utcTime = DateTime.UtcNow;
Debug.WriteLine("It is now {0} (UTC: {1})", localTime, utcTime);
Results:
Local TimeZone is (UTC-08:00) Pacific Time (US & Canada) offset from UTC:-08:00:00
It is now 10/09/2014 14:59:07 (UTC: 10/09/2014 21:59:07)

Related

Is there a way to convert from timezone format (America/Chicago) to UTC (-0500) in C# .net?

I'm being provided a set of timezone names and need to use them as UTC offsets. Is there a way to make this conversion to get the current UTC offset (including appropriate DST shift)?
This is what the TimeZoneInfo.GetUtcOffset method is designed to accomplish.
DateTime utcNow = DateTime.UtcNow;
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("America/Chicago");
TimeSpan offset = tz.GetUtcOffset(utcNow);
The above will work if you are running .NET on Linux or Mac OSX, and in the future (starting with .NET 6) will work on Windows.
If you are running .NET on Windows today, you can use my TimeZoneConverter library which will internally convert the IANA time zone ID to a Windows time zone ID when getting a TimeZoneInfo object.
DateTime utcNow = DateTime.UtcNow;
TimeZoneInfo tz = TZConvert.GetTimeZoneInfo("America/Chicago");
TimeSpan offset = tz.GetUtcOffset(utcNow);

How to get convert server time to local time and deal with daylight saving time

I host my website (asp.net webforms, .Net 4.5, SQL Server 2012) on Godaddy and they (the server) use Mountain Standard Time (-7 compare to UTC time) which is never changed and does not observe daylight saving time.
So if I do
Response.Write("UTC Time: " + DateTime.UtcNow.ToString() + "<br/>");
Response.Write("Server Time: " + DateTime.Now.ToString() + "<br/>");
Response.Write("Server DateTimeOffset: " + DateTimeOffset.Now.ToString() + "<br/>");
It will display this:
UTC Time: 9/18/2015 5:14:09 PM
Server Time: 9/18/2015 10:14:09 AM
Server DateTimeOffset: 9/18/2015 10:14:09 AM -07:00
But my users are located in Atlanta, GA which does observe daylight saving time and according to timeanddate.com they use EDT in the summer and EST in the winter
How do I get correct current time of user? Let say user open my web-application and hit Show my time button, it will display a correct current user's time?
You should never rely on the time zone settings of a server. Therefore DateTime.Now should not be ever used in an ASP.NET application.
There are many other reasons to avoid DateTime.Now. Read:The case against DateTime.Now.
The local time of the server is never guaranteed to be the local time of the user of your website anyway. If it is, it's just coincidental.
The easiest way to get the user's current time in their time zone is via JavaScript:
var now = new Date();
Though this is based on the user's clock, which may or may not be correctly set. To have any guarantees about the time, you'd have to use the UTC time of the server's clock, with the user's time zone applied.
One approach you might consider is to send the UTC time of the server down to the client, then load that into JavaScript in the client to project it to their time zone:
// C#
string serverUtcTime = DateTime.UtcNow.ToString("o"); // "2015-09-18T17:53:15.6988370Z"
// JS
var now = new Date("2015-09-18T17:53:15.6988370Z");
Actually detecting the user's time zone is a hard problem that does not currently have a solution. Some may recommend new Date().getTimezoneOffset(), but that only gives you the current numeric offset, not the time zone. Offsets can change for DST, and many time zones use similar offsets. There are also complications for historical dates near DST transitions that will work against you.
Scripts like jsTimeZoneDetect can guess your IANA time zone ID, such as America/New_York for Eastern time, but they are not 100% accurate. If you need the user's time zone on your server, then ultimately should ask the user for their time zone somewhere in your application.
In .NET, you can use Noda Time to work with IANA time zones. Without Noda Time, .NET has the TimeZoneInfo class, but it can only work with Windows time zones.
If you know for certain that the users are in Atlanta, GA (which is in the US Eastern time zone), then you can do this:
DateTime utc = DateTime.UtcNow;
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime eastern = TimeZoneInfo.ConvertTimeFromUtc(utc, tz);
Or, with Noda Time and IANA time zone IDs:
Instant now = SystemClock.Instance.Now;
DateTimeZone tz = DateTimeZoneProviders.Tzdb["America/New_York"];
ZonedDateTime eastern = now.InZone(tz);
You can use TimeZoneInfo.ConvertTime to convert from one time zone to another. However, if you just convert to EST or EDT, it will always display that value. If you want to always display the correct time for the client, you'll need to do something like using Javascript to store the client browser's local time zone in a cookie, then use that value as the time zone to convert to.
It might be a little more streamlined to get UtcTime from the server and convert from that using TimeZoneInfo.ConvertTimeFromUtc, if you expect to do much of this. Basically the same process, though.
Take a look at this example. This is quite easy.
[Test, TestCase(1), TestCase(9)]
public void Test(int month)
{
var serverTime = new DateTime(2015, month, 18, 10, 14, 09);
// No Daylight saving in Russia
var serverTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Russian Standard Time");
// Daylight saving in Atlanta
var localTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Atlantic Standard Time");
// check if ConvertTime take care of daylight saving
var localTime = TimeZoneInfo.ConvertTime(serverTime, serverTimeZone, localTimeZone);
// it does
if (localTimeZone.IsDaylightSavingTime(localTime))
Assert.AreEqual(string.Format("{0}/18/15 04:14 AM", month), localTime.ToString("M/dd/yy hh:mm tt", System.Globalization.CultureInfo.InvariantCulture));
else
Assert.AreEqual(string.Format("{0}/18/15 03:14 AM", month), localTime.ToString("M/dd/yy hh:mm tt", System.Globalization.CultureInfo.InvariantCulture));
}

Correct approach to getting the universal time zone

In my project I want to get the universal time zone. I used two different kinds of approaches but I don't know which one is the best practice.
First approach is
public static DateTime GetUniversalTime(DateTime localDateTime)
{
TimeZone zone = TimeZone.CurrentTimeZone;
DateTime universal = zone.ToUniversalTime(localDateTime);
return universal;
}
then I want revert to local time I used the below method:
public static DateTime GetLocalTime(DateTime universalDateTime)
{
TimeZone zone = TimeZone.CurrentTimeZone;
DateTime local = zone.ToLocalTime(universalDateTime);
return local;
}
and second approach is get universal time zone DateTime.UtcNow;
then I want to revert to local time I used the above GetLocalTime method.
Can one explain what is the different between the above two approaches?
Which one is the best practice ?
Since you are asking about best practices:
Do not use the TimeZone class. If you need time zone conversions, use the TimeZoneInfo class instead. This is very clear in the MSDN documentation:
Whenever possible, avoid any use of "local" time. It is local to the system where the code is running. In the vast majority of real-world use cases, it is likely that it is not the local time zone of your user. This is especially true in a web application.
That means you should not be calling any of the following:
DateTime.Now
TimeZone.CurrentTimeZone
TimeZoneInfo.Local
DateTime.ToLocalTime()
DateTime.ToUniversalTime()
Any other method that involves the server's local time zone.
Instead, your application should allow the user to select a time zone, then you can convert to and from the local time in that zone using the TimeZoneInfo.Convert... methods.
If you need the current universal time, use DateTime.UtcNow or DateTimeOffset.UtcNow.
If you need the current local time zone of your server, ONLY use DateTimeOffset.Now.
If you need the current local time in a known time zone, such as US Eastern Time:
DateTime easternNow = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(
DateTime.UtcNow, "Eastern Standard Time");
If you want to convert between a known time zone and UTC, then use the TimeZoneInfo.ConvertTimeToUtc and TimeZoneInfo.ConvertTimeFromUtc methods, and be sure to pass in the time zone you are converting to/from:
// get the local time zone of your user, not of the server!
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
// use this to convert from UTC to local
DateTime local = TimeZoneInfo.ConvertTimeFromUtc(yourUtcDateTime, tzi);
// use this to convert from local to UTC
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(yourLocalDateTime, tzi);
Be aware that when you convert from local to UTC, you might encounter ambiguities during daylight saving time transitions. Read more in the DST tag wiki.
Additional reading: The Case Against DateTime.Now
For Universal Time.
DateTime.Now.ToUniversalTime()
For Local Time
DateTime.UtcNow.ToLocalTime()
Universal To Local
var nowUtc = DateTime.Now.ToUniversalTime();
var nowLocal = nowUtc.ToLocalTime();

Convert US-Style DateTime to local time

How do I convert US-style DateTime such as 5/1/2012 3:38:27 PM returned from the server to user's local time? I am developing for windows phone.
I've tried
DateTime localTime = serverTime.ToLocalTime();
but the result is off a couple of hours. I thought ToLocalTime() will take care of the conversion to any timezone the user are in? Perhaps I need to get the user's timezone info first?
EDIT 1
I think the serverTime is in the PST time zone
EDIT 2
My timezone is GMT +8. I tried the following, but the resulting localTime is 15 hour behind.
TimeZoneInfo localZone = TimeZoneInfo.Local;
DateTime localTime = TimeZoneInfo.ConvertTime(serverTime, localZone);
EDIT 3
This result in 7 hours behind my local time.
TimeZoneInfo localZone = TimeZoneInfo.Local;
DateTime dateTimeKind = DateTime.SpecifyKind(serverTime, DateTimeKind.Utc);
DateTime localTime = TimeZoneInfo.ConvertTime(dateTimeKind, localZone);
EDIT 4
OK I think I am getting there but not sure if this is applicable for all time zones. I think I still have to consider day light saving because the resulting local time is just one hour ahead now.
TimeZoneInfo localZone = TimeZoneInfo.Local;
double offset = localZone.GetUtcOffset(DateTime.Now).TotalHours;
DateTime dateTimeKind = DateTime.SpecifyKind(serverTime, DateTimeKind.Utc);
DateTime localTime = TimeZoneInfo.ConvertTime(dateTimeKind, localZone).AddHours(offset);
But then how do you get DLS is in effect for a particular time zone in Windows Phone? TimeZoneInfo.FindSystemTimeZoneById does not seem to be supported?
For this to work, the DateTime-object serverTime must be of the UTC-form - or at least know what Kindit is. Read all the details around this under the remarks section of this page.
Best of luck!
What does the time represent? If it is a specific moment in time, such as the date and time that something happened, then you should update your server code to return the time in one of the following formats:
// ISO8601 local time with offset.
// get from DateTimeOffset.ToString("o")
2012-05-01T15:38:27-07:00
// ISO8601 UTC time
// get from DateTime.ToString("o") when kind is UTC
2012-05-01T22:38:27Z
It's really important that you do this, because local times can be ambiguous when daylight savings ends. You must either provide the correct offset, (-8 for PST, -7 for PDT), or send as UTC.
There are very few scenarios where sending local time by itself makes sense. If you think you have one, please elaborate about what the time represents.

Specify a date in another timezone C#

I've got an asp.net application that must run some code every day at a specific time in the Eastern Time Zone (DST aware). So my first thought is, get the eastern time value and convert it to local server time.
So I need something like this:
var eastern = DateTime.Today.AddHours(17); // run at 5pm eastern
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var utc = TimeZoneInfo.ConvertTimeToUtc(eastern, timeZoneInfo);
var local = TimeZoneInfo.ConvertTimeFromUtc(utc, TimeZoneInfo.Local);
But how do I specify that the eastern DateTime object should be in the EST timezone.
Am I approaching this the wrong way?
First, there are several things you have to consider. You have to deal with Daylight Savings Time, which from time to time seems to change (the start and end dates have changed twice in the last 10 years). So in the Northern Hemisphere Winter, Eastern time is -5 GMT (or UTC). But, in the Summer it's -6 GMT or is that -4 GMT, I can never keep it straight (nor should I have to).
There are some DNF library functions to deal with time zone information, however you really need .net 3.5 for the most useful stuff. There's the TimeZoneInfo class in .net 3.5.
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime dt = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(DateTime.Now,
TimeZoneInfo.IsDaylightSavingsTime(tzi) ?
tzi.DaylightName : tzi.StandardName);
if (dt.Hour == 17)
....
Also, keep in mind that twice every year an hour is lost or gained, so you also have to account for that if, for example, you have a countdown timer you display "time until next processing" or something like that. The fact is, time handling is not as easy as it would seem at first thought, and there are a lot of edge cases.
Seems I was able to answer my own question. Here's the code I'm using to get a next-run DateTime object.
private DateTime GetNextRun()
{
var today = DateTime.Today;
var runTime = new DateTime(today.Year, today.Month, today.Day, 17, 0, 0);
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var offset = timeZoneInfo.GetUtcOffset(runTime);
var dto = new DateTimeOffset(runTime, offset);
if (DateTime.Now > dto.LocalDateTime)
dto = dto.AddDays(1);
return dto.LocalDateTime;
}
Doing all the conversion using DateTimeOffset instead of DateTime proved effective. It even seems to handle Daylight Savings Time correctly.
A DateTime doesn't know about a time zone. Even DateTimeOffset doesn't really know about a time zone - it knows about a UTC instant and an offset from that.
You can write your own struct which does have a TimeZoneInfo and a DateTime, but I'm not sure you need it in this case. Are you just trying to schedule 5pm in Eastern time, or is this actually more general? What are you doing with the DateTime (or whatever) afterwards? Using DateTimeOffset and TimeZoneInfo you can definitely get the UTC instant of the time you're interested in; if you just need to know the time between "now" and then, that's fairly easy.
I feel duty-bound to point out that when Noda Time is production-ready, it would almost certainly be the right answer :)
You could use the DateTime.UtcNow to get UTC central time(which I believe is GMT 0) and from htere on just figure out how many time zones the one you want is and remove/add an hour for each zone.

Categories

Resources