Skip to content

Commit 6c584e6

Browse files
committed
Update README and Home.razor to clarify local time handling issues and hide "Today" and "Now" buttons in Ant Design Blazor
1 parent 1938044 commit 6c584e6

File tree

2 files changed

+75
-69
lines changed

2 files changed

+75
-69
lines changed

README.md

Lines changed: 57 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,39 @@
22

33
[![NuGet Version](https://img.shields.io/nuget/v/BlazorLocalTime?style=flat-square&logo=NuGet&color=0080CC)](https://www.nuget.org/packages/BlazorLocalTime/) ![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/arika0093/BlazorLocalTime/test.yaml?branch=main&label=Test&style=flat-square) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/arika0093/BlazorLocalTime?style=flat-square)
44

5-
`BlazorLocalTime` provides functionality to convert `DateTime` values to the user's local time zone in Blazor applications.
5+
`BlazorLocalTime` provides functionality to convert `DateTime` values to the user's local time zone in Blazor Server applications.
66

7-
## Demo
8-
[arika0093.github.io/BlazorLocalTime/](https://arika0093.github.io/BlazorLocalTime/)
7+
[Demo Page](https://arika0093.github.io/BlazorLocalTime/)
98

10-
## Installation
9+
## What's this?
10+
The following code contains a bug. Can you spot it?
11+
12+
```razor
13+
<p>@DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")</p>
14+
```
15+
16+
The issue is that this displays the **current time on the server, not the user's local time**.
17+
The time is formatted according to the Blazor host server's time zone, which may not match the user's time zone.
18+
19+
This bug occurs when the Blazor host server's time zone ≠ user's time zone. Because of this, it's an easy bug to overlook during development.
20+
21+
A similar issue arises with date/time input fields. In short, you can't determine "which time zone" the entered time refers to.
22+
23+
```razor
24+
<InputDate Type="InputDateType.DateTimeLocal" @bind-Value="dt" />
25+
@code {
26+
private DateTime dt { get; set; }
27+
private void SaveToDatabase()
28+
{
29+
// Cannot correctly convert to UTC (uses server's time zone)
30+
var utc = dt?.ToUniversalTime();
31+
}
32+
}
33+
```
34+
35+
You can use `BlazorLocalTime` to solve these problems.
36+
37+
## Setup
1138
Install `BlazorLocalTime` from [NuGet](https://www.nuget.org/packages/BlazorLocalTime):
1239

1340
```bash
@@ -77,51 +104,7 @@ Input forms also support separate date and time inputs:
77104
}
78105
```
79106

80-
## Using with UI Libraries
81-
82-
The `LocalTimeForm` component can be used with various UI libraries to create forms that handle local time input.
83-
Below are examples using [MudBlazor](https://mudblazor.com/), [Fluent UI](https://www.fluentui-blazor.net), and [Ant Design Blazor](https://antblazor.com/) components.
84-
85-
### MudBlazor
86-
87-
```razor
88-
<LocalTimeForm @bind-Value="Dt" Context="dtf">
89-
<MudDatePicker Label="Date" @bind-Date="dtf.Value" ShowToolbar="false" />
90-
<MudTimePicker Label="Time" @bind-Time="dtf.TimeSpan" ShowToolbar="false" />
91-
</LocalTimeForm>
92-
93-
@code {
94-
private DateTime? Dt { get; set; } = DateTime.UtcNow;
95-
}
96-
```
97-
98-
### Fluent UI
99-
100-
```razor
101-
<LocalTimeForm @bind-Value="Dt" Context="dtf">
102-
<FluentDatePicker Label="Date" @bind-Value="dtf.Value" />
103-
<FluentTimePicker Label="Time" @bind-Value="dtf.Value" />
104-
</LocalTimeForm>
105-
106-
@code {
107-
private DateTime? Dt { get; set; } = DateTime.UtcNow;
108-
}
109-
```
110-
111-
### Ant Design Blazor
112-
113-
```razor
114-
<LocalTimeForm @bind-Value="Dt" Context="dtf">
115-
<DatePicker TValue="DateTime?" @bind-Value="dtf.Value" ShowTime="@true" />
116-
@* Alternatively, you can use separate date and time pickers *@
117-
<DatePicker TValue="DateOnly?" @bind-Value="dtf.Date" />
118-
<TimePicker TValue="TimeOnly?" @bind-Value="dtf.Time" />
119-
</LocalTimeForm>
120-
121-
@code {
122-
private DateTime? Dt { get; set; } = DateTime.UtcNow;
123-
}
124-
```
107+
and more usage examples can be found in the [Demo](https://arika0093.github.io/BlazorLocalTime/).
125108

126109
## Using as a Service
127110

@@ -143,6 +126,11 @@ During the initial rendering (`OnInitialized`), the user's local time zone may n
143126
In such cases, you can use `ILocalTimeService.LocalTimeZoneChanged` to wait until the local time zone becomes available.
144127

145128
```razor
129+
@if(LocalTimeService.IsTimeZoneInfoAvailable)
130+
{
131+
<p>Current Time is @LocalTimeService.Now</p>
132+
}
133+
146134
@implements IDisposable
147135
@inject ILocalTimeService LocalTimeService
148136
@code {
@@ -158,14 +146,30 @@ In such cases, you can use `ILocalTimeService.LocalTimeZoneChanged` to wait unti
158146
159147
private void OnLocalTimeZoneChanged(object? sender, EventArgs e)
160148
{
161-
if(LocalTimeService.IsTimeZoneInfoAvailable)
162-
{
163-
// can use LocalTimeService.ToLocalTime() now
164-
}
149+
StateHasChanged();
165150
}
166151
}
167152
```
168153

154+
## Testing
155+
When testing, it is not practical to manually change the browser and runtime time zones each time.
156+
To address this, a function is provided to forcibly change the runtime time zone (`TimeZoneInfo.Local`).
157+
158+
```csharp
159+
// UTC
160+
LocalTimeZoneOverwrite.UseUtc();
161+
// Custom Offset (e.g., UTC+9)
162+
LocalTimeZoneOverwrite.UseCustomOffset(TimeSpan.FromHours(9));
163+
```
164+
165+
> [!NOTE]
166+
> Since the demo site is running on `WebAssembly`, the time zone of RunTime normally matches the browser's time zone and should not work well.
167+
Therefore, the above function is executed to force the time zone on the runtime side to be fixed to UTC.
168+
169+
> [!WARNING]
170+
> This feature is intended for testing only. It is not recommended to change `TimeZoneInfo.Local` in production applications.
171+
172+
169173
## Reference
170174

171175
[This article](https://www.meziantou.net/convert-datetime-to-user-s-time-zone-with-server-side-blazor-time-provider.htm) was used as a major reference. I would like to express my gratitude for the reference article.

example/BlazorLocalTimeSample/Pages/Home.razor

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,6 @@
2020
</a>
2121
</p>
2222

23-
<h2>Installation</h2>
24-
<p>Install <code>BlazorLocalTime</code> from NuGet:</p>
25-
<pre><code>dotnet add package BlazorLocalTime
26-
</code></pre>
27-
28-
<p>Next, register the service in your <code>Program.cs</code>:</p>
29-
<pre><code class="language-csharp">builder.Services.AddBlazorLocalTimeService();
30-
</code></pre>
31-
32-
<p>
33-
Finally, add the following component to <code>Routes.razor</code> (or <code>MainLayout.razor</code>, etc.):
34-
</p>
35-
<pre><code class="language-razor">@@using BlazorLocalTime
36-
&lt;BlazorLocalTimeProvider /&gt;
37-
</code></pre>
38-
3923
<h2>Using as a Component</h2>
4024
<p>To simply display a local time as text, use the <code>LocalTimeText</code> component:</p>
4125
<pre><code class="language-razor">&lt;LocalTimeText Value="@@DateTime.UtcNow" Format="yyyy-MM-dd HH:mm:ssK" /&gt;
@@ -180,6 +164,11 @@
180164

181165
<h3>Ant Design Blazor</h3>
182166

167+
<p>
168+
Due to implementation limitations, the <code>Today</code> and <code>Now</code> buttons reference the server-side current time and do not work as expected. <br/>
169+
Therefore, it is recommended to hide these buttons.
170+
</p>
171+
183172
<pre><code class="language-razor">Value: @@Dt?.ToString("yyyy-MM-dd HH:mm:ssK")
184173
&lt;br /&gt;
185174
&lt;LocalTimeForm @@bind-Value="Dt" Context="dtf"&gt;
@@ -189,6 +178,13 @@
189178
&lt;TimePicker TValue="TimeOnly?" @@bind-Value="dtf.Time" /&gt;
190179
&lt;/LocalTimeForm&gt;
191180

181+
&lt;style&gt;
182+
/* Hide "Today" and "Now" buttons */
183+
a.ant-picker-now-btn, a.ant-picker-today-btn {
184+
display: none;
185+
}
186+
&lt;/style&gt;
187+
192188
@@code {
193189
private DateTime? Dt { get; set; } = DateTime.UtcNow;
194190
}
@@ -203,6 +199,12 @@
203199
<DatePicker TValue="DateOnly?" @bind-Value="dtf.Date" />
204200
<TimePicker TValue="TimeOnly?" @bind-Value="dtf.Time" />
205201
</LocalTimeForm>
202+
203+
<style>
204+
a.ant-picker-now-btn, a.ant-picker-today-btn {
205+
display: none;
206+
}
207+
</style>
206208
</div>
207209

208210
<h2>Using as a Service</h2>

0 commit comments

Comments
 (0)