diff --git a/src/JobsJobsJobs/Client/AppState.cs b/src/JobsJobsJobs/Client/AppState.cs index 90e9825..8e4e00b 100644 --- a/src/JobsJobsJobs/Client/AppState.cs +++ b/src/JobsJobsJobs/Client/AppState.cs @@ -1,4 +1,6 @@ using JobsJobsJobs.Shared; +using Microsoft.JSInterop; +using NodaTime; using System; using System.Collections.Generic; using System.Net.Http; @@ -75,6 +77,32 @@ namespace JobsJobsJobs.Client return _continents; } + private DateTimeZone? _tz = null; + + /// + /// Get the time zone for the current user's browser + /// + /// The JS interop runtime for the application + /// The time zone based on the user's browser + public async Task GetTimeZone(IJSRuntime js) + { + if (_tz == null) + { + try + { + _tz = DateTimeZoneProviders.Tzdb.GetZoneOrNull(await js.InvokeAsync("getTimeZone")); + } + catch (Exception) { } + } + if (_tz == null) + { + // Either the zone wasn't found, or the user's browser denied us access to it; there's not much to do + // here but set it to UTC and move on + _tz = DateTimeZoneProviders.Tzdb.GetZoneOrNull("Etc/UTC")!; + } + return _tz; + } + public AppState() { } private void NotifyChanged() => OnChange.Invoke(); diff --git a/src/JobsJobsJobs/Client/Shared/FullDate.razor b/src/JobsJobsJobs/Client/Shared/FullDate.razor index cdb1cc6..da158dd 100644 --- a/src/JobsJobsJobs/Client/Shared/FullDate.razor +++ b/src/JobsJobsJobs/Client/Shared/FullDate.razor @@ -1,23 +1,4 @@ -@using NodaTime -@using NodaTime.Text -@using System.Globalization +@inject IJSRuntime js +@inject AppState state @Translated - -@code { - /// - /// The pattern with which dates will be formatted - /// - private static InstantPattern pattern = InstantPattern.Create("ld", CultureInfo.CurrentCulture); - - /// - /// The date to be formatted - /// - [Parameter] - public Instant TheDate { get; set; } - - /// - /// The formatted date - /// - private string Translated => pattern.Format(TheDate); -} diff --git a/src/JobsJobsJobs/Client/Shared/FullDate.razor.cs b/src/JobsJobsJobs/Client/Shared/FullDate.razor.cs new file mode 100644 index 0000000..c0fb3e7 --- /dev/null +++ b/src/JobsJobsJobs/Client/Shared/FullDate.razor.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Components; +using NodaTime; +using NodaTime.Text; +using System.Threading.Tasks; + +namespace JobsJobsJobs.Client.Shared +{ + public partial class FullDate : ComponentBase + { + /// + /// The pattern with which dates will be formatted + /// + private static readonly ZonedDateTimePattern Pattern = + ZonedDateTimePattern.CreateWithCurrentCulture("ld", DateTimeZoneProviders.Tzdb); + + /// + /// The date to be formatted + /// + [Parameter] + public Instant TheDate { get; set; } + + /// + /// The formatted date + /// + private string Translated { get; set; } = ""; + + protected override async Task OnInitializedAsync() => + Translated = Pattern.Format(TheDate.InZone(await state.GetTimeZone(js))); + } +} diff --git a/src/JobsJobsJobs/Client/Shared/FullDateTime.razor b/src/JobsJobsJobs/Client/Shared/FullDateTime.razor index 49d6ed3..da158dd 100644 --- a/src/JobsJobsJobs/Client/Shared/FullDateTime.razor +++ b/src/JobsJobsJobs/Client/Shared/FullDateTime.razor @@ -1,23 +1,4 @@ -@using NodaTime -@using NodaTime.Text -@using System.Globalization +@inject IJSRuntime js +@inject AppState state @Translated - -@code { - /// - /// The pattern with which dates will be formatted - /// - private static InstantPattern pattern = InstantPattern.Create("ld ' at ' lt", CultureInfo.CurrentCulture); - - /// - /// The date to be formatted - /// - [Parameter] - public Instant TheDate { get; set; } - - /// - /// The formatted date - /// - private string Translated => pattern.Format(TheDate); -} diff --git a/src/JobsJobsJobs/Client/Shared/FullDateTime.razor.cs b/src/JobsJobsJobs/Client/Shared/FullDateTime.razor.cs new file mode 100644 index 0000000..18f5fc0 --- /dev/null +++ b/src/JobsJobsJobs/Client/Shared/FullDateTime.razor.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Components; +using NodaTime; +using NodaTime.Text; +using System.Threading.Tasks; + +namespace JobsJobsJobs.Client.Shared +{ + public partial class FullDateTime : ComponentBase + { + /// + /// The pattern with which dates will be formatted + /// + private static readonly ZonedDateTimePattern Pattern = + ZonedDateTimePattern.CreateWithCurrentCulture("ld ' at ' lt", DateTimeZoneProviders.Tzdb); + + /// + /// The date to be formatted + /// + [Parameter] + public Instant TheDate { get; set; } + + /// + /// The formatted date + /// + private string Translated { get; set; } = ""; + + protected override async Task OnInitializedAsync() => + Translated = Pattern.Format(TheDate.InZone(await state.GetTimeZone(js))); + } +} diff --git a/src/JobsJobsJobs/Client/wwwroot/index.html b/src/JobsJobsJobs/Client/wwwroot/index.html index b86b985..4de33eb 100644 --- a/src/JobsJobsJobs/Client/wwwroot/index.html +++ b/src/JobsJobsJobs/Client/wwwroot/index.html @@ -43,6 +43,9 @@ function setPageTitle(theTitle) { document.title = theTitle } + function getTimeZone() { + return Intl.DateTimeFormat().resolvedOptions().timeZone + } diff --git a/src/JobsJobsJobs/Server/Pages/_Host.cshtml b/src/JobsJobsJobs/Server/Pages/_Host.cshtml index e37e190..d77f79c 100644 --- a/src/JobsJobsJobs/Server/Pages/_Host.cshtml +++ b/src/JobsJobsJobs/Server/Pages/_Host.cshtml @@ -35,6 +35,9 @@ function setPageTitle(theTitle) { document.title = theTitle } + function getTimeZone() { + return Intl.DateTimeFormat().resolvedOptions().timeZone + }