Ir al contenido principal

Vali-TimeZone

IValiTimeZone proporciona conversión de zonas horarias IANA, conciencia de horario de verano, cálculo de offsets y descubrimiento de zonas en más de 45 zonas seleccionadas. Envuelve la API TimeZoneInfo de .NET con una interfaz más amigable e identificadores IANA consistentes.

Instalación

dotnet add package Vali-TimeZone

Registro

builder.Services.AddValiTimeZone();
// o mediante el meta-paquete:
builder.Services.AddValiTempo();

Clase ValiZoneInfo

ValiZoneInfo describe una zona horaria:

PropiedadTipoDescripción
IdstringIdentificador IANA de zona (ej. "America/Lima")
DisplayNamestringNombre legible para humanos (ej. "Lima (UTC-05:00)")
CountrystringCódigo de país ISO 3166-1 alpha-2
StandardOffsetTimeSpanOffset desde UTC en horario estándar (sin horario de verano)
CurrentOffsetTimeSpanOffset desde UTC ahora mismo (incluye DST si está activo)
SupportsDstboolVerdadero si esta zona observa DST
BaseUtcOffsetTimeSpanOffset UTC base (sin DST)

API de IValiTimeZone

Convert

Convierte un DateTime de una zona horaria IANA a otra:

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

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

ConvertOffset

Convierte un DateTimeOffset de una zona a otra, devolviendo un DateTimeOffset:

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

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

ToUtc

Convierte un datetime local en una zona horaria nombrada a UTC:

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

Firma: DateTime ToUtc(DateTime localTime, string fromZone)

FromUtc

Convierte un datetime UTC a una zona horaria local nombrada:

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

Firma: DateTime FromUtc(DateTime utcTime, string toZone)

ToDateTimeOffset

Convierte un DateTime en una zona dada a un DateTimeOffset con el offset correcto incluido:

DateTimeOffset dto = tz.ToDateTimeOffset(localDateTime, "Europe/Madrid");
// → DateTimeOffset con +02:00 (verano) o +01:00 (invierno)

Firma: DateTimeOffset ToDateTimeOffset(DateTime dateTime, string zone)

GetOffset

Obtiene el offset UTC para un datetime específico en una zona nombrada (con conciencia de DST):

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

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

Firma: TimeSpan GetOffset(string zone, DateTime dateTime)

GetBaseOffset

Obtiene el offset UTC base (estándar, sin DST) de una zona:

TimeSpan base1 = tz.GetBaseOffset("America/Lima");
// → -05:00 (Perú siempre es UTC-5, sin DST)

TimeSpan base2 = tz.GetBaseOffset("Europe/Berlin");
// → +01:00 (horario estándar — CET)

Firma: TimeSpan GetBaseOffset(string zone)

IsDst

Devuelve true si el horario de verano está en vigor en una zona dada a una hora dada:

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

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

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

Firma: bool IsDst(string zone, DateTime dateTime)

OffsetDiff

Calcula la diferencia de offset entre dos zonas en un momento UTC dado:

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

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

FindZone

Encuentra un ValiZoneInfo por identificador IANA:

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

Firma: ValiZoneInfo? FindZone(string zoneId)

AllZones

Devuelve todas las más de 45 zonas IANA seleccionadas:

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

Firma: IEnumerable<ValiZoneInfo> AllZones()

ZonesForCountry

Devuelve todas las zonas seleccionadas para un código de país dado:

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

Firma: IEnumerable<ValiZoneInfo> ZonesForCountry(string countryCode)

IsValidZone

Devuelve true si el identificador de zona IANA es reconocido:

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

Firma: bool IsValidZone(string zoneId)

Now

Obtiene la hora local actual en una zona horaria nombrada:

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

Firma: DateTime Now(string zone)

Today

Obtiene la fecha calendario actual en una zona horaria nombrada:

DateTime todayInSydney = tz.Today("Australia/Sydney");
// → Puede diferir de la fecha UTC al cruzar la medianoche

Firma: DateTime Today(string zone)

IsSameInstant

Devuelve true si dos pares de datetime+zona representan el mismo instante UTC:

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"); // ambas son 15:00 UTC
// → true

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

FormatWithZone

Formatea un datetime con información de zona horaria incluida:

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" (formato predeterminado)

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

Muestra de zonas seleccionadas

ID IANAOffset estándarPaísDST
UTC+00:00No
America/New_York-05:00US
America/Chicago-06:00US
America/Denver-07:00US
America/Los_Angeles-08:00US
America/Lima-05:00PENo
America/Bogota-05:00CONo
America/Mexico_City-06:00MX
America/Sao_Paulo-03:00BR
America/Buenos_Aires-03:00ARNo
Europe/London+00:00GB
Europe/Paris+01:00FR
Europe/Berlin+01:00DE
Europe/Madrid+01:00ES
Europe/Rome+01:00IT
Asia/Tokyo+09:00JPNo
Asia/Shanghai+08:00CNNo
Asia/Kolkata+05:30INNo
Asia/Dubai+04:00AENo
Australia/Sydney+10:00AU
Pacific/Auckland+12:00NZ
Africa/Lagos+01:00NGNo

Ejemplo completo

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" : "")})");
}

// Encontrar la diferencia horaria entre Lima y Tokyo
TimeSpan diff = tz.OffsetDiff("America/Lima", "Asia/Tokyo", utcTime);
Console.WriteLine($"\nLima ↔ Tokyo difference: {diff.TotalHours:F0} hours");
}
}