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
+ }