A lightweight, always-on-top Windows desktop widget that shows time and date in Gregorian and Persian (Jalali) calendars โ synced with an online time API and beautifully themed with Material Design.
- ๐๏ธ Dual calendar support โ Gregorian and Persian (Jalali) dates, with Persian digit rendering
- ๐ Multi-timezone โ pick any Windows system timezone; the widget recalculates automatically
- ๐ Windows โ IANA mapping โ powered by TimeZoneConverter, so Windows IDs like
Iran Standard Timemap toAsia/Tehranwhen talking to the time API - โ๏ธ Online time sync โ pulls accurate time from timeapi.io with retry + circuit-breaker resilience (Polly)
- ๐ Configurable format โ 12/24-hour, optional seconds, optional date row
- ๐จ Customizable appearance โ Material Design color picker, opacity slider, three widget sizes
- ๐ฑ๏ธ Draggable, always-on-top window โ right-click for settings, hover for close
- ๐พ Persistent settings โ window position, color, size, language, timezone saved automatically
- ๐ Bilingual UI โ English and Persian (RTL-aware) rendering
- ๐งช Comprehensive unit test suite โ Services, ViewModels, Converters covered with xUnit + Moq + FluentAssertions
The application follows a clean MVVM structure with dependency injection, background hosted services, and a service abstraction layer.
WindowsTimeWidget/
โโโ Abstractions/ Interfaces (ITimeService, ISettingsService, ITimeSyncService)
โโโ Models/ Domain models (WidgetSettings, WidgetLanguage, WidgetSize, TimeApiResponse)
โโโ Services/
โ โโโ DateFormatter.cs Gregorian + Persian formatting, digit conversion
โ โโโ SettingsService.cs JSON persistence under %APPDATA%
โ โโโ TimeService.cs API sync + system-time fallback + drift projection
โ โ (converts Windows timezone IDs โ IANA via TimeZoneConverter)
โ โโโ BackgroundServices/
โ โโโ TimeSyncService.cs IHostedService, periodic + triggered re-sync
โ โโโ TimeSyncOptions.cs Configuration binding
โ โโโ ServiceCollectionExtensions.cs
โโโ ViewModels/
โ โโโ ViewModelBase.cs INotifyPropertyChanged base
โ โโโ RelayCommand.cs ICommand implementation
โ โโโ MainViewModel.cs Drives the widget window
โ โโโ SettingsViewModel.cs Drives the settings window
โโโ Views/
โ โโโ Converters/
โ โ โโโ BoolToFlowDirectionConverter.cs
โ โ โโโ ColorToHexConverter.cs
โ โ โโโ EnumToBoolConverter.cs
โ โ โโโ HexToBrushConverter.cs
โ โโโ UserControls/
โ โ โโโ DateTimeDisplay.xaml The visual content of the widget
โ โโโ Windows/
โ โโโ MainWindow.xaml Frameless, draggable, always-on-top widget
โ โโโ SettingsWindow.xaml Material Design settings dialog
โโโ App.xaml / App.xaml.cs Host builder, DI, HTTP client, Polly policies
โโโ appsettings.json TimeSync configuration
- Dependency injection everywhere โ
Microsoft.Extensions.Hostingdrives the app lifecycle - Interfaces over concretes โ every service has an
I*abstraction, making the ViewModels unit-testable - Resilience by default โ HTTP calls go through Polly retry + circuit-breaker policies
- Non-blocking UI โ time sync runs on a
BackgroundService; the UI just reads projected time - Culture-invariant formatting โ
DateFormatteruses expliciten-USandPersianCalendar, independent of the host culture - Portable timezone IDs โ Windows IDs are converted to IANA at the HTTP boundary, keeping the UI Windows-native while remaining compatible with the API
- Windows 10 / 11
- .NET 10 SDK (with the Windows Desktop workload)
- Internet connection for time sync (the widget falls back to system time if offline)
git clone https://github.com/omiddadvar/Windows-Time-Widget.git
cd Windows-Time-Widget
dotnet restore
dotnet run --project WindowsTimeWidgetdotnet testOr filter by module:
dotnet test --filter "Module~Services"
dotnet test --filter "Module~ViewModels"
dotnet test --filter "Module~Views.Converters"Time sync behavior is controlled via appsettings.json:
{
"TimeSync": {
"SyncInterval": "00:05:00",
"StartupDelay": "00:00:03"
}
}| Key | Default | Description |
|---|---|---|
TimeSync:SyncInterval |
00:05:00 |
How often to re-sync with the API |
TimeSync:StartupDelay |
00:00:03 |
Delay before the first sync after app start |
Persisted at:
%APPDATA%\Mohaasaan\DateTimeWidget\settings.json
Contains timezone, color, size, opacity, language, format flags, and window position.
Windows exposes timezones through TimeZoneInfo.GetSystemTimeZones(), which returns Windows IDs (e.g. Iran Standard Time, N. Central Asia Standard Time). The time API at timeapi.io only accepts IANA IDs (e.g. Asia/Tehran, Asia/Novosibirsk).
TimeService bridges the two using TimeZoneConverter:
- On the way out to the API:
TZConvert.TryWindowsToIana(id, out var iana). - On the way back to
TimeZoneInfo: the IANA ID is passed through unchanged. - If the input is already an IANA ID,
TryWindowsToIanareturnsfalseand the ID is used as-is.
This means the settings dropdown can show Windows-native timezone names (what users expect on Windows), while the HTTP layer stays compatible with the API's IANA-only contract.
| Action | Result |
|---|---|
| Left-click + drag | Move the widget |
| Right-click | Open the settings window |
| Hover top-right corner | Reveal the close button |
| Change timezone in settings | Widget re-syncs immediately |
| Change language to Persian | Dates render RTL with Persian digits |
The project ships with a comprehensive xUnit test suite organized by module to mirror the application structure.
- xUnit โ test framework
- Moq + Moq.Contrib.HttpClient โ mock
ISettingsService,ITimeService, andHttpMessageHandler - FluentAssertions โ readable assertion syntax
| Module | Focus |
|---|---|
Models.TimeApiResponse |
Deserialization of the real snake_case API payload, DateTimeOffset computed property, offset handling, partial payloads |
Services.DateFormatter |
Gregorian + Persian formatting, digit conversion, culture invariance |
Services.SettingsService |
Persistence, cloning, invalid input, corrupt-file recovery, event raising |
Services.TimeService |
API sync success/failure, Windows โ IANA URL translation, drift projection, multi-zone reads, semaphore guard, malformed payload fallback |
Services.BackgroundServices |
Hosted service cadence, option binding, DI registration, exception โ system-time fallback |
ViewModels.ViewModelBase |
SetProperty, OnPropertyChanged semantics |
ViewModels.RelayCommand |
Execute/CanExecute both overloads, null guards |
ViewModels.MainViewModel |
Settings binding, derived properties, timer lifecycle, FormattedTime derived from CurrentTime |
ViewModels.SettingsViewModel |
Load/save/reset, hex normalization, event propagation, timezone selection |
Views.Converters |
All four converters โ including round-trip and fallback paths |
Views.UserControls.DateTimeDisplay |
Construction smoke test, tree structure, binding propagation, visibility, flow direction |
- Every test is annotated with
// Arrange,// Act,// Assertcomments - WPF-dependent tests run on a dedicated STA thread via a
StaRunnerhelper - Settings-based tests back up and restore
%APPDATA%to avoid polluting the host - Assembly-level
DisableTestParallelizationprevents cross-test interference on shared resources
| Concern | Choice |
|---|---|
| Runtime | .NET 10 (net10.0-windows) |
| UI | WPF + MaterialDesignInXamlToolkit |
| DI / Hosting | Microsoft.Extensions.Hosting |
| HTTP | HttpClient + System.Net.Http.Json |
| Resilience | Polly (retry with exponential backoff, circuit breaker) |
| Timezone mapping | TimeZoneConverter 7.2.0 |
| Serialization | System.Text.Json |
| Testing | xUnit, Moq, Moq.Contrib.HttpClient, FluentAssertions |
Contributions are welcome!
- Fork the repo
- Create a feature branch:
git checkout -b feature/amazing-thing - Follow the existing style:
- MVVM โ no logic in code-behind
- Interfaces for every service
- Unit tests for every ViewModel / Service / Converter change
// Arrange,// Act,// Assertcomments in tests
- Run
dotnet testand make sure everything is green - Open a Pull Request
- UI automation tests (FlaUI) for the actual window behavior
- Localization โ currently English + Persian; more languages welcome
- Additional time providers โ NTP, worldtimeapi.org as fallback sources
- Tray icon + startup shortcut support
- Dark / light theme sync with the OS
This project is licensed under the MIT License โ see the LICENSE file for details.
- Time data by timeapi.io
- Icons & styling by MaterialDesignInXamlToolkit
- Persian calendar support via
System.Globalization.PersianCalendar - Windows โ IANA timezone mapping by TimeZoneConverter (MIT)
Made with โค๏ธ for the Windows desktop.
If this project helps you, consider giving it a โญ


