Imprima la hora actual ... teniendo en cuenta los segundos bisiestos

9

(Nota: aunque relacionado, este desafío no es un duplicado de este porque requiere determinar los segundos bisiestos automáticamente en lugar de codificar sus tiempos, y no es un duplicado de este porque la mayor parte de la dificultad proviene de determinar el tiempo sin sesgar el segundo salto , algo que la mayoría de las veces las API no hacen de manera predeterminada. Como tal, es probable que una solución se vea diferente de una solución a cualquiera de esos desafíos)

Estamos llegando a finales de 2016, pero llevará un poco más de lo que la mayoría de la gente espera. Así que aquí hay un desafío para celebrar nuestro segundo extra este año.

Salida de la hora actual en UTC, como horas, minutos, segundos. (Por ejemplo, los formatos de salida legítimos para el mediodía incluirían 12:00:00y [12,0,0]; el formato no es muy importante aquí).

Sin embargo, hay un giro: su programa debe manejar los segundos intercalares adecuadamente, tanto en el pasado como en el futuro. Esto significa que su programa tendrá que obtener una lista de segundos intercalares de alguna fuente en línea o actualizada / actualizable automáticamente. Puede conectarse a Internet para obtener esto si lo desea. Sin embargo, solo puede conectarse a una URL que sea anterior a este desafío (es decir, no descargar partes de su programa desde otro lugar), y no puede usar la conexión para determinar la hora actual (específicamente: su programa debe funcionar incluso si intenta acceder Internet devuelve una página que está inactiva hasta 24 horas).

La mayoría de las API predeterminadas de los sistemas operativos para la hora actual sesgarán el tiempo en segundos bisiestos para ocultarlas de los programas que de otro modo podrían confundirse. Como tal, la principal dificultad de este desafío es encontrar un método o una API para deshacer eso, y calcular la hora actual no modificada en UTC.

En teoría, su programa debe ser perfectamente preciso si se ejecuta en una computadora infinitamente rápida, y no debe tomar más de cero intencionalmente en ejecutarse. (Por supuesto, en la práctica, su programa se ejecutará en una computadora imperfecta, por lo que probablemente no se ejecutará instantáneamente. No tiene que preocuparse de que esto invalide los resultados, pero no debe depender de él para la corrección de su programa. )

Su programa debe funcionar independientemente de la zona horaria en la que esté configurado el reloj del sistema. (Sin embargo, puede solicitar información del sistema operativo o del entorno sobre qué zona horaria se está utilizando y puede suponer que la respuesta es precisa).

Como , gana el programa más corto. ¡Buena suerte!

Comunidad
fuente

Respuestas:

2

PowerShell , 161 bytes

(('{0:H:m:s}','23:59:60')[(($d=[datetime]::UtcNow).Ticks-6114960*98e9)/1e8-in((irm ietf.org/timezones/data/leap-seconds.list)-split'[^@]	|
'-match'^\d{9}')])-f$d

Pruébalo en línea! (no funciona aquí, parece que TIO no reconoce irmy iwr, ¿tal vez es una característica de seguridad?)

Prueba lógica (fecha codificada):

(('{0:H:m:s}','23:59:60')[(($d=[datetime]'1/1/2017 00:00:00').Ticks-6114960*98e9)/1e8-in((irm ietf.org/timezones/data/leap-seconds.list)-split'[^@]	|
'-match'^\d{9}')])-f$d

Notas

Hay un salto de línea literal TABy uno literal ( 0xA) en la cadena de expresiones regulares, por lo que no tuve que escapar de ellos (guardado 1 byte cada uno).

Explicación

Los tiempos dados (de los segundos bisiestos) en el archivo ietf están en segundos desde la época NTP que es 1/1/1900 00:00:00. En Windows, un "tic" es simplemente una décima millonésima de segundo (10,000,000 ticks / seg).

Si agrega un número entero a un [datetime], cuenta el valor entero como ticks, por lo que estoy usando el valor de tick codificado de NTP epoch, luego lo resta del valor de tick del tiempo UTC actual (cuyo valor original se asigna simultáneamente a $d)

Para hacer que el valor de la marca codificada sea más pequeño, eliminé algunos ceros (9 de ellos) y los dividí entre 98, luego los multipliqué por 98e9(98 * 10 9 ).

El resultado de esa resta es el valor en ticks desde la época NTP. Eso se divide por 1e8(no 1e9, por razones que serán claras en un momento) para obtener el valor en segundos (más o menos) desde la época de NTP. Será más pequeño por un factor de 10, en realidad.

Al recuperar el documento del IETF, en lugar de dividirlo en líneas primero, luego procesar las líneas con las marcas de tiempo, decidí dividir en saltos de línea y en TABcaracteres, ya que eso es lo que viene después de la marca de tiempo. Debido a una sola línea errante en el archivo, eso solo incluiría una marca de tiempo adicional que no queremos. La línea se ve así:

#@	3707596800

Así que cambié la expresión regular para dividir [^@]\t(cualquier carácter que no sea @seguido por a TAB) que funciona para excluir esa línea, pero también termina consumiendo el último 0en cada una de las marcas de tiempo.

Es por eso que divido por 1e8y no 1e9, para dar cuenta de los desaparecidos 0.

La marca de tiempo actual se verifica para ver si existe dentro de la lista de marcas de segundo de salto neutralizadas. Todo este proceso que describí está dentro del descriptor de acceso a la matriz [], por lo que el [bool]valor resultante se fusiona a a 0( $false) o 1( $true). La matriz en la que estamos indexando contiene dos elementos: una cadena de formato para mostrar la hora y una codificada 23:59:60. La veracidad de la comparación mencionada anteriormente determina cuál se elegirá, y eso se alimenta al operador de formato -fcon la fecha actual previamente asignada $dcomo parámetro.

briantista
fuente
¿Qué imprime esto el segundo después de un segundo intercalar? Puedo seguir la lógica durante los segundos bisiestos, pero no estoy seguro de poder seguir la lógica en cualquier momento. (¿Windows muestra naturalmente un segundo
@ ais523 mostrará el segundo después del segundo intercalar como sea la hora del sistema. Windows no conoce los segundos bisiestos, por lo que el reloj será 1 segundo más rápido hasta que sea corregido por una sincronización o una configuración manual. Teniendo en cuenta los requisitos, realmente no puedo ajustar eso, ya que no es posible determinar si la hora del sistema es correcta o no sin usar una fuente de tiempo externa, que está prohibida. Lo mejor que puedo hacer es agregar un código a esto que fuerce la sincronización NTP después de que haya impreso la hora, lo que por supuesto podría fallar (error de red, no se configuró la fuente de tiempo, etc.), si eso está permitido.
briantist