none
¿Como se puede hacer una correccion en la fecha hora para pasarlo a hora UTC? RRS feed

  • Pregunta

  • Necesito hacer una corrección en una fecha/hora que me viene como String desde una BDD porque la hora esta en hora local y la necesito pasar a UTC sumándole 3 horas.

    Estuve leyendo pero solo encontré como restar fechas pero sin horas y vi que existe TimeSpan, que no lo he usado nunca y también vi que existe el método AddHours en el tipo Date el cual me parece mas apropiado a lo que necesito pero no se como usarlo, es decir ¿Como convierto la cadena a tipo Date?.


    The Real Blue
    jueves, 7 de abril de 2011 20:19

Respuestas

  • jueves, 7 de abril de 2011 21:00
  • "Electric_Blue" preguntó:

    > Necesito hacer una corrección en una fecha/hora que me viene como
    > String desde una BDD porque la hora esta en hora local y la
    > necesito pasar a UTC sumándole 3 horas.

    No necesitas sumar ni restar para pasar una hora local (un valor DateTime local) a UTC. El usuario Ángel Jiménez ya te ha indicado varios enlaces que muestran cómo hacerlo.

    > ¿Como convierto la cadena a tipo Date?

    Yo me voy a limitar a responderte a esa pregunta.

    Dices que el valor de fecha y hora "te viene como String desde una BDD". Si la fecha y hora estuviera guardada en la base como un valor Datetime, la solución sería más fácil, pero si está guardada como String, todo dependerá del formato de fecha y hora que tenga ese String.

    Vamos a suponer que todos los valores tienen el mismo formato de fecha y hora existente en la Configuración regional de tu sistema operativo:

       ' Una fecha correspondiente al día 8 de abril de 2011
       '
       Dim cadenaFechaHora As String = "08/04/2011 10:44:24"

       Dim dt As DateTime
       Dim bln As Boolean = DateTime.TryParse(cadenaFechaHora, dt)

       If (bln) Then
          ' Se ha convertido el valor alfanumérico a un valor
          ' DateTime válido. Convertimos la fecha y hora actual
          ' en Hora Universal Coordinada (UTC).
          '
          dt = TimeZoneInfo.ConvertTimeToUtc(dt)

          MessageBox.Show(dt.ToString())

       Else
          MessageBox.Show("El valor String no se ha podido convertir a DateTime.")

       End If

    Se comprende que la variable «cadenaFechaHora» deberá tener el valor String devuelto por la base de datos. Asimismo, la supuesta fecha devuelta se entenderá como "hora local", tal y como así comentas en tu mensaje.

    Pero si te falla el método TryParse porque no se reconoce el formato de fecha y hora, lo mismo vas a tener que utilizar el método compartido TryParseExact de la estructura DateTime, pasándole el formato adecuado que tenga el String devuelto, y averiguar el formato que tiene un valor String, va a ser complicado. Si necesitas información y ejemplos sobre el método TryParseExact, consulta la ayuda de Visual Studio.

    Lo correcto es almacenar como Datetime los valores de fecha y hora, salvo que todos los valores se ingresen en la base de datos con el mismo formato, en cuyo caso se puede almacenar el valor como String. Pero en éste último caso hay que ser muy estrictos para que todos los valores String tengan el mismo formato, un formato que posteriormente pueda ser convertido a DateTime sin problemas.

     


    Enrique Martínez
      [MS MVP - VB]

    viernes, 8 de abril de 2011 3:55
    Moderador
  • "Electric_Blue" escribió:

    > El método TimeZoneInfo.ConvertTimeToUtc lo use y funciona, pero según leí de
    > los links asume que es hora local y no se que pasaría si como suelen hacer
    > en mi país corren la hora por ajuste de verano, es decir seguiría siendo
    > hora local, pero no seria -3UTC como seria la hora correcta.

    Y en mi país también cambian la hora en primavera, como así se hace también en un montón de países más. Pero el método ConvertTimeToUtc te devolverá la hora UTC que se corresponda con el valor de la fecha especificada, o mejor dicho, con el valor de la estructura DateTime obtenida del valor String existente en la base de datos.

    Por ejemplo, en España entró en vigor el horario de verano el pasado día 27 de marzo a las 2:00:00 AM. Si yo extraigo de la base de datos la fecha y hora "08/04/2011 10:44:24", como en esa fecha ya ha entrado en vigor el horario de verano, el método ConvertTimeToUtc me devolverá la misma fecha pero con dos horas menos, que es la diferencia horaria en España respecto de la hora universal UTC, es decir, me devolverá "08/04/2011 08:44:24".

    Pero si yo extraigo de la base de datos una fecha que es anterior a la entrada en vigor del horario de verano ("08/03/2011 10:44:24"), el método ConvertTimeToUtc me devolverá una hora menos ("08/03/2011 09:44:24"), que es el desfase existente en invierno respecto de la hora universal UTC. ¿Comprendes?

    Por tanto, en principio entiendo que no te tienes que preocupar si estamos en el horario de verano o no. Por supuesto, vuelvo a repetir que se comprende que la hora que se extrae de la base de datos, ES HORA LOCAL, porque de no ser así, vas a liar un jaleo de mil demonios, ya que el método ConvertTimeToUtc entiende que el objeto DateTime pasado contiene una hora local.

    De todas maneras, si deseas tener un mayor control sobre la zona horaria, al método ConvertTimeToUtc le puedes pasar un objeto TimeZoneInfo que contiene la información de la zona horaria correspondiente al valor DateTime. Para ello, bien te puede servir la siguiente función:

      ''' <summary>
      ''' Convierte la hora local de una zona horaria determinada en hora universal coordinada (UTC).
      ''' </summary>
      ''' <author>Enrique Martínez Montejo - 2011</author>
      ''' <param name="fechaLocal">Cadena alfanumérica con la fecha y hora que se desea
      ''' convertir a hora universal coordinada (UTC).</param>
      ''' <returns></returns>
      ''' <remarks></remarks>
      Public Function ConvertLocalToUtc(ByVal fechaLocal As String) As DateTime
    
        If (fechaLocal = String.Empty) Then _
          Throw New ArgumentNullException()
    
        Dim dt As DateTime
        Dim bln As Boolean = DateTime.TryParse(fechaLocal, dt)
    
        If (Not (bln)) Then _
          Throw New ArgumentException("No se corresponde con un valor de fecha y hora válido.")
    
        ' Se ha convertido el valor alfanumérico a un valor DateTime válido.
    
        Try
          ' Zona horaria actual del equipo donde actualmente
          ' se está ejecutándose el código.
          '
          Dim tz As TimeZone = TimeZone.CurrentTimeZone
    
          ' Obtenemos el periodo de duración del horario de verano
          ' correspondiente al año especificado.
          '
          Dim dlc As DaylightTime = tz.GetDaylightChanges(dt.Year)
    
          ' Si la hora especificada se corresponde EXACTAMENTE con la hora
          ' de la fecha de inicio del horario de verano, a la hora le 
          ' sumamos la diferencia horaria.
          '
          If (dlc.Start = dt) Then _
            dt = dt.Add(dlc.Delta)
    
          ' Obtenemos la información de la zona horaria correspondiente
          ' al equipo donde actualmente se está ejecutando el código, de
          ' acuerdo a su identificador de zona horaria existente en la
          ' configuración regional de Windows.
          '
          Dim tzi As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.Id)
    
          ' Convertimos la fecha y hora de una zona horaria
          ' determinada en Hora Universal Coordinada (UTC).
          '
          dt = TimeZoneInfo.ConvertTimeToUtc(dt, tzi)
    
          Return dt
    
        Catch ex As Exception
          Throw
    
        End Try
    
      End Function
    
    Y a la función la llamarías de la siguiente manera:

            Try
                ' Una fecha correspondiente al día 8 de abril de 2011
                '
                Dim cadenaFechaHora As String = "08/04/2011 10:44:24"

                Dim dt As DateTime = ConvertLocalToUtc(cadenaFechaHora)

                MessageBox.Show(dt.ToString())

            Catch ex As Exception
                MessageBox.Show(ex.Message)

            End Try

    Como en la fecha indicada ha entrado en vigor el horario de verano, para una zona horaria -3UTC la función te devolverá la hora 07:44:24. Para comprobar que también funciona en horario de invierno, en lugar de especificar el més de Abril, especifica el més de Marzo, y obtendrás el valor 08:44:24, es decir, -2UTC.

     

    sábado, 9 de abril de 2011 10:33
    Moderador

Todas las respuestas

  • jueves, 7 de abril de 2011 21:00
  • "Electric_Blue" preguntó:

    > Necesito hacer una corrección en una fecha/hora que me viene como
    > String desde una BDD porque la hora esta en hora local y la
    > necesito pasar a UTC sumándole 3 horas.

    No necesitas sumar ni restar para pasar una hora local (un valor DateTime local) a UTC. El usuario Ángel Jiménez ya te ha indicado varios enlaces que muestran cómo hacerlo.

    > ¿Como convierto la cadena a tipo Date?

    Yo me voy a limitar a responderte a esa pregunta.

    Dices que el valor de fecha y hora "te viene como String desde una BDD". Si la fecha y hora estuviera guardada en la base como un valor Datetime, la solución sería más fácil, pero si está guardada como String, todo dependerá del formato de fecha y hora que tenga ese String.

    Vamos a suponer que todos los valores tienen el mismo formato de fecha y hora existente en la Configuración regional de tu sistema operativo:

       ' Una fecha correspondiente al día 8 de abril de 2011
       '
       Dim cadenaFechaHora As String = "08/04/2011 10:44:24"

       Dim dt As DateTime
       Dim bln As Boolean = DateTime.TryParse(cadenaFechaHora, dt)

       If (bln) Then
          ' Se ha convertido el valor alfanumérico a un valor
          ' DateTime válido. Convertimos la fecha y hora actual
          ' en Hora Universal Coordinada (UTC).
          '
          dt = TimeZoneInfo.ConvertTimeToUtc(dt)

          MessageBox.Show(dt.ToString())

       Else
          MessageBox.Show("El valor String no se ha podido convertir a DateTime.")

       End If

    Se comprende que la variable «cadenaFechaHora» deberá tener el valor String devuelto por la base de datos. Asimismo, la supuesta fecha devuelta se entenderá como "hora local", tal y como así comentas en tu mensaje.

    Pero si te falla el método TryParse porque no se reconoce el formato de fecha y hora, lo mismo vas a tener que utilizar el método compartido TryParseExact de la estructura DateTime, pasándole el formato adecuado que tenga el String devuelto, y averiguar el formato que tiene un valor String, va a ser complicado. Si necesitas información y ejemplos sobre el método TryParseExact, consulta la ayuda de Visual Studio.

    Lo correcto es almacenar como Datetime los valores de fecha y hora, salvo que todos los valores se ingresen en la base de datos con el mismo formato, en cuyo caso se puede almacenar el valor como String. Pero en éste último caso hay que ser muy estrictos para que todos los valores String tengan el mismo formato, un formato que posteriormente pueda ser convertido a DateTime sin problemas.

     


    Enrique Martínez
      [MS MVP - VB]

    viernes, 8 de abril de 2011 3:55
    Moderador
  • El método TimeZoneInfo.ConvertTimeToUtc lo use y funciona, pero según leí de los links asume que es hora local y no se que pasaría si como suelen hacer en mi país corren la hora por ajuste de verano, es decir seguiría siendo hora local, pero no seria -3UTC como seria la hora correcta.

    Dado que es una vista lo que obtengo de la base tal vez sea mejor si modifico la vista para que entregue el valor correcto y ajustarlo según el desfase horario que designen(horario de verano). ¿Que opinan, lo hago en la aplicación o en la vista?


    The Real Blue
    viernes, 8 de abril de 2011 13:07
  • "Electric_Blue" escribió:

    > El método TimeZoneInfo.ConvertTimeToUtc lo use y funciona, pero según leí de
    > los links asume que es hora local y no se que pasaría si como suelen hacer
    > en mi país corren la hora por ajuste de verano, es decir seguiría siendo
    > hora local, pero no seria -3UTC como seria la hora correcta.

    Y en mi país también cambian la hora en primavera, como así se hace también en un montón de países más. Pero el método ConvertTimeToUtc te devolverá la hora UTC que se corresponda con el valor de la fecha especificada, o mejor dicho, con el valor de la estructura DateTime obtenida del valor String existente en la base de datos.

    Por ejemplo, en España entró en vigor el horario de verano el pasado día 27 de marzo a las 2:00:00 AM. Si yo extraigo de la base de datos la fecha y hora "08/04/2011 10:44:24", como en esa fecha ya ha entrado en vigor el horario de verano, el método ConvertTimeToUtc me devolverá la misma fecha pero con dos horas menos, que es la diferencia horaria en España respecto de la hora universal UTC, es decir, me devolverá "08/04/2011 08:44:24".

    Pero si yo extraigo de la base de datos una fecha que es anterior a la entrada en vigor del horario de verano ("08/03/2011 10:44:24"), el método ConvertTimeToUtc me devolverá una hora menos ("08/03/2011 09:44:24"), que es el desfase existente en invierno respecto de la hora universal UTC. ¿Comprendes?

    Por tanto, en principio entiendo que no te tienes que preocupar si estamos en el horario de verano o no. Por supuesto, vuelvo a repetir que se comprende que la hora que se extrae de la base de datos, ES HORA LOCAL, porque de no ser así, vas a liar un jaleo de mil demonios, ya que el método ConvertTimeToUtc entiende que el objeto DateTime pasado contiene una hora local.

    De todas maneras, si deseas tener un mayor control sobre la zona horaria, al método ConvertTimeToUtc le puedes pasar un objeto TimeZoneInfo que contiene la información de la zona horaria correspondiente al valor DateTime. Para ello, bien te puede servir la siguiente función:

      ''' <summary>
      ''' Convierte la hora local de una zona horaria determinada en hora universal coordinada (UTC).
      ''' </summary>
      ''' <author>Enrique Martínez Montejo - 2011</author>
      ''' <param name="fechaLocal">Cadena alfanumérica con la fecha y hora que se desea
      ''' convertir a hora universal coordinada (UTC).</param>
      ''' <returns></returns>
      ''' <remarks></remarks>
      Public Function ConvertLocalToUtc(ByVal fechaLocal As String) As DateTime
    
        If (fechaLocal = String.Empty) Then _
          Throw New ArgumentNullException()
    
        Dim dt As DateTime
        Dim bln As Boolean = DateTime.TryParse(fechaLocal, dt)
    
        If (Not (bln)) Then _
          Throw New ArgumentException("No se corresponde con un valor de fecha y hora válido.")
    
        ' Se ha convertido el valor alfanumérico a un valor DateTime válido.
    
        Try
          ' Zona horaria actual del equipo donde actualmente
          ' se está ejecutándose el código.
          '
          Dim tz As TimeZone = TimeZone.CurrentTimeZone
    
          ' Obtenemos el periodo de duración del horario de verano
          ' correspondiente al año especificado.
          '
          Dim dlc As DaylightTime = tz.GetDaylightChanges(dt.Year)
    
          ' Si la hora especificada se corresponde EXACTAMENTE con la hora
          ' de la fecha de inicio del horario de verano, a la hora le 
          ' sumamos la diferencia horaria.
          '
          If (dlc.Start = dt) Then _
            dt = dt.Add(dlc.Delta)
    
          ' Obtenemos la información de la zona horaria correspondiente
          ' al equipo donde actualmente se está ejecutando el código, de
          ' acuerdo a su identificador de zona horaria existente en la
          ' configuración regional de Windows.
          '
          Dim tzi As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(TimeZoneInfo.Local.Id)
    
          ' Convertimos la fecha y hora de una zona horaria
          ' determinada en Hora Universal Coordinada (UTC).
          '
          dt = TimeZoneInfo.ConvertTimeToUtc(dt, tzi)
    
          Return dt
    
        Catch ex As Exception
          Throw
    
        End Try
    
      End Function
    
    Y a la función la llamarías de la siguiente manera:

            Try
                ' Una fecha correspondiente al día 8 de abril de 2011
                '
                Dim cadenaFechaHora As String = "08/04/2011 10:44:24"

                Dim dt As DateTime = ConvertLocalToUtc(cadenaFechaHora)

                MessageBox.Show(dt.ToString())

            Catch ex As Exception
                MessageBox.Show(ex.Message)

            End Try

    Como en la fecha indicada ha entrado en vigor el horario de verano, para una zona horaria -3UTC la función te devolverá la hora 07:44:24. Para comprobar que también funciona en horario de invierno, en lugar de especificar el més de Abril, especifica el més de Marzo, y obtendrás el valor 08:44:24, es decir, -2UTC.

     

    sábado, 9 de abril de 2011 10:33
    Moderador