i want to know the time difference between two countries.
There is ofcourse the static time difference, but during some periods the daylight saving time comes in between.
As far as i know the dst period is also different for some countries, so june 1 the diff between country a and b can be 1 hour, 1 july it can be 2 hours due to DST, and 1 august it can be 1 again etc etc
Is there a framework function for it or do i have to calculate it myself?
Michel
You need to know:
Both time zones (use TimeZoneInfo from .NET 3.5, bearing in mind that one country can have several time zones)
An instant in time, e.g. a UTC DateTime or a DateTimeOffset.
At that point it's relatively easy: convert the UTC instant into the local time in both time zones using TimeZoneInfo.ConvertTime, and subtract one from the other. Alternatively, use TimeZoneInfo.GetUtcOffset for both of them, and subtract one offset from the other.
Here's an example to find the current difference between London and Mountain View:
using System;
class Test
{
static void Main()
{
var mountainView = TimeZoneInfo.FindSystemTimeZoneById
("Pacific Standard Time");
var london = TimeZoneInfo.FindSystemTimeZoneById
("GMT Standard Time");
DateTimeOffset now = DateTimeOffset.UtcNow;
TimeSpan mountainViewOffset = mountainView.GetUtcOffset(now);
TimeSpan londonOffset = london.GetUtcOffset(now);
Console.WriteLine(londonOffset-mountainViewOffset); // 8 hours
}
}
To find out any historical difference (ie. for a date in the past when local DST policies for one or both timezones were different) you will have to store past policies for DST start/end/offset for each timezone and work them out yourself.
If you're fine with knowing the difference based on the current set of rules loaded into Windows then the built-in .NET method is straightforward and easy.
Related
There are 2 events (start and stop of some job) in the past which happened in different time zones.
I need to compute duration of the job.
I can get difference between those time zones in minutes and compute duration like this:
var duration = endTime - startTime.AddMinutes(diff);
However, there is a thing which confuses me.
Suppose start event happend in California and end event was in say Israel.
Right now difference between these time zones is 9 hours - California just switched to the day light and Israel not yet.
Next week this difference will be 10 hours because Israel will switch.
So, duration will be different if computed now and on the next week.
What is the right way to compute it?
Use DateTimeOffset?
So, duration will be different if computed now and on the next week.
I think you're forgetting that its you who is moving through time. not the project start and end times. therefore results will always be the same.
Id be tempted though just to convert the second time into the zone of the first, so it's just a straight diff. to convert from utc to any other zone you can use the following code
DateTime timeUtc = DateTime.UtcNow;
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
Theres also good info at https://learn.microsoft.com/en-us/dotnet/standard/datetime/converting-between-time-zones
In windows, we get timezone list like this:
ID Time zone name Display string
-- -------------- --------------
0 Dateline Standard Time (UTC-12:00) International Date Line West
110 UTC-11 (UTC-11:00) Coordinated Universal Time -11
200 Hawaiian Standard Time (UTC-10:00) Hawaii
300 Alaskan Standard Time (UTC-09:00) Alaska
more here.
I use this list to convert from one timezone to another using TimeZoneInfo class which accepts time zone name shown in above list.
Ex.
// Local time zone to UTC
var utcOffset = new DateTimeOffset(DateTime.UtcNow, TimeSpan.Zero);
var localTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timezoneName); // here tz name can be any name from above table
var localOffset = new DateTimeOffset(date.Value, localTimeZone.GetUtcOffset(utcOffset));
DateTime utcDate = localOffset.UtcDateTime;
Now I came across SalesForce timezone representation like:
Time Zone Code Time Zone Name
-------------- --------------
GMT+14:00 Line Is. Time (Pacific/Kiritimati)
GMT+13:00 Phoenix Is.Time (Pacific/Enderbury)
GMT+13:00 Tonga Time (Pacific/Tongatapu)
GMT+12:45 Chatham Standard Time (Pacific/Chatham)
more here.
I couldn't find built in functionality to use either time zone code or time zone name given in above table for the conversion.
If you're happy to stick with TimeZoneInfo and DateTime/DateTimeOffset, you can use Matt Johnson's TimeZoneConverter library to convert the IANA ID (the part in brackets, e.g. Pacific/Kiritimati) to a Windows system time zone ID.
Examples from the project page docs:
string tz = TZConvert.IanaToWindows("America/New_York");
// Result: "Eastern Standard Time"
Or:
TimeZoneInfo tzi = TZConvert.GetTimeZoneInfo("America/New_York");
However, things to be aware of:
There won't always be a complete mapping from IANA IDs to Windows IDs. Some aren't mapped, although the situation is better than it used to be.
The Windows time zone data can be different to the IANA data sometimes. (Again, this is getting better.)
Time zone data changes over time. If you're storing future date/time values, you might want to store the time zone and local time rather than the UTC instant. (That instant may not map to the same local time in the future.)
Some local times can be ambiguous - e.g. if the clocks go back from 2am to 1am on a particular date in a particular time zone, then 1:15am on that day will occur twice in that time zone. Think about how you want to handle that, and test it.
I'd personally recommend using my Noda Time library anyway, as a cleaner way of handling date/time, but I acknowledge that if you've got a lot of code dealing with DateTime already, that may not be feasible.
I have written an application to show the remaining time until the next big industry trade-show.
(it's about two years in the future at the time of writing)
I started off using the standard DateTime class but quickly ran into issues dealing with the varying number of days in each month, 2016 is a Leap Year and contains a Leap Day, Daylight Savings Time, etc.
Thankfully I discovered NodaTime. (Thanks #JonSkeet)
Not so thankfully, the way I am used to working with DateTime doesn't apply and I'm having a really hard time figuring out how to get the time remaining. (There aren't many examples floating around)
For example, the following code doesn't work because you can't subtract an instant from a LocalDateTime:
void example()
{
DateTime DT = Convert.ToDateTime("09/12/2016 10:00AM");
LocalDateTime NodaLocalDateTime = new LocalDateTime(
DT.Year, DT.Month, DT.Day, DT.Hour, DT.Minute, 0);
Period P = NodaLocalDateTime - SystemClock.Instance.Now;
}
So the question becomes:
How do you get the remaining time from now until some date?
To determine a "calendrical" amount of time between two events, you want Period as you've already discovered. However, that only deals with local dates and times.
To determine a "calendar-neutral" amount of time between two events, you can use Instant and Duration - but then you can't display the number of months left.
Both of these approaches have drawbacks, but basically they're fundamental to the way that time works. If you use the local time approach, then you'll find that the amount of time will jump back or forward an hour as you go over a DST transition. If you use the instant approach, you're restricted to days/months/hours/minutes etc - not months.
One option for between the two would be to use LocalDateTime and Period, but anchor both the event and the current time in UTC. That way there'll never be a discontinuity, as UTC is an unchanging base line, effectively. This also means that you'll always display the same amount of "time left" regardless of where in the world you look at the counter (or host the code, depending on exactly what you were planning to do).
If you want more details about why you can't get a Period between two ZonedDateTime values, I could think of examples which are fundamentally problematic. The bottom line is that calendrical arithmetic and time zones don't play nicely together though...
Just to give some actual code, I would have something like:
public sealed class EventCountdown
{
private readonly LocalDateTime eventTimeUtc;
private readonly IClock clock;
// It's probably most convenient to express the event time with the time zone
// in which it occurs. You could easily change this though.
public EventCountdown(ZonedDateTime zonedEventTime, IClock clock)
{
this.eventTimeUtc = zonedEventTime.WithZone(DateTimeZone.Utc).LocalDateTime;
this.clock = clock;
}
public Period GetPeriodRemaining()
{
return Period.Between(clock.Now.InUtc().LocalDateTime, eventTimeUtc);
}
}
Note that in Noda Time 2.0 the IClock.Now property is being changed to a GetCurrentInstant method... but in that case you'd probably use a ZonedClock in UTC and call GetCurrentLocalDateTime on it.
The solution I ended up using is Period.Between(), which seems do the trick.
using NodaTime;
DateTime EventDT;
LocalDateTime LocalizedEventDT;
Period TimeLeft;
public EventCountdown()
{
// Start with a date and time
EventDT = Convert.ToDateTime("09/12/2016 10:00AM");
// Localize it
LocalizedEventDT = new LocalDateTime(
EventDT.Year, EventDT.Month,
EventDT.Day, EventDT.Hour,
EventDT.Minute, 0);
}
// find out how much time is between now and the future date
public Period GetPeriodRemaining()
{
DateTime dt_Now = DateTime.Now;
return Period.Between(new LocalDateTime(
dt_Now.Year, dt_Now.Month, dt_Now.Day, dt_Now.Hour,
dt_Now.Minute, dt_Now.Second), LocalizedEventDT);
}
If anyone has a solution that does this while taking time zones (local vs where the event is taking place) into account that would be awesome. (I tried doing this using a ZonedDateTime in a similar fashion but ran into a brick wall).
Also, it's not clear to me if this method is taking the various days of the month, daylight savings time, leap year, etc. into account. Anyone know?
If it is not, obviously I'd welcome any solutions that do so gracefully.
Does C# take Daylight savings time into consideration when converting between timezones?
I have a source date which is in the current time in London, and I want to convert it to my timezone (CET). Here's the code I'm using.
DateTime time = DateTime.ParseExact(timeString, "HH:mm", null);
time = DateTime.SpecifyKind(time, DateTimeKind.Unspecified);
//Convert it to the right timezone. It is currently in GMT
TimeZoneInfo gmt = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
TimeZoneInfo current = TimeZoneInfo.Local;
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(time, gmt);
DateTime local = TimeZoneInfo.ConvertTimeFromUtc(utc, core.startTime = local;
It's currently working well. However when DST rears its ugly head, will it continue working or will it break horribly? I'm a bit wary of TimeZones due to having had tons of issues in the past.
The short answer is "Not everywhere, not perfectly."
TimeZoneInfo.GetAdjustmentRules will give you a collection of rules about changes in the DST offset and when they come into and go out of effect.
However, your user can still cock things up by un-checking "Automatically adjust for daylight savings" in Windows Control Panel Date and Time. If DST is turned off in Windows then you will get an empty collection of adjustment rules.
If you want automagical application of adjustment rules you must use DateTime objects for which the DateTimeKind has been set. If DST is turned off this will be honoured in the conversion.
GMT is solar time at the Royal Observatory in Greenwich. The British invented the whole business of timezone offsets from a date-line because they were the first to coordinate anything on a global scale. In halcyon days of yore they had a planet-wide navy of sailboats and no radio. Lag on orders was weeks or months, so consistent, precise, global time-keeping was invented by the only people with a frame of reference larger than a planet - the Royal Astronomers.
The moon's tidal forces are slowing the Earth's rotation. It takes a lot of juice to slosh an ocean of water up and down and it's not magic, it comes from the spin moment of the planet.
Also the duration of a solar orbit isn't constant either, so we have leap seconds every now and then to synch the calendar with planetary reality. Sidereal time on the other hand has no such foolishness, so we drift away from it. Then there is relativistic drift. GPS satellites move so fast they actually have to compensate for slight time-warping.
Does C# take Daylight savings time into consideration when converting between timezones?
Yes, assuming your computer is kept updated as the timezone info is sometimes updated with windows update. It should still work even without windows update if the country hasn't changed their DST time periods (this happened in Australia recently)
I have a source date which is in the current time in London, and I want to convert it to my timezone (CET)
What do you mean 'source date which is the current time in London' ?
Always store your dates as UTC and convert them 'at the last minute' to the desired local time.
If you're wondering what happens when daylight savings changes then you can test this by changing the clock on your computer.
Be careful when working with dates before 1987 in .NET. Default AdjustmentRules in TimeZoneInfo for the time zone that you are interested in may not be sufficient for your purpose. Read more here : http://blog.appliedis.com/2013/03/06/beware-daylight-saving-time-transitions-in-dot-net/
At least in .net 4.5 TimeZoneInfo does handle daylight saving time.
The easiest way to check it is to compare BaseUtcOffset and GetUtcOffset
var baseOffset = timeZoneInfo.BaseUtcOffset;
var currentOffset = timeZoneInfo.GetUtcOffset(currentLocalTime);
var isDst = currentOffset > baseOffset;
var delta = currentOffset - baseOffset;
This is much easier than dealing with AdjustmentRule which you don't need if you are only interested in adjusting a DateTime for DST.
Btw GMT is obsolete and is replaced by UTC.
I am storing date/times in the database as UTC and computing them inside my application back to local time based on the specific timezone. Say for example I have the following date/time:
01/04/2010 00:00
Say it is for a country e.g. UK which observes DST (Daylight Savings Time) and at this particular time we are in daylight savings. When I convert this date to UTC and store it in the database it is actually stored as:
31/03/2010 23:00
As the date would be adjusted -1 hours for DST. This works fine when your observing DST at time of submission. However, what happens when the clock is adjusted back? When I pull that date from the database and convert it to local time that particular datetime would be seen as 31/03/2010 23:00 when in reality it was processed as 01/04/2010 00:00.
Correct me if I am wrong but isn't this a bit of a flaw when storing times as UTC?
Example of Timezone conversion
Basically what I am doing is storing the date/times of when information is being submitted to my system in order to allow users to do a range report. Here is how I am storing the date/times:
public DateTime LocalDateTime(string timeZoneId)
{
var tzi = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
return TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tzi).ToUniversalTime().ToLocalTime();
}
Storing as UTC:
var localDateTime = LocalDateTime("AUS Eastern Standard Time");
WriteToDB(localDateTime.ToUniversalTime());
You don't adjust the date for DST changes based on whether you're currently observing them - you adjust it based on whether DST is observed at the instant you're describing. So in the case of January, you wouldn't apply the adjustment.
There is a problem, however - some local times are ambiguous. For example, 1:30am on October 31st 2010 in the UK can either represent UTC 01:30 or UTC 02:30, because the clocks go back from 2am to 1am. You can get from any instant represented in UTC to the local time which would be displayed at that instant, but the operation isn't reversible.
Likewise it's very possible for you to have a local time which never occurs - 1:30am on March 28th 2010 didn't happen in the UK, for example - because at 1am the clocks jumped forward to 2am.
The long and the short of it is that if you're trying to represent an instant in time, you can use UTC and get an unambiguous representation. If you're trying to represent a time in a particular time zone, you'll need the time zone itself (e.g. Europe/London) and either the UTC representation of the instant or the local date and time with the offset at that particular time (to disambiguate around DST transitions). Another alternative is to only store UTC and the offset from it; that allows you to tell the local time at that instant, but it means you can't predict what the local time would be a minute later, as you don't really know the time zone. (This is what DateTimeOffset stores, basically.)
We're hoping to make this reasonably easy to handle in Noda Time, but you'll still need to be aware of it as a possibility.
EDIT:
The code you've shown is incorrect. Here's why. I've changed the structure of the code to make it easier to see, but you'll see it's performing the same calls.
var tzi = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
var aussieTime = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tzi);
var serverLocalTime = aussieTime.ToLocalTime();
var utcTime = serverLocalTime.ToUniversalTime();
So, let's think about right now - which is 13:38 in my local time (UTC+1, in London), 12:38 UTC, 22:39 in Sydney.
Your code will give:
aussieTime = 22:39 (correct)
serverLocalTime = 23:39 (*not* correct)
utcTime = 22:39 (*not* correct)
You should not call ToLocalTime on the result of TimeZoneInfo.ConvertTimeFromUtc - it will assume that it's being called on a UTC DateTime (unless it's actually got a kind of DateTimeKind.Local, which it won't in this case).
So if you're accurately saving 22:39 in this case, you aren't accurately saving the current time in UTC.
It's good that you are attempting to store the dates and times as UTC. It is generally best and easiest to think of UTC as the actual date and time and local times are just pseudonyms for that. And UTC is absolutely critical if you need to do any math on the date/time values to get timespans. I generally manipulate dates internally as UTC, and only convert to local time when displaying the value to the user (if it's necessary).
The bug that you are experiencing is that you are incorrectly assigning the local time zone to the date/time values. In January in the UK it is incorrect to interpret a local time as being in a Summertime time zone. You should use the time zone that was in effect at the time and location that the time value represents.
Translating the time back for display depends entirely on the requirements of the system. You could either display the times as the user's local time or as the source time for the data. But either way, Daylight Saving/Summertime adjustments should be applied appropriately for the target time zone and time.
You could work around this by also storing the particular offset used when converting to UTC. In your example, you'd store the date as something like
31/12/2009 23:00 +0100
When displaying this to the user, you can use that same offset to convert, or their current local offset, as you choose.
This approach also comes with its own problems. Time is a messy thing.
The TimeZoneInfo.ConvertTimeFromUtc() method will solve your problem:
using System;
class Program {
static void Main(string[] args) {
DateTime dt1 = new DateTime(2009, 12, 31, 23, 0, 0, DateTimeKind.Utc);
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
Console.WriteLine(TimeZoneInfo.ConvertTimeFromUtc(dt1, tz));
DateTime dt2 = new DateTime(2010, 4, 1, 23, 0, 0, DateTimeKind.Utc);
Console.WriteLine(TimeZoneInfo.ConvertTimeFromUtc(dt2, tz));
Console.ReadLine();
}
}
Output:
12/31/2009 11:00:00 PM
4/2/2010 12:00:00 AM
You'll need .NET 3.5 or better and run on an operating system that keeps historical daylight saving time changes (Vista, Win7 or Win2008).
Correct me if I am wrong but isn't
this a bit of a flaw when storing
times as UTC?
Yes it is. Also, days of the adjustment will have either 23 or 25 hours so the idiom of the prior day at the same time being local time - 24 hours is wrong 2 days a year.
The fix is picking one standard and sticking with it. Storing dates as UTC and displaying as local is pretty standard. Just don't use a shortcut of doing calculations local (+- somthing) = new time and you are OK.
This is a huge flaw but it isn't a flaw of storing times in UTC (because that is the only reasonable thing to do -- storing local times is always a disaster). This is a flaw is the concept of daylight savings time.
The real problem is that the time zone information changes. The DST rules are dynamic and historic. They time when DST starting in USA in 2010 is not the same when it started in 2000. Until recently Windows did not even contain this historic data, so it was essentially impossible to do things correctly. You had to use the tz database to get it right. Now I just googled it and it appears that .NET 3.5 and Vista (I assume Windows 2008 too) has done some improvement and the System.TimeZoneInfo actually handles historic data. Take a look at this.
But basically DST must go.