
Dotnet Timezone
Apply cross-platform .NET timezone patterns when solo builders ship APIs, schedulers, or billing windows that must behave correctly on Linux containers and Windows hosts.
Overview
dotnet-timezone is an agent skill for the Build phase that supplies vetted .NET timezone code patterns spanning TimeZoneInfo, TimeZoneConverter, and NodaTime.
Install
npx skills add https://github.com/github/awesome-copilot --skill dotnet-timezoneWhat is this skill?
- Documents three patterns: Windows-only TimeZoneInfo, cross-platform TimeZoneConverter (recommended default), and NodaTim
- Shows TZConvert accepting IANA IDs (Asia/Colombo) and legacy Windows IDs (Sri Lanka Standard Time)
- Explicit guidance to avoid bare TimeZoneInfo when the app runs in containers or mixed OS environments
- Copy-paste-ready C# snippets with package references for TimeZoneConverter 6.* and NodaTime 3.*
- 3 documented implementation patterns (TimeZoneInfo, TimeZoneConverter, NodaTime)
Adoption & trust: 1.3k installs on skills.sh; 34.6k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You need reliable local-time conversion in .NET but Windows timezone IDs break on Linux containers and DST edge cases are easy to get wrong.
Who is it for?
Solo builders writing .NET APIs or background jobs that must run on both Windows dev machines and Linux production.
Skip if: Teams that only target Windows desktop with fixed zones and no container path, or front-end-only locale formatting with no server conversion.
When should I use this skill?
Implementing or refactoring .NET code that converts between UTC and local zones, especially before deploying to Linux or containers.
What do I get? / Deliverables
You pick the right library tier for your deployment surface and paste patterns that convert UTC safely across platforms.
- Package references and C# snippets for the chosen timezone approach
- Documented choice between TimeZoneConverter default and NodaTime for edge cases
Recommended Skills
Journey fit
Timezone logic is implemented during backend and API work, before ship—not a distribution or ops concern. Canonical shelf is backend because the skill is code-pattern reference for server-side DateTime handling, not frontend UI formatting alone.
How it compares
Use as a procedural pattern sheet instead of guessing TimeZoneInfo IDs from Stack Overflow snippets.
Common Questions / FAQ
Who is dotnet-timezone for?
Indie and solo .NET developers implementing server-side time conversion, scheduling, or reporting across Windows and Linux hosts.
When should I use dotnet-timezone?
During Build backend work when you add billing cutoffs, user-local timestamps, or cron windows and need a default of TimeZoneConverter unless NodaTime-level rigor is required.
Is dotnet-timezone safe to install?
Review the Security Audits panel on this Prism page before installing; the skill is documentation-only patterns with no mandated shell or network access in the SKILL body.
SKILL.md
READMESKILL.md - Dotnet Timezone
# .NET Timezone Code Patterns ## Pattern 1: Basic TimeZoneInfo Use this only when the application is Windows-only and Windows timezone IDs are acceptable. ```csharp DateTime utcNow = DateTime.UtcNow; TimeZoneInfo sriLankaTz = TimeZoneInfo.FindSystemTimeZoneById("Sri Lanka Standard Time"); DateTime localTime = TimeZoneInfo.ConvertTimeFromUtc(utcNow, sriLankaTz); DateTime backToUtc = TimeZoneInfo.ConvertTimeToUtc(localTime, sriLankaTz); TimeZoneInfo tokyoTz = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time"); DateTime tokyoTime = TimeZoneInfo.ConvertTime(localTime, sriLankaTz, tokyoTz); ``` Use `TimeZoneConverter` or `NodaTime` instead for Linux, containers, or mixed environments. ## Pattern 2: Cross-Platform With TimeZoneConverter Recommended default for most .NET apps that run across Windows and Linux. ```xml <PackageReference Include="TimeZoneConverter" Version="6.*" /> ``` ```csharp using TimeZoneConverter; TimeZoneInfo tz = TZConvert.GetTimeZoneInfo("Asia/Colombo"); DateTime converted = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, tz); ``` This also accepts Windows IDs: ```csharp TimeZoneInfo tz = TZConvert.GetTimeZoneInfo("Sri Lanka Standard Time"); ``` ## Pattern 3: NodaTime Use this for strict timezone arithmetic, recurring schedules, or DST edge cases where correctness matters more than minimal dependencies. ```xml <PackageReference Include="NodaTime" Version="3.*" /> ``` ```csharp using NodaTime; DateTimeZone colomboZone = DateTimeZoneProviders.Tzdb["Asia/Colombo"]; Instant now = SystemClock.Instance.GetCurrentInstant(); ZonedDateTime colomboTime = now.InZone(colomboZone); DateTimeZone tokyoZone = DateTimeZoneProviders.Tzdb["Asia/Tokyo"]; ZonedDateTime tokyoTime = colomboTime.WithZone(tokyoZone); LocalDateTime localDt = new LocalDateTime(2024, 6, 15, 14, 30, 0); ZonedDateTime zoned = colomboZone.AtStrictly(localDt); Instant utcInstant = zoned.ToInstant(); ``` ## Pattern 4: DateTimeOffset For APIs Prefer `DateTimeOffset` for values crossing service or process boundaries. ```csharp using TimeZoneConverter; DateTimeOffset utcNow = DateTimeOffset.UtcNow; TimeZoneInfo tz = TZConvert.GetTimeZoneInfo("Asia/Colombo"); DateTimeOffset colomboTime = TimeZoneInfo.ConvertTime(utcNow, tz); ``` ## Pattern 5: ASP.NET Core Persistence And Presentation Store UTC, convert at the edges. ```csharp using TimeZoneConverter; entity.CreatedAtUtc = DateTime.UtcNow; public DateTimeOffset ToUserTime(DateTime utc, string userIanaTimezone) { var tz = TZConvert.GetTimeZoneInfo(userIanaTimezone); return TimeZoneInfo.ConvertTimeFromUtc(utc, tz); } ``` ## Pattern 6: Scheduling And Recurring Jobs Translate a user-facing local time to UTC before scheduling. ```csharp using TimeZoneConverter; TimeZoneInfo tz = TZConvert.GetTimeZoneInfo("Asia/Colombo"); DateTime scheduledLocal = new DateTime(2024, 12, 1, 9, 0, 0, DateTimeKind.Unspecified); DateTime scheduledUtc = TimeZoneInfo.ConvertTimeToUtc(scheduledLocal, tz); ``` With Hangfire: ```csharp RecurringJob.AddOrUpdate( "morning-job", () => DoWork(), "0 9 * * *", new RecurringJobOptions { TimeZone = tz }); ``` ## Pattern 7: Ambiguous And Invalid DST Times Check for repeated or skipped local timestamps when the timezone observes daylight saving time. ```csharp using TimeZoneConverter; TimeZoneInfo tz = TZConvert.GetTimeZoneInfo("America/New_York"); DateTime localTime = new DateTime(2024, 11, 3, 1, 30, 0); if (tz.IsAmbiguousTime(localTime)) { var offsets = tz.GetAmbiguousTimeOffsets(localTime); var standardOffset = offsets.Min(); var dto = new DateTimeOffset(localTime, standardOffset); } if (tz.IsInvalidTime(localTime)) { localTime = localTime.AddHours(1); } ``` ## Common Mistakes | Wrong | Better | | --- | --- | | `DateTime.Now` in server code | `DateTime.UtcNow` | | Storing local timestamps in the database | Store UTC and convert for display | | Hardcoding offsets such as `+05:30` | Use timezone IDs | | Using `Find