Crear una fecha y hora en una zona horaria específica en c#


Estoy tratando de crear una prueba unitaria para probar el caso para cuando la zona horaria cambia en una máquina porque se ha establecido incorrectamente y luego corregido.

En la prueba necesito poder crear objetos DateTime en una zona horaria local none para asegurarme de que las personas que ejecutan la prueba puedan hacerlo con éxito independientemente de dónde se encuentren.

Por lo que puedo ver desde el constructor DateTime, puedo establecer la zona horaria para que sea la zona horaria local, la zona horaria UTC o no indicado.

¿Cómo puedo crear una fecha y hora con una zona horaria específica como PST?

Author: Liam, 2008-10-29

6 answers

La respuesta de Jon habla de Zona horaria, pero yo sugeriría usar TimeZoneInfo en su lugar.

Personalmente me gusta mantener las cosas en UTC cuando sea posible, así que sugeriría una estructura como esta:

public struct DateTimeWithZone
{
    private readonly DateTime utcDateTime;
    private readonly TimeZoneInfo timeZone;

    public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
    {
        var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
        utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone); 
        this.timeZone = timeZone;
    }

    public DateTime UniversalTime { get { return utcDateTime; } }

    public TimeZoneInfo TimeZone { get { return timeZone; } }

    public DateTime LocalTime
    { 
        get 
        { 
            return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); 
        }
    }        
}

Es posible que desee cambiar los nombres de "Zona horaria" a "TimeZoneInfo" para hacer las cosas más claras - Yo prefiero los nombres más breves.

 170
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:34:36

La estructura DateTimeOffset fue creada exactamente para este tipo de uso.

Véase: http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx

Este es un ejemplo de creación de un objeto DateTimeOffset con una zona horaria específica:

DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));

 41
Author: Clever Human,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-15 02:32:07

Las otras respuestas aquí son útiles pero no cubren cómo acceder a Pacific específicamente-aquí tienes:

public static DateTime GmtToPacific(DateTime dateTime)
{
    return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
        TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}

Curiosamente, aunque "Hora Estándar del Pacífico" normalmente significa algo diferente de "Hora Diaria del Pacífico", en este caso se refiere a la hora del Pacífico en general. De hecho, si usa FindSystemTimeZoneById para obtenerlo, una de las propiedades disponibles es un bool que le indica si esa zona horaria está actualmente en horario de verano o no.

Puede ver ejemplos más generalizados de esto en una biblioteca que terminé juntando para lidiar con las fechas que necesito en diferentes zonas horarias según desde dónde está preguntando el usuario, etc.:

Https://github.com/b9chris/TimeZoneInfoLib.Net

Esto no funcionará fuera de Windows (por ejemplo Mono en Linux) ya que la lista de tiempos proviene del Registro de Windows: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

Debajo de eso encontrarás claves (iconos de carpetas en el Editor del Registro); los nombres de esas claves son lo que pasas a FindSystemTimeZoneById. En Linux tengo que usar un conjunto separado de definiciones de zona horaria estándar de Linux, que no he explorado adecuadamente.

 29
Author: Chris Moschini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-13 21:23:36

Alteré la respuesta de Jon Skeet un poco para la web con el método de extensión. También funciona en azure como un encanto.

public static class DateTimeWithZone
{

private static readonly TimeZoneInfo timeZone;

static DateTimeWithZone()
{
//I added web.config <add key="CurrentTimeZoneId" value="Central Europe Standard Time" />
//You can add value directly into function.
    timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["CurrentTimeZoneId"]);
}


public static DateTime LocalTime(this DateTime t)
{
     return TimeZoneInfo.ConvertTime(t, timeZone);   
}
}
 6
Author: Jernej Novak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:10

Tendrás que crear un objeto personalizado para eso. Su objeto personalizado contendrá dos valores:

No estoy seguro de si ya hay un tipo de datos proporcionado por CLR que lo tenga, pero al menos el componente Zona horaria ya está disponible.

 2
Author: Jon Limjap,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-29 11:51:21

Me gusta la respuesta de Jon Skeet, pero me gustaría añadir una cosa. No estoy seguro de si Jon esperaba que el Ctor se pasara siempre en la zona horaria local. Pero quiero usarlo para casos en los que es algo distinto a lo local.

Estoy leyendo valores de una base de datos, y sé en qué zona horaria está esa base de datos. Así que en el ctor, voy a pasar en la zona horaria de la base de datos. Pero entonces me gustaría el valor en hora local. Jon's LocalTime no devuelve la fecha original convertida en un fecha de la zona horaria local. Devuelve la fecha convertida en la zona horaria original (lo que haya pasado en el ctor).

Creo que estos nombres de propiedades lo aclaran...

public DateTime TimeInOriginalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } }
public DateTime TimeInLocalZone    { get { return TimeZoneInfo.ConvertTime(utcDateTime, TimeZoneInfo.Local); } }
public DateTime TimeInSpecificZone(TimeZoneInfo tz)
{
    return TimeZoneInfo.ConvertTime(utcDateTime, tz);
}
 2
Author: Gabe Halsmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-10 20:13:18