Skip to main content

Vali-TimeZone

IValiTimeZone provides IANA timezone conversion, DST awareness, offset computation, and zone discovery across 45+ curated zones. It wraps the .NET TimeZoneInfo API with a friendlier interface and consistent IANA identifiers.

Installation

dotnet add package Vali-TimeZone

Registration

builder.Services.AddValiTimeZone();
// or via the meta-package:
builder.Services.AddValiTempo();

ValiZoneInfo Class

ValiZoneInfo describes a timezone zone:

PropertyTypeDescription
IdstringIANA zone identifier (e.g. "America/Lima")
DisplayNamestringHuman-readable name (e.g. "Lima (UTC-05:00)")
CountrystringISO 3166-1 alpha-2 country code
StandardOffsetTimeSpanOffset from UTC in standard (non-DST) time
CurrentOffsetTimeSpanOffset from UTC right now (includes DST if active)
SupportsDstboolTrue if this zone observes DST
BaseUtcOffsetTimeSpanBase UTC offset (without DST)

IValiTimeZone API

Convert

Convert a DateTime from one IANA timezone to another:

DateTime lima = tz.Convert(utcTime, "UTC", "America/Lima");
DateTime tokyo = tz.Convert(nyTime, "America/New_York", "Asia/Tokyo");

Signature: DateTime Convert(DateTime dateTime, string fromZone, string toZone)

ConvertOffset

Convert a DateTimeOffset from one zone to another, returning a DateTimeOffset:

DateTimeOffset result = tz.ConvertOffset(dto, "America/Lima", "Europe/Madrid");

Signature: DateTimeOffset ConvertOffset(DateTimeOffset dto, string fromZone, string toZone)

ToUtc

Convert a local datetime in a named timezone to UTC:

DateTime utc = tz.ToUtc(new DateTime(2025, 7, 15, 10, 0, 0), "America/Lima");
// → 2025-07-15 15:00:00 UTC (Lima is UTC-5)

Signature: DateTime ToUtc(DateTime localTime, string fromZone)

FromUtc

Convert a UTC datetime to a named local timezone:

DateTime local = tz.FromUtc(DateTime.UtcNow, "America/Sao_Paulo");

Signature: DateTime FromUtc(DateTime utcTime, string toZone)

ToDateTimeOffset

Convert a DateTime in a given zone to a DateTimeOffset with the correct offset included:

DateTimeOffset dto = tz.ToDateTimeOffset(localDateTime, "Europe/Madrid");
// → DateTimeOffset with +02:00 (summer) or +01:00 (winter)

Signature: DateTimeOffset ToDateTimeOffset(DateTime dateTime, string zone)

GetOffset

Get the UTC offset for a specific datetime in a named zone (DST-aware):

TimeSpan offset = tz.GetOffset("America/New_York", new DateTime(2025, 7, 1));
// → -04:00 (EDT, daylight saving time)

TimeSpan offset2 = tz.GetOffset("America/New_York", new DateTime(2025, 1, 1));
// → -05:00 (EST, standard time)

Signature: TimeSpan GetOffset(string zone, DateTime dateTime)

GetBaseOffset

Get the base (standard, non-DST) UTC offset for a zone:

TimeSpan base1 = tz.GetBaseOffset("America/Lima");
// → -05:00 (Peru is always UTC-5, no DST)

TimeSpan base2 = tz.GetBaseOffset("Europe/Berlin");
// → +01:00 (standard time — CET)

Signature: TimeSpan GetBaseOffset(string zone)

IsDst

Return true if DST is in effect for a given zone at a given time:

bool dst = tz.IsDst("America/New_York", new DateTime(2025, 7, 4));
// → true (summer — EDT)

bool notDst = tz.IsDst("America/New_York", new DateTime(2025, 1, 4));
// → false (winter — EST)

bool neverDst = tz.IsDst("America/Lima", DateTime.Now);
// → false (Lima has no DST)

Signature: bool IsDst(string zone, DateTime dateTime)

OffsetDiff

Compute the offset difference between two zones at a given UTC moment:

TimeSpan diff = tz.OffsetDiff("America/Lima", "Asia/Tokyo", DateTime.UtcNow);
// → 14 hours (Lima UTC-5, Tokyo UTC+9 → diff of 14h)

Signature: TimeSpan OffsetDiff(string zoneA, string zoneB, DateTime utcTime)

FindZone

Find a ValiZoneInfo by IANA identifier:

ValiZoneInfo? zone = tz.FindZone("America/Lima");
if (zone is not null)
{
Console.WriteLine(zone.DisplayName);
Console.WriteLine(zone.SupportsDst);
}

Signature: ValiZoneInfo? FindZone(string zoneId)

AllZones

Return all 45+ curated IANA zones:

IEnumerable<ValiZoneInfo> all = tz.AllZones();
foreach (var z in all.OrderBy(z => z.StandardOffset))
Console.WriteLine($"{z.Id,-35} {z.StandardOffset:hh\\:mm}");

Signature: IEnumerable<ValiZoneInfo> AllZones()

ZonesForCountry

Return all curated zones for a given country code:

IEnumerable<ValiZoneInfo> usZones = tz.ZonesForCountry("US");
// → America/New_York, America/Chicago, America/Denver, America/Los_Angeles, etc.

Signature: IEnumerable<ValiZoneInfo> ZonesForCountry(string countryCode)

IsValidZone

Return true if the IANA zone identifier is recognized:

bool valid = tz.IsValidZone("America/Lima");     // → true
bool invalid = tz.IsValidZone("Invalid/Zone"); // → false

Signature: bool IsValidZone(string zoneId)

Now

Get the current local time in a named timezone:

DateTime nowInTokyo = tz.Now("Asia/Tokyo");
DateTime nowInLima = tz.Now("America/Lima");

Signature: DateTime Now(string zone)

Today

Get the current calendar date in a named timezone:

DateTime todayInSydney = tz.Today("Australia/Sydney");
// → May differ from UTC date when crossing midnight

Signature: DateTime Today(string zone)

IsSameInstant

Return true if two datetime+zone pairs represent the same UTC instant:

bool same = tz.IsSameInstant(
new DateTime(2025, 7, 15, 10, 0, 0), "America/Lima", // UTC-5
new DateTime(2025, 7, 15, 15, 0, 0), "UTC"); // both are 15:00 UTC
// → true

Signature: bool IsSameInstant(DateTime a, string zoneA, DateTime b, string zoneB)

FormatWithZone

Format a datetime with timezone information included:

string formatted = tz.FormatWithZone(DateTime.Now, "America/Lima", "yyyy-MM-dd HH:mm zzz");
// → "2025-07-15 10:00 -05:00"

string formatted2 = tz.FormatWithZone(DateTime.Now, "Asia/Tokyo");
// → "2025-07-16 00:00 JST" (default format)

Signature: string FormatWithZone(DateTime dateTime, string zone, string? format = null)

Curated Zones Sample

IANA IDStandard OffsetCountryDST
UTC+00:00No
America/New_York-05:00USYes
America/Chicago-06:00USYes
America/Denver-07:00USYes
America/Los_Angeles-08:00USYes
America/Lima-05:00PENo
America/Bogota-05:00CONo
America/Mexico_City-06:00MXYes
America/Sao_Paulo-03:00BRYes
America/Buenos_Aires-03:00ARNo
Europe/London+00:00GBYes
Europe/Paris+01:00FRYes
Europe/Berlin+01:00DEYes
Europe/Madrid+01:00ESYes
Europe/Rome+01:00ITYes
Asia/Tokyo+09:00JPNo
Asia/Shanghai+08:00CNNo
Asia/Kolkata+05:30INNo
Asia/Dubai+04:00AENo
Australia/Sydney+10:00AUYes
Pacific/Auckland+12:00NZYes
Africa/Lagos+01:00NGNo

Complete Example

public class GlobalMeetingScheduler(IValiTimeZone tz)
{
public void ScheduleMeeting(DateTime utcTime)
{
var participants = new[]
{
("Lima", "America/Lima"),
("Madrid", "Europe/Madrid"),
("Tokyo", "Asia/Tokyo"),
("New York","America/New_York"),
};

Console.WriteLine($"Meeting UTC: {utcTime:HH:mm}");
Console.WriteLine();

foreach (var (city, zone) in participants)
{
DateTime local = tz.FromUtc(utcTime, zone);
TimeSpan offset = tz.GetOffset(zone, utcTime);
bool isDst = tz.IsDst(zone, utcTime);

Console.WriteLine($"{city,-12} {local:HH:mm} (UTC{offset:+hh\\:mm;-hh\\:mm}{(isDst ? " DST" : "")})");
}

// Find the time difference between Lima and Tokyo
TimeSpan diff = tz.OffsetDiff("America/Lima", "Asia/Tokyo", utcTime);
Console.WriteLine($"\nLima ↔ Tokyo difference: {diff.TotalHours:F0} hours");
}
}