Based on this question, I have this (so I can have a sense of the object later in calling functions).
But it throws an error, and I could do with some help to understand what is wrong in this code..? I have spent a day reading through multiple comprehensive NodaTime documentations, but loosing time now. Perhaps an oversight of something trivial? Cue: Under Pressure - Queen
Error is caused in GetZoneInterval() at return new ZoneInterval():
System.InvalidOperationException: Zone interval extends to the end of time.
Stack trace:
at NodaTime.Utility.Preconditions.CheckState(Boolean expression, String message)
at NodaTime.TimeZones.ZoneInterval.get_End()
at WebApp.PocTasks.Models.HeardIslandDateTimeZone.GetZoneInterval(Instant instant)
at NodaTime.DateTimeZone.GetUtcOffset(Instant instant)
at NodaTime.ZonedDateTime..ctor(Instant instant, DateTimeZone zone, CalendarSystem calendar)
at NodaTime.ZonedDateTime.WithZone(DateTimeZone targetZone)
at WebApp.PocTasks.DateTimeExtension.ConvertToZonedDateTime(ZonedDateTime zonedDateTime, DateTimeZone dateTimeZone)
at WebApp.PocTasks.Controllers.HomeController.GetUserTimezoneRecords(ZonedDateTime sourceStartTime, ZonedDateTime sourceEndTime)
public class HeardIslandDateTimeZone : DateTimeZone
{
private readonly DateTimeZone _brisbane;
/// <summary>
/// The Territory of Heard Island and McDonald Islands is an Australian external territory.
/// <para>French Southern and Antarctic Time (TFT) is 5 hours ahead of Coordinated Universal Time (UTC). This time zone is in use during standard time in: Indian Ocean.</para>
/// </summary>
/// <remarks>
/// <para>Ref: www.timeanddate.com/worldclock/@1547315</para>
/// </remarks>
public HeardIslandDateTimeZone()
: base(
"Australia/HeardIsland",
false,
Offset.FromHours(5),
Offset.FromHours(5))
{
this._brisbane = DateTimeZoneProviders.Tzdb["Australia/Brisbane"];
}
public override int GetHashCode() => RuntimeHelpers.GetHashCode(this);
public override ZoneInterval GetZoneInterval(Instant instant)
{
// Return the same zone interval, but offset by 5 hours.
var brisbaneInterval = _brisbane.GetZoneInterval(instant);
return new ZoneInterval(
brisbaneInterval.Name,
brisbaneInterval.Start,
brisbaneInterval.End,
brisbaneInterval.WallOffset + Offset.FromHours(-5), // taking-off 5 from +10 that is Brisbane.
brisbaneInterval.Savings);
}
}
My calling POC function is using HomeController's Index action and corresponding view.
HomeController.cs
[HttpGet]
public IActionResult Index()
{
var meeting = new ViewModelExample();
meeting.StartTime = new DateTime(2023, 2, 18, 9, 30, 0);
meeting.EndTime = new DateTime(2023, 2, 18, 10, 30, 0);
var sydney = DateTimeZoneProviders.Tzdb["Australia/Sydney"];
meeting.HostStartTime = meeting.StartTime.ConvertToZonedDateTime(sydney);
meeting.HostEndTime = meeting.EndTime.ConvertToZonedDateTime(sydney);
var heard = new HeardIslandDateTimeZone();
meeting.AttendeeStartTime = meeting.HostStartTime.ConvertToZonedDateTime(heard);
meeting.AttendeeEndTime = meeting.HostEndTime.ConvertToZonedDateTime(heard);
return View(meeting);
}
And displaying the data on the View is:
<div>
<p>Database Time: @Model.StartTime.ToCustomString() - @Model.EndTime.ToCustomString()</p>
<p>Host Time (Sydney): @Model.HostStartTime.ToCustomString() - @Model.HostEndTime.ToCustomString()</p>
<p>Attendee Time (Heard Island): @Model.AttendeeStartTime.ToCustomString() - @Model.AttendeeEndTime.ToCustomString()</p>
</div>
Note: ConvertToZonedDateTime, ToCustomString are simple extension classes to convert (b/w DateTime & ZoneDateTime) and render to string in formats like "dd/MM/yyyy HH:mm.ss" and "dd/MM/yyyy HH:mm.ss '('o<g>')'".
An identical class works well, such as this:
// Return the same zone interval, but offset by 1 hour.
var sydneyInterval = _sydney.GetZoneInterval(instant);
return new ZoneInterval(
sydneyInterval.Name,
sydneyInterval.Start,
sydneyInterval.End,
sydneyInterval.WallOffset + Offset.FromHours(1), // adding +1 hr to +10:00 that is Sydney.
sydneyInterval.Savings);
I am hoping to understand what I am missing, why the later works and to resolve the error?
C#, .NET 7, NodaTime 3.1.9, ASP.NET Core Web App, VS 2022
Ah, it looks like it's because you're using the
Endproperty for an interval which extends to the end of time - so it's throwing the (documented) exception.You can detect this and avoid calling
Endwhere it's not appropriate:However, it would be better just to use
DateTimeZone.ForOffset(Offset.FromHours(5))if you want a fixed offset. Currently your zone will vary between UTC+5 and UTC+6, because Australia/Brisbane varies between UTC+10 and UTC+11, or at least did until 1992.