Leap year bug calling ToUniversalTime().AddYears().ToLocalTime()? - c#

I encountered what may be a leap year in .NET's DateTime handling, specifically ToLocalTime(). Here's some code which reproduces the problem (I'm in the Pacific time zone):
DateTime dtStartLocal = DateTime.Parse("2009-02-28T23:00:00.0-08:00");
DateTime dtEndLocal = dtStartLocal.AddYears(3);
DateTime dtStartUtc = dtStartLocal.ToUniversalTime();
DateTime dtEndUtc = dtStartUtc.AddYears(3);
DateTime dtEndLocal2 = dtEndUtc.ToLocalTime();
DateTime dtStartLocal2 = dtStartUtc.ToLocalTime();
Console.WriteLine("START: 1={0}, 2={0}", dtStartLocal, dtStartLocal2);
Console.WriteLine("END : 1={0}, 2={1}", dtEndLocal, dtEndLocal2);
Console.ReadLine();
The output is:
START: 1=2/28/2009 11:00:00 PM, 2=2/28/2009 11:00:00 PM
END : 1=2/28/2012 11:00:00 PM, 2=2/29/2012 11:00:00 PM
Notice the variable which I did ToUniversalTime().AddYears(3).ToLocalTime() is different than just AddYears(3), it's one day ahead.
Has anyone encountered this? If this is expected, can someone explain the logic behind it?
NOTE: Yes, the best approach is to work entirely in UTC and not flip flop between them. This isn't something which is effecting me, but a peculiarity I encountered. Essentially I misunderstood how AddYears() worked and now I can see why it's doing what it's doing (see my selected answer below).

I think that this is working correctly.
DateTime dtStartUtc = dtStartLocal.ToUniversalTime();
PST is UTC-8. Therefore, this converts the time to March 1, 2009, 07:00:00.
DateTime dtEndUtc = dtStartUtc.AddYears(3);
This adds three years to the previous time, putting it at March 1, 2012, 07:00:00.
DateTime dtEndLocal2 = dtEndUtc.ToLocalTime();
This converts the end time back to PST, which would be February 29, 2012, 11:00:00.
I'd say this is just a side affect of converting between local and UTC time.

Print the timezone/correction factor. When you do the .ToUniversialTime() it essentially adds the 8 hours from your original time ("-08:00"), which would put it at 11:00 the next day starting from 23:00 hours February 28th. So when you add 3 years to it, it's the 11:00 AM on the 29th. Had you done 2 years, it would have been March 1st, it has nothing to do with the leap year.

This behaviour isn't incorrect, as far as I can tell. When you convert the local time to UTC it effectively pushes it into the next day; March 1st. When you add three years, it stays as March 1st. Convert it back to local time and it rolls back to the previous day, which because 2012 is a leap year, is February 29th.

Related

Check if TimeSpan falls in Daylight Saving transition

I have flight arrival time and the flight departure time. I have to check if the flight time falls in the daylight saving transition (Equinox Transition). If the hour is forward I need to add an hour in flight time else if the hour is reverted I need to deduct an hour from flight time.
In TimeZoneInfo class we do have IsDaylightSavingTime but it only says either if the time is in Daylight saving or not.
I need to check that my timespan is either effected by DayLight Saving Transition or not.
Update1: The transition is observed in March and November but the date changes every year so I can't hard code any date. I need to get the specific date of the year at which the EQUINOX will occur.
Update2: Datetime is local not UTC, as the flight arrival and departure are from the same airport.
Data:
Flight Departure Time : 19 March 2019 23:00
Flight Arrival Time : 20 March 2019 08:00
Flight Time : 7 Hours but due to EQUINOX its 8 Hours as the hour was forward at
20 March 2019 05:58
The GetAdjustmentRules provide you the info you are looking for:
Provides information about a time zone adjustment, such as the transition to and from daylight saving time.
Example of the output of the sample code in the above link:
W. Europe Standard Time Adjustment rules
Start Date: Monday, January 01, 0001
End Date: Friday, December 31, 9999
Time Change: 1:00 hours
Annual Start: The Last Sunday of March at 2:00 AM
Annual End: The Last Sunday of October at 3:00 AM
Also the IsInvalidTime say you if the specific value is invalid due to daylight transition.
You can convert it to a valid DateTime by using:
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById(id);
if (timeZone.IsInvalidTime(dateTime))
dateTime = TimeZoneInfo.ConvertTime(dateTime.ToUniversalTime(), timeZone);
Finally, my suggestion is to store and evaluate DateTime as UTC in order to avoid ambiguity. You can convert it to local time for GUI purpose only.
EDIT: here is there an example of how to use GetAdjustmentRules.

c#: How do I get the previous year-to-date and previous month-to-date for specific time periods?

Using c#, I want to compare the current week-to-date to the same period last week-to-date. For example, if today is Wednesday, and if the first day of the week is Sunday, then I want to compare totals for Sunday – Tuesday of this week against Sunday – Tuesday of last week. I’m not counting Wednesday because I don’t have a full day of data until midnight the same day.
The same applies to comparing this mtd to the same number of days last month, and last year. For example, if the current date is June 19th, I want to compare the data from May 1-18th of last month as well as January 1 – June 18th of last year against January 1 – June 18th of this year.
The variables I’m trying to use look like this:
//Current dates
DateTime currentDte = DateTime.Now;
DateTime beginWeek = DateTime.Now.StartOfWeek(DayOfWeek.Sunday);
DateTime beginMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
DateTime beginYear = new DateTime(DateTime.Now.Year, 1, 1);
//Historical dates
DateTime lastWeekToDate = DateTime.Now.StartOfWeek(DayOfWeek.Sunday - (7 - (int)DateTime.Now.DayOfWeek));
DateTime lastMonthToDate =
DateTime lastYearToDate =
As you can see I figured out the current dates and can loop through them to get the wtd, mtd, and ytd data I need. And I managed to figure out how to get the last week-to-date I need.
But I don’t know how to get the lastMonthToDate and lastYearToDate dates I need. I’ve tried everything I can think of. I’ve read date documentation until my eyes hurt, and still I come up with goose eggs. Can anyone offer any suggestions?
If I understand your question correctly, you just need to use AddMonths and AddYears.
DateTime lastMonthToDate = beginMonth.AddMonths(-1);
DateTime lastYearToDate = beginYear.AddYears(-1);
EDIT
Based your comment - it looks like you want the to subtract months/years from the current date in which case it would be
DateTime lastMonthToDate = currentDte.AddMonths(-1);
DateTime lastYearToDate = currentDte.AddYears(-1);
If it's the time of day that's throwing you off, just use the date part DateTime.Now.Date.AddMonths(-1)
Based on the feedback I received from Zeph, I was able to get the beginning of last year using this code:
DateTime startDate = beginYear.AddYears(-1);
Now I'm able to tally all of the ytd data I need based on the interval dates. Thank you very much!

Julian Time stamp to Date Time

I am trying to convert to Julian Time Stamp to Date Time. I have the following microseconds time stamp 212302469304212709. As i understand i need to add these milliseconds to the beginning of Julian Calendar (January 1, 4713 B.C., 12:00 (noon)). So i have the following method:
private DateTime GetDateTime(string julianTimeStamp)
{
var julianMilliseconds = Convert.ToDouble(julianTimeStamp)/1000;
var beginningOfTimes = new DateTime(1, 1, 1, 0, 0, 0, 0);
var dateTime = beginningOfTimes.AddMilliseconds(julianMilliseconds).AddYears(-4713).AddMonths(-1).AddDays(-1).AddHours(-12);
return dateTime;
}
Assume i pass 212302469304212709 string as the parameter. The expected result should be 2015/07(July)/01 00:08:24.212. Based on my method, i have almost the same result, but day is not 1, it is 6. Same problem for different time stamps i tested.
Could any one tell me what i am doing wrong? Thanks in advance.
Edited:
This is the exact date time i expect to receive: 2015(year) 7(month) 1(day) 0(hour) 8(minute) 24(second) 212(millisecond) 709(microsecond)
The given timestamp 212,302,469,304,212,709 μs when converted to days (just divide by 86,400,000,000) gives 2457204.505836 days (to six decimal places, which is the best I can do without a lot of extra trouble). Using the Multi Year Computer Interactive Almanac (MICA) written by the United States Naval Observatory, and putting in the free form date 2015(year) 7(month) 1(day) 0(hour) 8(minute) 24(second) 212(millisecond) 709(microsecond), the program calculates exactly the same day count (to six decimal places), proving the time stamp is an accurate Julian date.
One problem with the OP's calculation is trying to use the DateTime class before the earliest supported date, as pointed out by another poster. Also, the OP didn't say if 1 July 2015 was in the Julian or Gregorian calendar, but the MICA calculation proves it is in the Gregorian calendar. Since the OP is working in the Gregorian calendar, the epoch of Julian dates should be stated in the Gregorian proleptic calendar: Noon Universal Time, November 24, 4714 BC. The oft-quoted date January 1, 4713 BC is a proleptic Julian calendar date.
"Proleptic" means a date has been found by beginning at a modern date, who's calendar date is known with absolute certainty, and applying the rules of the chosen calendar backward until the desired date is reached, even though the desired date is before the chosen calendar was invented.
DateTime uses Gregorian calendar, so when you substract years, months and so on you are doing it with that calendar, not the Julian.
Unfortunately DateTime does not support dates before year 1. You can check the library in this post, maybe it helps you.

C# difference between two dates where one ends with a Z?

I have two dates
DateTime date1Z = DateTime.Parse("2014-05-22 23:39:29Z");
DateTime date1ZKind = DateTime.SpecifyKind(DateTime.Parse("2014-05-22 23:39:29Z"), DateTimeKind.Utc);
DateTime date2 = DateTime.Parse("2014-05-22 23:39:29");
DateTime date2Kind = DateTime.SpecifyKind(DateTime.Parse("2014-05-22 23:39:29"), DateTimeKind.Utc);
Console.WriteLine(date1Z);
Console.WriteLine(date1ZKind);
Console.WriteLine(date2);
Console.WriteLine(date2Kind);
Prints
23/05/2014 11:39:29 a.m.
23/05/2014 11:39:29 a.m.
22/05/2014 11:39:29 p.m.
22/05/2014 11:39:29 p.m.
Can someone explain whats going on here?
Using the suffix "Z" is date shorthand for saying that the Date-Time is "Zulu" time which is another word for UTC time. The first two dates are being parsed as UTC, while the last two are being parsed as whatever time is on the computer in question.
So to answer you question of what is going on: the latter two dates are being offset by your local time, which is apparently +12:00 (plus twelve hours), while the first two are not (as they are marked as "Zulu" or UTC time).
You live in New Zealand, which is +12 over UTC. That matches the date difference you are experiencing. As mentioned, the Z stands for UTC.

DateTime.Today , beginning or end of the day?

I am using DateTime.Today.
Now I'm not sure if the date is from the beginning of the day or the end of the day.
This is what DateTime.Today returns : {11-3-2014 0:00:00}
MSDN states the following: "An object that is set to today's date, with the time component set to 00:00:00."
This means that a DateTime object is created with today's date at the absolute start of the day hence 00:00:00.
You can check if it is the start of the day by using the AddHour() method of the DateTime class.
DateTime d = DateTime.Today;
//AddHours, AddMinutes or AddSeconds
d = d.AddHours(1);
if (d.Date != DateTime.Today.Date)
{
//Not the same day
}
If d.date should be different the date was initialised at a different time (eg. 23:00:01).
http://msdn.microsoft.com/en-us/library/system.datetime.today(v=vs.110).aspx
0:00:00 is the start of the day and 23:59:59 is the end of day.
You can also confirm through this 24-hour clock
In the 24-hour time notation, the day begins at midnight, 00:00, and the last minute of the day begins at 23:59. Where convenient, the
notation 24:00 may also be used to refer to midnight at the end of a
given date[5] – that is, 24:00 of one day is the same time as 00:00 of
the following day.
On a side note:-
If you want to know the time then use .Now because that includes the 10:32:32 or whatever time; however .Today is the date-part only (at 00:00:00 on that day ie the begining of the day). So you can say that .Today is essentially the same as .Now.Date
Thats the beginning of the day, the end of the day would be:
{11-3-2014 23:59:59}
And remember, the only stupid question is the one you don't ask :)
DateTime.Today returns the current DateTime value, without the Time part.
Which means, it is the the first possible DateTime value for the current day.
Think of it like this:
The last moment in a day can be 23:59 or theoretically any amount of nanseconds before the next day. the next day then starts at 00:00:00 counting upwards.
So 11-3-2014 0:00:00 marks the beginning of a day. Either the earliest possible moment, or no time at all, if you want to treat 0:00:00 as a default value.

Categories