diff --git a/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs b/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs index 87f58fa..22b1bdc 100644 --- a/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs +++ b/DiunaBI.UI.Shared/Extensions/ServiceCollectionExtensions.cs @@ -44,6 +44,7 @@ public static class ServiceCollectionExtensions services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); // Filter state services (scoped to maintain state during user session) services.AddScoped(); diff --git a/DiunaBI.UI.Shared/Pages/DataInbox/Index.razor b/DiunaBI.UI.Shared/Pages/DataInbox/Index.razor index fb3f281..a3dc0de 100644 --- a/DiunaBI.UI.Shared/Pages/DataInbox/Index.razor +++ b/DiunaBI.UI.Shared/Pages/DataInbox/Index.razor @@ -52,7 +52,7 @@
@row.Name
@row.Source
-
@row.CreatedAt.ToString("yyyy-MM-dd HH:mm:ss")
+
@DateTimeHelper.FormatDateTime(row.CreatedAt)
No data inbox items to display diff --git a/DiunaBI.UI.Shared/Pages/DataInbox/Index.razor.cs b/DiunaBI.UI.Shared/Pages/DataInbox/Index.razor.cs index 02fbbf2..b294995 100644 --- a/DiunaBI.UI.Shared/Pages/DataInbox/Index.razor.cs +++ b/DiunaBI.UI.Shared/Pages/DataInbox/Index.razor.cs @@ -15,6 +15,7 @@ public partial class Index : ComponentBase [Inject] private NavigationManager NavigationManager { get; set; } = default!; [Inject] private DataInboxFilterStateService FilterStateService { get; set; } = default!; [Inject] private IJSRuntime JSRuntime { get; set; } = default!; + [Inject] private DateTimeHelper DateTimeHelper { get; set; } = default!; private PagedResult dataInbox = new(); @@ -23,6 +24,7 @@ public partial class Index : ComponentBase protected override async Task OnInitializedAsync() { + await DateTimeHelper.InitializeAsync(); filterRequest = FilterStateService.FilterRequest; await LoadDataInbox(); } diff --git a/DiunaBI.UI.Shared/Pages/Jobs/Details.razor b/DiunaBI.UI.Shared/Pages/Jobs/Details.razor index 4574e4a..26c35bc 100644 --- a/DiunaBI.UI.Shared/Pages/Jobs/Details.razor +++ b/DiunaBI.UI.Shared/Pages/Jobs/Details.razor @@ -6,6 +6,7 @@ @inject EntityChangeHubService HubService @inject NavigationManager NavigationManager @inject ISnackbar Snackbar +@inject DateTimeHelper DateTimeHelper @implements IDisposable @@ -92,14 +93,14 @@ - - -
- @row.CreatedAt.ToString("yyyy-MM-dd HH:mm") + @DateTimeHelper.FormatDateTime(row.CreatedAt, "yyyy-MM-dd HH:mm")
- @(row.LastAttemptAt?.ToString("yyyy-MM-dd HH:mm") ?? "-") + @DateTimeHelper.FormatDateTime(row.LastAttemptAt, "yyyy-MM-dd HH:mm")
diff --git a/DiunaBI.UI.Shared/Pages/Jobs/Index.razor.cs b/DiunaBI.UI.Shared/Pages/Jobs/Index.razor.cs index c57ca8d..8ed89a3 100644 --- a/DiunaBI.UI.Shared/Pages/Jobs/Index.razor.cs +++ b/DiunaBI.UI.Shared/Pages/Jobs/Index.razor.cs @@ -15,6 +15,7 @@ public partial class Index : ComponentBase, IDisposable [Inject] private ISnackbar Snackbar { get; set; } = default!; [Inject] private NavigationManager NavigationManager { get; set; } = default!; [Inject] private IJSRuntime JSRuntime { get; set; } = default!; + [Inject] private DateTimeHelper DateTimeHelper { get; set; } = default!; private PagedResult jobs = new(); private bool isLoading = false; @@ -25,6 +26,7 @@ public partial class Index : ComponentBase, IDisposable protected override async Task OnInitializedAsync() { + await DateTimeHelper.InitializeAsync(); await LoadJobs(); // Subscribe to SignalR entity changes diff --git a/DiunaBI.UI.Shared/Pages/Layers/Details.razor b/DiunaBI.UI.Shared/Pages/Layers/Details.razor index 15f5941..7f6de90 100644 --- a/DiunaBI.UI.Shared/Pages/Layers/Details.razor +++ b/DiunaBI.UI.Shared/Pages/Layers/Details.razor @@ -58,7 +58,7 @@ }
- - @context.Code @context.Desc1 - @context.ModifiedAt.ToString("g") + @DateTimeHelper.FormatDateTime(context.ModifiedAt, "yyyy-MM-dd HH:mm") @GetModifiedByUsername(context.ModifiedById) diff --git a/DiunaBI.UI.Shared/Pages/Layers/Details.razor.cs b/DiunaBI.UI.Shared/Pages/Layers/Details.razor.cs index 74fdb3a..5251c6f 100644 --- a/DiunaBI.UI.Shared/Pages/Layers/Details.razor.cs +++ b/DiunaBI.UI.Shared/Pages/Layers/Details.razor.cs @@ -26,6 +26,9 @@ public partial class Details : ComponentBase [Inject] private ISnackbar Snackbar { get; set; } = null!; + [Inject] + private DateTimeHelper DateTimeHelper { get; set; } = null!; + private LayerDto? layer; private List records = new(); private List displayedColumns = new(); @@ -52,6 +55,7 @@ public partial class Details : ComponentBase protected override async Task OnInitializedAsync() { + await DateTimeHelper.InitializeAsync(); await LoadLayer(); } diff --git a/DiunaBI.UI.Shared/Services/DateTimeHelper.cs b/DiunaBI.UI.Shared/Services/DateTimeHelper.cs new file mode 100644 index 0000000..6e5238c --- /dev/null +++ b/DiunaBI.UI.Shared/Services/DateTimeHelper.cs @@ -0,0 +1,80 @@ +using Microsoft.JSInterop; + +namespace DiunaBI.UI.Shared.Services; + +public class DateTimeHelper +{ + private readonly IJSRuntime _jsRuntime; + private TimeZoneInfo? _userTimeZone; + private bool _initialized = false; + + public DateTimeHelper(IJSRuntime jsRuntime) + { + _jsRuntime = jsRuntime; + } + + public async Task InitializeAsync() + { + if (_initialized) return; + + try + { + // Get the user's timezone from JavaScript + var timeZoneId = await _jsRuntime.InvokeAsync("eval", "Intl.DateTimeFormat().resolvedOptions().timeZone"); + + // Try to find the TimeZoneInfo + try + { + _userTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId); + } + catch + { + // Fallback to local timezone if the IANA timezone ID is not found + _userTimeZone = TimeZoneInfo.Local; + } + } + catch + { + // Fallback to local timezone if JavaScript interop fails + _userTimeZone = TimeZoneInfo.Local; + } + + _initialized = true; + } + + public string FormatDateTime(DateTime? dateTime, string format = "yyyy-MM-dd HH:mm:ss") + { + if (!dateTime.HasValue) + return "-"; + + if (!_initialized) + { + // If not initialized yet, just format as-is (will be UTC) + return dateTime.Value.ToString(format); + } + + // Convert UTC to user's timezone + var localDateTime = TimeZoneInfo.ConvertTimeFromUtc(dateTime.Value, _userTimeZone ?? TimeZoneInfo.Local); + return localDateTime.ToString(format); + } + + public string FormatDate(DateTime? dateTime, string format = "yyyy-MM-dd") + { + return FormatDateTime(dateTime, format); + } + + public string FormatTime(DateTime? dateTime, string format = "HH:mm:ss") + { + return FormatDateTime(dateTime, format); + } + + public string GetTimeZoneAbbreviation() + { + if (!_initialized || _userTimeZone == null) + return "UTC"; + + return _userTimeZone.IsDaylightSavingTime(DateTime.Now) + ? _userTimeZone.DaylightName + : _userTimeZone.StandardName; + } +}