Imprima a hora atual… levando em consideração os segundos bissextos

9

(Nota: embora relacionado, esse desafio não é uma duplicata deste, porque requer determinar segundos bissextos automaticamente, em vez de codificar seus tempos, e não é uma duplicata deste, porque a maior parte da dificuldade vem da determinação do tempo sem distorção do segundo bissexto. , algo que as APIs na maioria das vezes não fazem por padrão. Sendo assim, é provável que uma solução pareça diferente de uma solução para qualquer um desses desafios.)

Estamos chegando ao final de 2016, mas vai demorar um pouco mais do que a maioria das pessoas espera. Então, aqui está um desafio celebrando nosso segundo extra este ano.

Transmita a hora atual no UTC, como horas, minutos, segundos. (Por exemplo, os formatos de saída legítimos para o meio-dia incluiriam 12:00:00e [12,0,0]; a formatação não é muito importante aqui.)

No entanto, há uma reviravolta: seu programa deve lidar com segundos bissextos de maneira apropriada, tanto no passado quanto no futuro. Isso significa que seu programa precisará obter uma lista de segundos bissextos de alguma fonte online ou atualizada / atualizável automaticamente. Você pode se conectar à Internet para obter isso, se desejar. No entanto, você pode conectar-se apenas a um URL que antecede esse desafio (ou seja, sem baixar partes do seu programa de outro lugar) e não pode usar a conexão para determinar a hora atual (especificamente: o seu programa deve funcionar mesmo se houver alguma tentativa de acessar a Internet retorna uma página com até 24 horas de atraso).

As APIs padrão da maioria dos sistemas operacionais para o horário atual irão distorcer o tempo em segundos, para ocultá-los de programas que, de outra forma, poderiam ser confundidos. Como tal, a principal dificuldade desse desafio é encontrar um método ou uma API para desfazer isso e calcular o verdadeiro horário atual não modificado no UTC.

Em teoria, seu programa deve ser perfeitamente preciso se for executado em um computador infinitamente rápido e não deve intencionalmente levar mais que zero tempo para ser executado. (Obviamente, na prática, seu programa será executado em um computador imperfeito e, portanto, provavelmente não será executado instantaneamente. Você não precisa se preocupar com isso invalidando os resultados, mas não deve depender dele para a correção do seu programa. )

Seu programa deve funcionar independentemente do fuso horário em que o relógio do sistema está definido. (No entanto, ele pode solicitar informações do sistema operacional ou do ambiente sobre o fuso horário em uso e pode assumir que a resposta é precisa.)

Como um , o programa mais curto vence. Boa sorte!

Comunidade
fonte

Respostas:

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

Experimente online! (não funciona aqui, parece que o TIO não reconhece irme iwr, talvez seja um recurso de segurança?)

Teste de lógica (data 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

Há um literal TABe um literal linebreak ( 0xA) na cadeia de caracteres regex, de modo que não precisei escapar deles (salvou 1 byte cada).

Explicação

Os tempos indicados (dos segundos bissextos) no arquivo ietf estão em segundos desde a época NTP, que é 1/1/1900 00:00:00. No Windows, um "tick" é simplesmente um milionésimo de segundo (10.000.000 ticks / s).

Se você adicionar um número inteiro a um, [datetime]ele conta o valor inteiro como ticks, então estou usando o valor de tick codificado da época NTP, subtraindo-o do valor do tick da hora UTC atual (cujo valor original está sendo atribuído simultaneamente para $d).

Para diminuir o valor do tick codificado, tirei alguns zeros (9 deles) e dividi por 98, depois multipliquei por 98e9(98 * 10 9 ).

O resultado dessa subtração é o valor em ticks desde a época NTP. Isso é dividido por 1e8(não 1e9, por razões que ficarão claras em um momento) para obter o valor em segundos (mais ou menos) desde a época do NTP. Será menor por um fator de 10, na verdade.

Recuperando o documento da IETF, em vez de dividi-lo em linhas primeiro, depois processá-las com os carimbos de data / hora, decidi dividir nas quebras de linha e nos TABcaracteres, pois é o que vem depois do carimbo de data / hora. Devido a uma única linha incorreta no arquivo, isso por si só incluiria um carimbo de data / hora adicional que não queremos. A linha é assim:

#@	3707596800

Então, mudei a regex para dividir [^@]\t(qualquer caractere que não seja @seguido de a TAB) que funciona para excluir essa linha, mas também acaba consumindo o último 0em cada um dos carimbos de data / hora.

É por isso que divido por 1e8e não 1e9, para dar conta dos desaparecidos 0.

O registro de data e hora atual é verificado para ver se existe dentro da lista de registros de data e hora de segundo neutralizados. Todo esse processo que descrevi está dentro do acessador da matriz [], portanto, o [bool]valor resultante se junta a um 0( $false) ou 1( $true). A matriz na qual estamos indexando contém dois elementos: uma string de formato para exibir a hora e uma codificada 23:59:60. A veracidade da comparação mencionada determina qual será escolhida e que será inserida no operador de formato -fcom a data atual atribuída anteriormente $dcomo parâmetro.

briantist
fonte
O que isso imprime no segundo após um salto de segundo? Eu posso seguir a lógica por segundos bissextos, mas não tenho certeza se consigo seguir a lógica por vezes em ambos os lados. (O Windows naturalmente apresentar tanto um segundo salto e o seguinte segunda como 00:00:00?)
@ ais523 exibirá o segundo após o segundo, independentemente da hora do sistema. O Windows não conhece os segundos bissextos, portanto o relógio será 1 segundo rápido até que seja corrigido por uma sincronização ou configuração manual. Dado os requisitos, não posso realmente ajustar isso, pois não é possível determinar se a hora do sistema está correta ou não sem o uso de uma fonte de hora externa, que é banida. O melhor que pude fazer é adicionar um código que force a sincronização NTP após a hora impressa, o que obviamente pode falhar (erro de rede, nenhuma fonte de tempo definida etc.), se isso for permitido.
Briantist