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
Related
I would like to convert the current time to a decimal representing a fraction of the day. For example, if the day starts at 0, then 12:00 PM should be 0.5.
I need to send that value to an API, and it needs to be in that format. i.e.
"LAST_PRINT_TIME":0.22020833"
Depending on the precision requirements of your result, this may help you:
DateTime now = DateTime.Now;
double dayFraction = (now.Hour + now.Minute / 60d) / 24d;
now.Minute / 60d calculates the fraction of the current hour (so if the time is XX:15 PM this will give 0.25). This is then added to the current hour. This value is then divided by 24 to obtain the final result.
For example, 3:45 PM would go as follows:
(15 + 45 / 60) / 24) => (15 + 0.75) / 24 => 15.75 / 24 => 0.65625
So 3:45 PM, which is 15.75 hours into the day, would be 0.65625 (or 65.625%) of the day.
Or, as #madreflection mentioned in a comment, you could use .ToOADate() as well. In this case, you could do something like:
DateTime now = DateTime.Now;
double dayFraction = now.ToOADate() - now.Date.ToOADate();
This is one of those problems that seems deceptively simple, but the solution is actually much more complex than you would think.
The complexities arise from the nature of local time, whose rules are defined by time zones. Many time zones have transitions that occur either regularly (such as for daylight saving time), or irregularly (such as for changes in standard time).
As such, one needs to consider:
Could the day be shorter or longer than 24 hours?
For example, in most of the US the start of DST is at 2:00 AM, and on that day there are 23 hours in the day because the hour from 2:00 to 2:59 is skipped. At the end of DST, also at 2:00 AM in the US, the hour from 1:00 through 1:59 is repeated, creating 25 hours in that day.
Could the day start or stop at a time other than midnight?
For example, in most of Chile in 2019, the start of DST made the date 2019-09-08 start at 01:00 instead of 00:00.
Learn more in Falsehoods programmers believe about time.
Consider using the following approach to overcome these real-world considerations.
First, define some helper functions to do most of the work. They are not specific to a particular point in time or a particular time zone.
static double GetFractionOfDay(DateTimeOffset dto, TimeZoneInfo tz)
{
// Get the start of the day, and the start of the next day
DateTimeOffset startOfDay = GetStartOfDay(dto, tz);
DateTimeOffset startOfNextDay = GetStartOfDay(startOfDay.AddDays(1), tz);
// Calculate the length of the day. It might not be 24 hours!
TimeSpan lengthOfDay = startOfNextDay - startOfDay;
// Now calculate the position within the day, and the fraction to return
TimeSpan durationSinceStartOfDay = dto - startOfDay;
return durationSinceStartOfDay / lengthOfDay;
}
static DateTimeOffset GetStartOfDay(DateTimeOffset dto, TimeZoneInfo tz)
{
// Make sure we're in the correct time zone
dto = TimeZoneInfo.ConvertTime(dto, tz);
// Start by assuming a local midnight exists
DateTime dt = dto.Date;
// Handle days without a local midnight (these do exist in several time zones)
if (tz.IsInvalidTime(dt))
{
// Advance by the transition gap. This is usually 1 hour, but best not to hard-code that.
TimeSpan[] offsets = { tz.GetUtcOffset(dt.AddDays(-1)), tz.GetUtcOffset(dt.AddDays(1)) };
TimeSpan gap = offsets[1] - offsets[0];
return new DateTimeOffset(dt.Add(gap), offsets[1]);
}
// Handle days with more than one midnight (it's possible, even if unlikely)
if (tz.IsAmbiguousTime(dt))
{
// There's more than one. Prefer the first one, since we want the beginning of the day.
TimeSpan[] offsets = tz.GetAmbiguousTimeOffsets(dt);
TimeSpan offset = offsets[0] > offsets[1] ? offsets[0] : offsets[1];
return new DateTimeOffset(dt, offset);
}
// Clean case, just one local midnight and it does exist
return new DateTimeOffset(dt, tz.GetUtcOffset(dt));
}
With those defined, you can now get an answer to your question with regard to "now" in the local time zone.
double dayFraction = GetFractionOfDay(DateTimeOffset.Now, TimeZoneInfo.Local);
However - Though this is the correct answer of "what fraction of the day is it", keep in mind it may be more important to align with what the receiving API expects, even if not exactly correct. In other words, if 12:00 should always be 0.5, even when it's not exactly at the midpoint of the day, then use elmer007's approach.
We are now in the summer time (UTC+01:00) but I need always winter time whereever I am.
For example now time is 08:05 and winter time is 07:05
I can find whether it is saving time or not by using this function
DateTime.Now.IsDaylightSavingTime()
and here is the delta (1 hour change)
TimeZoneInfo.Local.GetAdjustmentRules()[0].DaylightDelta;
so if I do something like that, is it correct?
var winterTime= DateTime.Now;
if (DateTime.Now.IsDaylightSavingTime())
{
winterTime = DateTime.Now.AddHours(-1 * delta.Hours);
}
or is there another way to do? (without using any 3rd solution)
Edit: The reason why I am asking this is that we are flashing a firmware to a nfc device and some dates in the devices should be in winter time. Thats why our tool should write winter time as paramter to the device.
In case DaylightDelta is not whole hours better use the TimeSpan directly. Also you need to find the rule in GetAdjustmentRules() that matches the current date. GetAdjustmentRules() returns both future and historical rules.
var now = DateTime.Today;
var rule = TimeZoneInfo.Local.GetAdjustmentRules().Where(x => now >= x.DateStart && now <= x.DateEnd).First();
winterTime = DateTime.Now - rule.DaylightDelta;
We are now in the summer time (UTC+01:00) but I need always winter time whereever I am.
...
... The reason why I am asking this is that we are flashing a firmware to a nfc device and some dates in the devices should be in winter time. Thats why our tool should write winter time as paramter to the device.
It sounds like you simply want to obtain the UTC time to set on the device. If so, just use DateTime.UtcNow. There is no need to concern yourself with time zones.
However, if you actually wanted to take the standard time (or winter time) for whatever local time zone you're in (that would seem to be a bit silly because that's not how local times work), but if you really are sure you want that, you can do it without querying adjustment rules. Instead, try this:
DateTime dt = DateTimeOffset.UtcNow.ToOffset(TimeZoneInfo.Local.BaseUtcOffset).DateTime;
This takes the current UTC time, applies the base offset of the local time zone, and then gives you back a DateTime with .Kind == DateTimeKind.Unspecified. The base offset is the offset from UTC that applies during standard time without any adjustment rules applied for DST.
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 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.