Consulta / función personalizada para convertir UTC a EST

Un usuario Pregunto ✅

RandomUser01

Estoy extrayendo una serie de columnas de fecha y hora de varias fuentes, que en su mayoría están en UTC. Estoy usando ToLocal para mostrarlos en EST, que es mi hora local, y es la forma en que mis usuarios finales necesitan ver los datos.

Sin embargo, esto no funciona en el informe después de publicarlo en el servicio PowerBI, que parece usar UTC como su hora local.

Si mi fuente de datos lee las 18:00 UTC, ToLocal no tiene ningún efecto en los datos; todavía se muestra como 18:00 en el servicio PowerBI.

Una solución simple sería restar X horas de mis horas UTC en PowerQuery. Los datos se «verían» como EST en PowerBI Desktop, y se «verían» como EST en el servicio PowerBI (aunque PowerBI piensa que es una hora UTC).

Sin embargo, esto no tiene en cuenta el horario de verano, lo cual no es trivial, porque el horario de verano comienza y termina en un día diferente cada año.

Así que me gustaría una función M (o algún otro enfoque creativo) que pueda …

  • Leer en una fecha y hora en UTC
  • Compruebe si esa fecha y hora cae en el horario de verano
    • Si es así, reste 5 horas
    • Si no, reste 4 horas
  • Se aplica fácilmente a varias columnas

¿Algunas ideas?

Para obtener la zona horaria local, use la siguiente función, que creé en una consulta en blanco.

= DateTimeZone.SwitchZone(DateTimeZone.LocalNow(),-7)

Cambie el -7 a su compensación normal sin horario de verano.

También llamé a esa consulta varToday

Ahora crea otra consulta como esta:

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("LczBDcAwCATBXvy2BIcT2anFov82ErL+7WkEe7dhCgvXbL1JdtPZf1GthVz0Ea/1IING1jfCAdHnpB6EkElnvg==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [dtDSTStart = _t, dtDSTEnd = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"dtDSTStart", type date}, {"dtDSTEnd", type date}}),
    #"Filtered Rows" = Table.SelectRows(#"Changed Type", each (DateTime.Date(varToday) >= [dtDSTStart] and DateTime.Date(varToday) <= [dtDSTEnd])),
    #"Counted Rows" = Table.RowCount(#"Filtered Rows")
in
    #"Counted Rows"

Eso devolverá un 1 o 0. 1 si estamos en DST, 0 si no. Llamé a esta consulta varDST Tenga en cuenta que hace referencia a varToday arriba.

Ahora todas las demás funciones deberían usar la misma lógica que DateTimeZone.SwitchZone ([UTC], -7) pero agrega varDST, que agregará 1 o 0.

1) En Power Query, seleccione New Source, luego Blank Query
2) En la cinta de Inicio, seleccione el botón «Editor avanzado»
3) Elimina todo lo que ves, luego pega el código M que te he dado en ese cuadro.
4) Presione Listo

EDITAR: Esta propiedad no funcionará en las primeras horas de la mañana en las fechas de cambio de horario de verano. Se asume que todo el día es o no horario de verano. Necesitaría expandir mucho la tabla para manejar el cambio de 2 am-3am.

Me alegro de haber ayudado @ Shart2019

Para obtener la zona horaria local, use la siguiente función, que creé en una consulta en blanco.

= DateTimeZone.SwitchZone(DateTimeZone.LocalNow(),-7)

Cambie el -7 a su compensación normal sin horario de verano.

También llamé a esa consulta varToday

Ahora crea otra consulta como esta:

let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("LczBDcAwCATBXvy2BIcT2anFov82ErL+7WkEe7dhCgvXbL1JdtPZf1GthVz0Ea/1IING1jfCAdHnpB6EkElnvg==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [dtDSTStart = _t, dtDSTEnd = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"dtDSTStart", type date}, {"dtDSTEnd", type date}}),
    #"Filtered Rows" = Table.SelectRows(#"Changed Type", each (DateTime.Date(varToday) >= [dtDSTStart] and DateTime.Date(varToday) <= [dtDSTEnd])),
    #"Counted Rows" = Table.RowCount(#"Filtered Rows")
in
    #"Counted Rows"

Eso devolverá un 1 o 0. 1 si estamos en DST, 0 si no. Llamé a esta consulta varDST Tenga en cuenta que hace referencia a varToday arriba.

Ahora todas las demás funciones deberían usar la misma lógica que DateTimeZone.SwitchZone ([UTC], -7) pero agrega varDST, que agregará 1 o 0.

1) En Power Query, seleccione New Source, luego Blank Query
2) En la cinta de Inicio, seleccione el botón «Editor avanzado»
3) Elimina todo lo que ves, luego pega el código M que te he dado en ese cuadro.
4) Presione Listo

EDITAR: Esta propiedad no funcionará en las primeras horas de la mañana en las fechas de cambio de horario de verano. Se asume que todo el día es o no horario de verano. Necesitaría expandir mucho la tabla para manejar el cambio de 2 am-3am.

RandomUser01

En respuesta a Edhans

@edhans Esto es útil, pero no estoy seguro de que sea 100% lo que necesito.

Esta consulta se basa en fecha actual para determinar si estamos en horario de verano o no, ¿no? La solución debe verificar la fecha que se está convirtiendo.

Imagine que tengo tres años de datos todos en UTC y necesito convertirlos todos a EST. ¿Pensamientos?

La solución tendrá que ser alguna función personalizada que tome la fecha como entrada, en lugar de depender de varToday. ¡Simplemente no estoy lo suficientemente versado en M para escribirlo!

En respuesta a RandomUser01

Simplemente cambie la función para extraer su campo, frente a la hora actual.

= DateTimeZone.SwitchZone(DateTimeZone.LocalNow(),-7)

becomes

= DateTimeZone.SwitchZone([YourUTCDateTimeZoneField],-7)

En otras palabras, no usaría varToday. Simplemente agregue una columna personalizada que pueda tener esta fórmula completa

= DateTimeZone.SwitchZone([YourUTCDateTimeZoneField],-7 + varDST)

¿Tener sentido? De lo contrario, envíe algunos datos a través de los enlaces a continuación y una captura de pantalla de Excel del resultado esperado.

Cómo obtener una buena ayuda rápidamente. Ayúdanos a ayudarte.
Cómo obtener una respuesta rápida a su pregunta
Cómo proporcionar datos de muestra en el foro de Power BI

RandomUser01

En respuesta a Edhans


@edhans escribió:

Simplemente cambie la función para extraer su campo, frente a la hora actual.

= DateTimeZone.SwitchZone(DateTimeZone.LocalNow(),-7)

becomes

= DateTimeZone.SwitchZone([YourUTCDateTimeZoneField],-7)

Hmm, creo que hay algo de desconexión aquí. No puedo (y no debo) hacer referencia a una columna de diferente en esta consulta.

Tengo muchos campos / columnas que deben convertirse, no solo uno.

Por lo tanto, la solución debe tomar una fecha y hora como entrada, determinar si la fecha específica está dentro del horario de verano y luego ajustar esa fecha y hora de manera apropiada. De esa forma puedo aplicar la solución a cualquier número de columnas.

En cualquier caso, sus publicaciones fueron útiles, finalmente las usé para escribir una función personalizada a continuación. Muy fácil de adaptar a cualquier zona horaria. Incluso podría tomar la zona horaria como parámetro, pero solo necesito EST. Se implementa simplemente agregando una columna personalizada en PowerQuery con function = UTCtoEST ([DateColumn])

let
    UTCtoEST = (UTC_DateTime) =>
    let 
        Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("Rc5BCsAgDETRu7gWdCZttWeR3P8amk6gux8eCVmrWAMbO0apBWi32usniGlKLnVKj+mVmFoyz8AugDpX4gAhGeqUOEBKHnVKvEb7XzvtvgE=", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [dtDSTStart = _t, dtDSTEnd = _t]),
        #"Changed Type" = Table.TransformColumnTypes(Source,{{"dtDSTStart", type date}, {"dtDSTEnd", type date}}),
        #"Filtered Rows" = Table.SelectRows(#"Changed Type", each (DateTime.Date(UTC_DateTime) >= [dtDSTStart] and DateTime.Date(UTC_DateTime) <= [dtDSTEnd])),
        result = DateTimeZone.RemoveZone(DateTimeZone.SwitchZone(DateTime.AddZone(UTC_DateTime,0),-5 + Table.RowCount(#"Filtered Rows")))
    in
        result
in
    UTCtoEST

Jruiz218

En respuesta a RandomUser01

@ RandomUser01 ¡muchas gracias! esto hizo exactamente lo que estaba buscando. Solo tengo una pregunta, ¿se ajustará automáticamente a DTS?

En respuesta a Jruiz218

No @ Jruiz218 – Tienes que hacer los cambios de horario de verano tú mismo. Tengo un artículo aquí que le muestra cómo agregar una marca de tiempo de actualización a su informe y explica cómo puede ajustar el horario de verano con una tabla que tiene las fechas de inicio / finalización del horario de verano durante algunos años. Utilice las fechas correctas para su región. Estas fechas son para EE. UU.

RandomUser01

En respuesta a Edhans

@ Jruiz218 sí, esta función se ajusta al horario de verano. No estoy seguro de por qué @edhans dice que no.

Por otro lado, encontré que el rendimiento de esta función es muy deficiente; si está convirtiendo muchas fechas, le sugiero que cree una tabla DST en PowerQuery, luego haga referencia a esa tabla en la función –

let
    UTCtoEST = (UTC_DateTime) =>
    let 
        Source = Table.Buffer(Table_DST),
        #"Filtered Rows" = Table.SelectRows(Source, each (DateTime.Date(UTC_DateTime) >= [dtDSTStart] and DateTime.Date(UTC_DateTime) <= [dtDSTEnd])),
        result = DateTimeZone.RemoveZone(DateTimeZone.SwitchZone(DateTime.AddZone(UTC_DateTime,0),-5 + Table.RowCount(#"Filtered Rows")))
    in
        result
in
    UTCtoEST

En respuesta a RandomUser01

Lo siento @ RandomUser01 – estás haciendo algunos ajuste a DST, pero no hay un calendario de DST. Consulte este artículo para 2021. Muchos países no tienen horario de verano y muchos otros tienen calendarios diferentes, y otros tienen varios calendarios de horario de verano (o no tienen) en diferentes áreas. Arizona, en los EE. UU., Por ejemplo, no tiene horario de verano.

Es por eso que le dije a @ Jruiz218 que necesitarían mirar el artículo que proporcioné y ajustar el horario de verano de acuerdo con la (s) zona (s) horaria (s) según corresponda.

Pero sí, si tú y @ Jruiz218 están en el mismo calendario DST, entonces funciona.

Shart2019

En respuesta a RandomUser01

¡Gracias por tu publicación! Encontré esto muy útil para resolver un problema similar.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *