I am trying to control Daylight saving in a C# application instead of letting windows do it. (I won't come into the reason here).
So I have removed the checkmark "Automatically adjust clock for daylight saving" in Date and Time settings (Windows7)
I have written this small piece of code in order to demonstrate the problem that I am facing.
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.Id);
// "Romance Standard Time"
var rule = tzi.GetAdjustmentRules()[0];
System.Globalization.CultureInfo.CurrentCulture.ClearCachedData();
var timestampToWorkOn = DateTime.Now;
Console.WriteLine("Timezone is: " + tzi.ToString());
Console.WriteLine("Timezone id is: " + tzi.Id);
Console.WriteLine("Timestamp right now: " + timestampToWorkOn.ToString("yyyy-MM-dd HH:mm"));
Console.WriteLine("Rule for change says: " + rule.DaylightTransitionEnd.TimeOfDay.ToString("HH:mm"));
Console.WriteLine("Is it dst: " + tzi.IsDaylightSavingTime(timestampToWorkOn));
Console.WriteLine("Is it ambiguous:" + tzi.IsAmbiguousTime(timestampToWorkOn));
As the transition from dst to normal time is supposed to happen at 3:00 I would suspect that the time from 2:00 to 3:00 would be Ambiguous.
But the result from running the code at 1:54 is:
Timezone is: (UTC+01:00) Brussels, Copenhagen, Madrid, Paris
Timezone id is: Romance Standard Time
Timestamp right now: 2013-10-27 01:54
Rule for change says: 03:00
Is it dst: False
Is it ambiguous:True
I might be missing something.
I would expect dst to be true and ambiguous to be false, but it is the opposite way around.
It's hard to keep an overview but why am I seeing this behavior?
You should read this blog post, which describes in detail how the Windows registry settings are affected by the time zone selection and the "Automatically adjust..." checkbox. It also describes how TimeZoneInfo uses these settings. Specifically, it states:
When daylight saving time is disabled for the local time zone, TimeZoneInfo.Local will return a TimeZoneInfo object with TimeZoneInfo.SupportsDaylightSavingTime set to False. Any TimeZoneInfo.ConvertTime(...) calls using this TimeZoneInfo instance will not take daylight saving time into account.
IMHO, there is never a good reason to clear that checkbox and disable DST. It puts the computer's clock in an artificial reality.
If you are running code on a server, you should probably set the server's time zone to UTC. This will keep Windows from having to update the computer's bios for the transition, and will let local timestamps from other servers all line up.
Regarding your code, realize that the result of DateTime.Now has .Kind == DateTimeKind.Local, and has no bearing on the time zone you used earlier. You happened to be reporting the local time zone, but if you used a different one, your code would be incorrect.
When you are getting the adjustment rules, you are assuming the local time zone will have one. Some (like Arizona) do not have any DST, so they have no adjustment rules and you get an index out of bounds exception (because of the [0]).
Also, just being nitpicky but,
// This line is self redundant.
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.Id);
// It can be reduced to:
TimeZoneInfo tzi = TimeZoneInfo.Local;
But the real problem is that because you have the "adjust for DST" option turned off, the DateTime is not being converted to the right UTC moment in order to make the determination if it is ambiguous or not. If you drill in to the .Net source code (decompiled or symbolsource) for DateTime.IsAmbiguousTime(), you will find that it uses TimeZoneInfo.ConvertTime(), which (per the earlier quote) does not take DST into account when the box is unchecked, thus making the result incorrect (essentially 1 hour off).
You should also look at the MSDN notes for TimeZoneInfo.IsAmbiguousTime, which describe how the Kind of the input affects the output result.
Related
This seems so basic but I've been researching this (here, other sites, Microsoft documentation, etc.) and working on it for months. I'm just not getting the problem.
I have a program that uses DateTime a lot. It worked great before DST last fall. Then everything stopped working well - seems like everything's off by an hour now. I compensated with DateTime.Now.AddHours() but that's only a band aid.
I've tried DateTimeOffset.Now, DateTime.ToLocalTime, DateTime.UTCNow, etc. It just won't use system time or compensate.
I'm in Pacific Standard time and nobody will ever use this site outside of this time zone if that's another way to approach it.
Anyone have any thoughts on why this is happening? The whole program is doing it, but I'll give a little snippit of one of the areas.
<table class="table-bordered" id="table_lunch" style="width:15em;">
#*populate the table with only those breaks that lack a TimeCleared value*#
#if (ViewBag.Lunches != null)
{
foreach (var item in modelOrdered)
{
if (DateTimeOffset.Now.AddHours(-1) >= item.LunchTime.AddMinutes(-1) && DateTimeOffset.Now.AddHours(-1) <= item.LunchTime.AddMinutes(1))
{
if (item.EmpSent == false)
{
<tr class="listTime">
#*Make each name clickable - deletes the lunch*#
<td class="LunchIdNumber">
#if (item.LongerLunch == false && item.Double == false)
{
<input type="hidden" class="hiddenLunchID" value="#item.LunchID" />
#item.Employee.DisplayName
It's really hard to answer your question without a minimal, reproducible example, but I will make an attempt.
In your code, by using DateTimeOffset.Now you are using the system's local time zone as a basis of comparison. Instead, you should get the time in a specific time zone before making your comparison:
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
DateTimeOffset now = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, tzi);
Then you can use now in your comparison and it will reflect the current time in the Pacific time zone, both when DST is in effect and when it is not.
Note that I inferred a few things from your question, comments, and symptoms you described:
Your item.LunchTime is a DateTime type. If it's actually a DateTimeOffset type, then the comparison would be made correctly regardless of time zone. In other words, DateTime comparison is based on the date and time as presented while DateTimeOffset comparison is based on the equivalent UTC timestamp.
Your server is a Windows server. I believe GoDaddy only uses Plex for it's Windows hosting (from what I could gather from searching their documentation).
Because you said everything worked until last fall, I assume you meant it worked until DST ended. In other words, while Pacific Time was UTC-7 the value you got from DateTimeOffset.Now was what you expected, but when Pacific Time returned to UTC-8, you still got values with a UTC-7 offset as before.
If that last point is correct, then likely your server is set for Arizona rather than for Pacific Time. Since GoDaddy is an Arizona-based company, this is plausible.
It may or may not be possible to change the system's time zone depending on how much of the hosting environment GoDaddy has exposed. I can see from Plesk's docs that they do indeed give a Date and Time settings panel - but I'm not sure whether GoDaddy exposes it to you or not.
Again, my recommendation would be to ignore the system-local time zone and not try to change it. Instead, alter your code to use a specific time zone as shown. Put it in a helper function somewhere in your code if that makes it easier to use throughout your applicaiton.
We are developing a C# application for a web-service client. This will run on Windows XP PC's.
One of the fields returned by the web service is a DateTime field. The server returns a field in GMT format i.e. with a "Z" at the end.
However, we found that .NET seems to do some kind of implicit conversion and the time was always 12 hours out.
The following code sample resolves this to some extent in that the 12 hour difference has gone but it makes no allowance for NZ daylight saving.
CultureInfo ci = new CultureInfo("en-NZ");
string date = "Web service date".ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
As per this date site:
UTC/GMT Offset
Standard time zone: UTC/GMT +12 hours
Daylight saving time: +1 hour
Current time zone offset: UTC/GMT +13 hours
How do we adjust for the extra hour? Can this be done programmatically or is this some kind of setting on the PC's?
For strings such as 2012-09-19 01:27:30.000, DateTime.Parse cannot tell what time zone the date and time are from.
DateTime has a Kind property, which can have one of three time zone options:
Unspecified
Local
Utc
NOTE If you are wishing to represent a date/time other than UTC or your local time zone, then you should use DateTimeOffset.
So for the code in your question:
DateTime convertedDate = DateTime.Parse(dateStr);
var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified
You say you know what kind it is, so tell it.
DateTime convertedDate = DateTime.SpecifyKind(
DateTime.Parse(dateStr),
DateTimeKind.Utc);
var kind = convertedDate.Kind; // will equal DateTimeKind.Utc
Now, once the system knows its in UTC time, you can just call ToLocalTime:
DateTime dt = convertedDate.ToLocalTime();
This will give you the result you require.
I'd look into using the System.TimeZoneInfo class if you are in .NET 3.5. See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx. This should take into account the daylight savings changes correctly.
// Coordinated Universal Time string from
// DateTime.Now.ToUniversalTime().ToString("u");
string date = "2009-02-25 16:13:00Z";
// Local .NET timeZone.
DateTime localDateTime = DateTime.Parse(date);
DateTime utcDateTime = localDateTime.ToUniversalTime();
// ID from:
// "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zone"
// See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.id.aspx
string nzTimeZoneKey = "New Zealand Standard Time";
TimeZoneInfo nzTimeZone = TimeZoneInfo.FindSystemTimeZoneById(nzTimeZoneKey);
DateTime nzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, nzTimeZone);
TimeZone.CurrentTimeZone.ToLocalTime(date);
DateTime objects have the Kind of Unspecified by default, which for the purposes of ToLocalTime is assumed to be UTC.
To get the local time of an Unspecified DateTime object, you therefore just need to do this:
convertedDate.ToLocalTime();
The step of changing the Kind of the DateTime from Unspecified to UTC is unnecessary. Unspecified is assumed to be UTC for the purposes of ToLocalTime: http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx
I know this is an older question, but I ran into a similar situation, and I wanted to share what I had found for future searchers, possibly including myself :).
DateTime.Parse() can be tricky -- see here for example.
If the DateTime is coming from a Web service or some other source with a known format, you might want to consider something like
DateTime.ParseExact(dateString,
"MM/dd/yyyy HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)
or, even better,
DateTime.TryParseExact(...)
The AssumeUniversal flag tells the parser that the date/time is already UTC; the combination of AssumeUniversal and AdjustToUniversal tells it not to convert the result to "local" time, which it will try to do by default. (I personally try to deal exclusively with UTC in the business / application / service layer(s) anyway. But bypassing the conversion to local time also speeds things up -- by 50% or more in my tests, see below.)
Here's what we were doing before:
DateTime.Parse(dateString, new CultureInfo("en-US"))
We had profiled the app and found that the DateTime.Parse represented a significant percentage of CPU usage. (Incidentally, the CultureInfo constructor was not a significant contributor to CPU usage.)
So I set up a console app to parse a date/time string 10000 times in a variety of ways. Bottom line:
Parse() 10 sec
ParseExact() (converting to local) 20-45 ms
ParseExact() (not converting to local) 10-15 ms
... and yes, the results for Parse() are in seconds, whereas the others are in milliseconds.
I'd just like to add a general note of caution.
If all you are doing is getting the current time from the computer's internal clock to put a date/time on the display or a report, then all is well. But if you are saving the date/time information for later reference or are computing date/times, beware!
Let's say you determine that a cruise ship arrived in Honolulu on 20 Dec 2007 at 15:00 UTC. And you want to know what local time that was.
1. There are probably at least three 'locals' involved. Local may mean Honolulu, or it may mean where your computer is located, or it may mean the location where your customer is located.
2. If you use the built-in functions to do the conversion, it will probably be wrong. This is because daylight savings time is (probably) currently in effect on your computer, but was NOT in effect in December. But Windows does not know this... all it has is one flag to determine if daylight savings time is currently in effect. And if it is currently in effect, then it will happily add an hour even to a date in December.
3. Daylight savings time is implemented differently (or not at all) in various political subdivisions. Don't think that just because your country changes on a specific date, that other countries will too.
#TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)
Don't forget if you already have a DateTime object and are not sure if it's UTC or Local, it's easy enough to use the methods on the object directly:
DateTime convertedDate = DateTime.Parse(date);
DateTime localDate = convertedDate.ToLocalTime();
How do we adjust for the extra hour?
Unless specified .net will use the local pc settings. I'd have a read of: http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx
By the looks the code might look something like:
DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year );
And as mentioned above double check what timezone setting your server is on. There are articles on the net for how to safely affect the changes in IIS.
In answer to Dana's suggestion:
The code sample now looks like:
string date = "Web service date"..ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate);
The original date was 20/08/08; the kind was UTC.
Both "convertedDate" and "dt" are the same:
21/08/08 10:00:26; the kind was local
I had the problem with it being in a data set being pushed across the wire (webservice to client) that it would automatically change because the DataColumn's DateType field was set to local. Make sure you check what the DateType is if your pushing DataSets across.
If you don't want it to change, set it to Unspecified
I came across this question as I was having a problem with the UTC dates you get back through the twitter API (created_at field on a status); I need to convert them to DateTime. None of the answers/ code samples in the answers on this page were sufficient to stop me getting a "String was not recognized as a valid DateTime" error (but it's the closest I have got to finding the correct answer on SO)
Posting this link here in case this helps someone else - the answer I needed was found on this blog post: http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetimeparse-doesnt-work/ - basically use DateTime.ParseExact with a format string instead of DateTime.Parse
This code block uses universal time to convert current DateTime object then converts it back to local DateTime. Works perfect for me I hope it helps!
CreatedDate.ToUniversalTime().ToLocalTime();
I'm trying to get the difference between an application running on Windows Embedded 7 and UTC time. To do that I have the following piece of code:
TimeZoneInfo utcTimeZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTime localTime = DateTime.Now;
DateTime utcTime = TimeZoneInfo.ConvertTime(localTime, TimeZoneInfo.Local, utcTimeZone);
TimeSpan utcOffset = localTime - utcTime;
This runs fine on my own development PC, running Windows 7. However, when I install my application on a device running Windows Embedded 7, no matter what timezone I set it to, when I run my application,
The value for TimeZoneInfo.Local.BaseUtcOffset is always 00:00.
The BaseUtcOffset value in the object returned by TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time") is also 00:00 (though this is to be expected).
The ConvertTime() function above always returns the current time less one hour. (Kind of not surprised since the TimeZoneInfo.Local.SupportsDaylightSavingsTime value is always false.)
Should I be using another way that TimeZoneInfo.Local to get the offset between UTC and the current time zone? I need to include Daylight Savings in this.
A few things:
The time zone with the ID "GMT Standard Time" is not UTC - it's UK Time. Its display name matches "Dublin, Edinburgh, Lisbon, London". It uses UTC+0 in the winter, and UTC+1 in the summer for daylight saving time.
The UTC time zone ID is simply "UTC" - though you'll rarely need that.
If TimeZoneInfo.Local.BaseUtcOffset is zero, then that means the computer's time zone setting is one that has UTC+0 as its standard offset. There are four of those currently defined in Windows. This property does not reflect daylight saving time.
Recognize that offsets will change depending on what time of the year that you are running the code. A time zone is not the same as a time zone offset.
Since you said you got zero in your above code, I'd guess that your local time zone is either the previously mentioned UK Time, or Casablanca, Morocco. This is because you are subtracting a UTC+1 local time with the time from another time zone that is also UTC+1 presently. 1 - 1 = 0
The correct way to do this does not involve subtraction at all. Simply use the GetUtcOffset method:
TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now);
Again, note that this returns the current offset. Running it at different times of the year, or by passing a different value instead of DateTime.Now could return a different result.
I have an application that converts local time to UTC and stores it in the database. I encountered this problem while I was testing the conversion during a particular date - 1st November, 2015(the date on which the Daylight savings time ends(the clock goes back to 1.00AM on reaching 2.00AM)).
My local system timezone is (UTC-08:00) Pacific Time (US & Canada)
I converted the time 2015-10-31 01:49:00.000 to UTC, the output was 2015-10-31 08:49:00.000.
but
when I tried to convert 2015-11-01 01:49:00.000 to UTC, the output was 2015-10-31 09:49:00.000.
Isn't this wrong? why did the converted time increase by an hour on 1st November?
This is my method,
DateTime universalFormatDateTime = localDateTime.Value.GetUniversalFormatDateTime();
utcDateTime = TimeZoneInfo.ConvertTimeToUtc(universalFormatDateTime, _timeZoneInfo);
Isn't this wrong? why did the converted time increase by an hour on 1st November?
Because that's when the clocks change, as you say.
The problem is that "2015-11-01 01:49:00.000" is ambiguous in Pacific Time - it occurs twice, once at 2015-11-01T08:49:00Z and once at 2015-11-01T09:49:00Z.
A DateTime can remember which of those you mean, but it depends on how you came up with the value. If you've just parsed this from text somewhere, you basically don't have enough information - it doesn't specify a single instant in time.
If you were to use my Noda Time library instead, then when converting from LocalDateTime to ZonedDateTime you'd be able to specify how you wanted ambiguity to be handled - so that may be an option for you... but it depends on where the value came from, and whether you know that it was always the second occurrence or always the first.
If you still want to use TimeZoneInfo, you can use TimeZoneInfo.IsAmbiguousTime and TimeZoneInfo.IsInvalidTime to detect local times which occur twice or zero times due to time zone shifts, and then handle those appropriately in your app.
I have a question about DateTimeOffset and daylight savings time. To explain my question lets assume that right now the date and time is:
11/6/2010 10:15:00 AM
If I run this code:
DateTimeOffset myTime = DateTimeOffset.Now;
Console.WriteLine("Local time: " + myTime.ToLocalTime().DateTime);
Then I get this result:
Local time: 11/6/2010 10:15:00 AM
Meaning that the event happened at 10:15 in the morning (my time zone is Mountain Daylight Time (-6 offset)).
So, then I save this DateTimeOffset to my SQL Server 2008 db (as a DateTimeOffset). The next day I want to display it to the user. But now daylight savings has expired.
If I run the above WriteLine with the saved off value (from the previous day) what will display?
The offset stored in the database is -6. But now that daylight savings is over, the current offset is -7. So as I understand the documentation, it will first convert my time to UTC time (so it takes 10:15 AM and adds 6 hours (4:15 pm). It will then subtract the current offset of the local time (4:15 pm - 7 = 9:15 AM).
So if I my math is right, now when I display my event, it will show that it occurred at 9:15 AM rather than 10:15 AM.
This is not good. I want to store time zone information, but I need my times to stay static in the same time zone. (Meaning that if the event happened at 10:15 AM in Utah, then the next time I look at it (in Utah), I need to see that it was at 10:15 AM, regardless if the daylight savings time change has happened.
I can't think I am the first one to have this issue. What do others do to fix this? (Or do I have the facts wrong?)
No, it won't add the current offset - it'll add the offset at that date which is still -6. So it should still display 10:15AM, because it knows the date involved, and thus the time zone rules in force on that date.
You may well want to store a simple UTC time and the time zone identifier separately, by the way. If you're storing a time zone, then using DateTimeOffset won't be particularly helpful over just a UTC date/time. (On the other hand, it's clearer that it does represent an instant in time - DateTime is a horribly confused type which doesn't let you easily express what you're trying to represent.)
Of course I'd personally encourage you to look at Noda Time which in my very biased opinion is a rather clearer date/time API than the built-in one... but which isn't quite ready for production use. (We're getting there though...)