Reputation: 1303
I have a rest api which gives me current date and previous month of current date, It has output like following:
{
fromDate:2018-03-22T00:00:00+04:30
toDate:2018-04-22T00:00:00+04:30
}
If I consume these two dates in JavaScript like below, I get different results:
new Date("2018-03-22T00:00:00+04:30")
console output: Wed Mar 21 2018 23:00:00 GMT+0330 (Iran Standard Time)
new Date("2018-04-22T00:00:00+04:30")
console output: Sun Apr 22 2018 00:00:00 GMT+0430 (Iran Daylight Time)
And on the c# side, I use this code to get dates from server:
var toDate = DateTime.Now.Date;
DateTime fromDate = toDate.AddMonths(-1);
how can I overcome this issue of not having different dates?
Upvotes: 1
Views: 178
Reputation: 241525
Due to the start of daylight saving time in Iran on 2018-03-22
, as the clock approached 00:00:00
, it was advanced by an hour to 01:00:00
. If one observed the clock carefully during this time, one would see it advance as follows:
...
2018-03-21 23:59:58
2018-03-21 23:59:59
2018-03-22 01:00:00
2018-03-21 01:00:01
...
In other words, the values 00:00:00
through 00:59:59
on that day did not exist in the local time zone.
Since you are providing such a non-existent value in your fromDate
, and your local computer's time zone is set for Iran, then JavaScript is converting it to a valid point in time, as follows:
2018-03-22T00:00:00+04:30 source input value
2018-03-21T19:30:00+00:00 converted to UTC
2018-03-21T23:00:00+03:30 converted to a valid local time
If you were looking to get the correct start of day for that day, your fromDate
would have to be 2018-03-22T01:00:00+04:30
.
To calculate that correctly on the server side in C#, you'll need to work with the TimeZoneInfo
API. Consider the following helper method:
static DateTimeOffset GetStartOfDay(DateTime dt, TimeZoneInfo tz)
{
// Work in the time zone provided
if (dt.Kind != DateTimeKind.Unspecified)
{
dt = TimeZoneInfo.ConvertTime(dt, tz);
}
// Start with assuming midnight
var d = dt.Date;
// Check for the time being invalid and handle if so
if (tz.IsInvalidTime(d))
{
// the gap is *usually* 1hr, but not always, so calculate it
var gap = tz.GetUtcOffset(dt.AddDays(1)) - tz.GetUtcOffset(dt.AddDays(-1));
// advance forward by the amount of the gap
d = d.Add(gap);
}
// Also check for the time being ambiguous, such as in a fall-back transition.
// We want the *first* occurrence, which will have a *larger* offset
var offset = tz.IsAmbiguousTime(d)
? tz.GetAmbiguousTimeOffsets(d).OrderByDescending(x => x).First()
: tz.GetUtcOffset(d);
// Now we know when the date starts precisely
return new DateTimeOffset(d, offset);
}
With that declared, now you can easily obtain accurate values for your API:
var tz = TimeZoneInfo.FindSystemTimeZoneById("Iran Standard Time");
var date = new DateTime(2014, 3, 22); // or DateTime.UtcNow for the current date
DateTimeOffset fromDate = GetStartOfDay(date, tz);
DateTimeOffset toDate = GetStartOfDay(fromDate.AddDays(1).Date, tz);
Of course this assumes that Iran is the correct time zone you want to emit from your API. If you are serving a wider audience, then you may need to adjust the time zone accordingly.
Upvotes: 1