jaytwo.LocalTime
0.1.0-beta-20251008230428
dotnet add package jaytwo.LocalTime --version 0.1.0-beta-20251008230428
NuGet\Install-Package jaytwo.LocalTime -Version 0.1.0-beta-20251008230428
<PackageReference Include="jaytwo.LocalTime" Version="0.1.0-beta-20251008230428" />
<PackageVersion Include="jaytwo.LocalTime" Version="0.1.0-beta-20251008230428" />
<PackageReference Include="jaytwo.LocalTime" />
paket add jaytwo.LocalTime --version 0.1.0-beta-20251008230428
#r "nuget: jaytwo.LocalTime, 0.1.0-beta-20251008230428"
#:package jaytwo.LocalTime@0.1.0-beta-20251008230428
#addin nuget:?package=jaytwo.LocalTime&version=0.1.0-beta-20251008230428&prerelease
#tool nuget:?package=jaytwo.LocalTime&version=0.1.0-beta-20251008230428&prerelease
jaytwo.LocalTime
jaytwo.LocalTime is a tiny, focused library for handling local times without surprises.
Features
- Convert between local time and UTC with a known time zone
- Translate times from one time zone to another
- Handle DST transitions with configurable strict/lenient rules
- Perform clock-aware arithmetic (add/subtract across DST changes correctly)
- Deterministic "now" injection for testing
- Simple ASP.NET Core DI integration (
ILocalTimeService,ILocalTimeTranslator) - Based on IANA TZDB identifiers (via NodaTime) for reliable cross-platform behavior
- Verbose DST Resolution API (detect ambiguous/skipped times, see alternatives)
- Optional truncation of "now" to a specified precision (e.g., seconds) for database compatibility
Installation
Add the NuGet package:
PM> Install-Package jaytwo.LocalTime
Usage
- Use
ILocalTimeServiceto work between a known local time zone and UTC. - Use
ILocalTimeTranslatorto convert a local time from one zone to another.
Examples
Basic Usage
- Local time ↔ UTC
using jaytwo.LocalTime;
var localTimeService = new LocalTimeService("America/Denver"); // throws if TZ ID is invalid
var nowLocal = localTimeService.LocalNow; // DateTimeOffset (local zone)
var nowUtc = localTimeService.UtcNow; // DateTimeOffset (UTC)
// Conversions
var timestamp = localTimeService.GetDateTimeOffset(someLocalDateTime); // local -> DateTimeOffset
var utc = localTimeService.GetUtcDateTime(someLocalDateTime); // local -> UTC DateTime
var local = localTimeService.GetLocalDateTimeFromUtc(someUtcDateTime); // UTC -> local DateTime (Unspecified)
Need deterministic now (e.g., for tests)?
LocalTimeService.Create("America/Denver", utcNowFactory: () => fixedUtcNow)
DST Handling
Pass throwOnAmbiguousOrSkipped: true to throw on DST gaps/ambiguities (or set it in the constructor). Default is lenient resolution.
- Clock-aware arithmetic (handles DST correctly)
// Add across DST transitions
var plus1h = localTimeService.AddHours(DateTime.Parse("2025-03-09T01:00:00"), 1); // returns 2025-03-09T03:00:00-06:00
// Subtract two local wall-clock times (real elapsed time)
var elapsed = localTimeService.Subtract(
DateTime.Parse("2025-11-02T03:00:00"),
DateTime.Parse("2025-11-02T00:00:00")); // returns 4 hours
- Zone → zone translation
var localTimeTranslator = new LocalTimeTranslator("America/Denver", "America/Los_Angeles");
// Local DateTime in input zone → local DateTimeOffset in output zone
var losAngelesDateTimeOffset = localTimeTranslator.ToOutputDateTimeOffset(someDenverDateTime);
// Or get a local DateTime in the output zone
var losAngelesDateTime = localTimeTranslator.ToOutputDateTime(someDenverDateTime);
Note: Using
nowPrecisiononly affectsLocalNowandUtcNow; it does not truncate time values passed to other methods.
- Verbose DST Resolution
// In the US, for a 'fall back' DST transition, the 1 AM hour repeats
var ambiguousLocalTime = DateTime.Parse("2025-11-02T01:30:00");
// resolve with details
var resolved = localTimeService.Resolve(ambiguousLocalTime);
// resolved.IsAmbiguous() → true
// resolved.IsSkipped() → false
// resolved.Matches[0] → 2025-11-02T01:30:00-06:00
// resolved.Matches[1] → 2025-11-02T01:30:00-07:00
// resolved.ForwardShifted → null
// resolved.StartOfIntervalAfter → null
// In the US, for a 'spring forward' DST transition, the 2 AM hour is skipped
var skippedLocalTime = DateTime.Parse("2025-03-09T02:30:00");
// resolve with details
var resolved = localTimeService.Resolve(skippedLocalTime);
// resolved.IsAmbiguous() → false
// resolved.IsSkipped() → true
// resolved.Matches → (empty)
// resolved.ForwardShifted → 2025-03-09T03:30:00-07:00
// resolved.StartOfIntervalAfter → 2025-03-09T03:00:00-07:00
Quantized Now
Optionally truncate "now" to a specified precision (e.g., seconds, milliseconds) for database compatibility. Though
the DateTime type can represent time with sub-microsecond precision, sometimes other systems (e.g., databases) do not.
var service = new LocalTimeService("America/Denver", nowPrecision: TimePrecision.Second);
// DateTimeOffset.Now → 2025-01-01T12:34:56.78987654-07:00 (full sub-microsecond precision)
// service.LocalNow → 2025-01-01T12:34:56.00000000-07:00 (truncated to second precision)
Injecting with DI (typical ASP.NET Core)
services.AddSingleton<ILocalTimeService>(sp => new LocalTimeService("America/Denver"));
Note: "Local" refers to the time zone configured on the service (
TimeZoneId).
Notes
| Concept | Behavior |
|---|---|
| Time zones | TimeZoneId expects an IANA TZDB identifier (e.g., America/Denver). Invalid IDs throw. |
DateTime.Kind |
Local DateTime results use Kind = Unspecified to represent a wall-clock time without an offset (common in UI/domain models). UTC parameters should be passed with DateTimeKind.Utc. |
DST handling (throwOnAmbiguousOrSkipped) |
true → throw on skipped (spring-forward gap) and ambiguous (fall-back overlap) local times. false (default) → resolve leniently (shift into the gap or prefer a standard offset per the underlying implementation). |
Made with ♥ by Jake — Licensed under the MIT License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.2
- jaytwo.Rounding (>= 0.1.2-beta-20251008224103)
- NodaTime (>= 3.2.2)
-
.NETStandard 2.0
- jaytwo.Rounding (>= 0.1.2-beta-20251008224103)
- NodaTime (>= 3.2.2)
-
net6.0
- jaytwo.Rounding (>= 0.1.2-beta-20251008224103)
- NodaTime (>= 3.2.2)
-
net8.0
- jaytwo.Rounding (>= 0.1.2-beta-20251008224103)
- NodaTime (>= 3.2.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on jaytwo.LocalTime:
| Package | Downloads |
|---|---|
|
jaytwo.BackgroundCron
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-beta-20251008230428 | 206 | 10/9/2025 |
| 0.1.0-beta-20251005214649 | 165 | 10/6/2025 |
| 0.1.0-beta-20251005205314 | 149 | 10/6/2025 |
| 0.1.0-beta-20250916172136 | 301 | 9/16/2025 |
| 0.1.0-beta-20250915160052 | 277 | 9/15/2025 |
| 0.1.0-beta-20250825215428 | 226 | 8/26/2025 |