A RFC 2550 é uma proposta satírica (publicada em 1 de abril de 1999) para uma representação ASCII com economia de espaço de data e hora que pode suportar qualquer data (mesmo aquelas anteriores ao início do universo e aquelas que ultrapassam o fim previsto do universo). O algoritmo para calcular um registro de data e hora compatível com RFC 2550 é o seguinte (nota: todos os intervalos incluem o início, mas excluem o final - 0 a 10.000 significa tudo em n
que 0 <= n < 10000
):
- Formato do ano
- Anos 0 a 10.000: um número decimal de 4 dígitos, preenchido à esquerda com zeros.
- Anos 10.000 a 100.000: um número decimal de 5 dígitos, prefixado com o caractere A.
- Anos 100.000 a 10 30 : o número decimal do ano, prefixado com a letra ASCII maiúscula cujo índice no alfabeto inglês é igual ao número de dígitos no ano decimal, menos 5 (B para anos de 6 dígitos, C para 7 -dígitos, etc.).
- Anos 10 30 a 10 56 : o mesmo formato que 10.000 a 10 30 , iniciando as letras com A e prefixando adicionalmente um sinal de intercalação (
^
) na sequência de caracteres (para que o ano 10 30 seja representado por^A1000000000000000000000000000000
e o ano 10 31 seja representado por^B10000000000000000000000000000000
). - Anos 10 56 a 10 732 : o ano é precedido por dois circunflexos e duas letras maiúsculas ASCII. As letras maiúsculas formam um número de base 26 representando o número de dígitos no ano, menos 57.
- Anos 10 732 em diante: o mesmo formato para 10 56 a 10 732 é usado, estendendo-o adicionando um sinal de intercalação adicional e uma letra maiúscula quando necessário.
- Anos aC (antes do ano 0): calcule a sequência do ano do valor absoluto do ano. Em seguida, substitua todas as letras pelo complemento da base 26 (A <-> Z, B <-> Y etc.), substitua todos os dígitos pelo complemento da base 10 (0 <-> 9, 1 <-> 8, etc.) e substitua os pontos de intercalação por pontos de exclamação (
!
). Se a sequência do ano tiver 4 dígitos ou menos (-1 a -10.000), adicione uma barra (/
). Se a sequência do ano não for prefixada por uma barra ou um ponto de exclamação, coloque um asterisco (*
).
- Meses, dias, horas, minutos e segundos : como esses valores têm apenas 2 dígitos no máximo, eles são simplesmente anexados à direita da string do ano, em ordem decrescente de significância, preenchidos à esquerda com zeros, se necessário, para formar Sequências de 2 dígitos.
- Precisão adicional : se for necessária precisão adicional (na forma de milissegundos, microssegundos, nanossegundos etc.), esses valores serão preenchidos à esquerda com zeros a 3 dígitos (porque cada valor é
1/1000
do valor anterior e, portanto, é no máximo999
) e anexado ao final do registro de data e hora, em ordem decrescente de significância.
Esse formato tem o benefício de a classificação lexical ser equivalente à classificação numérica do registro de data e hora correspondente - se o tempo A vier antes do tempo B, o registro de data e hora de A virá antes do registro de data e hora de B quando a classificação lexical for aplicada.
O desafio
Dada uma lista arbitrariamente longa de valores numéricos (correspondendo a valores de tempo em ordem decrescente de significância, por exemplo [year, month, day, hour, minute, second, millisecond]
), imprima o registro de data e hora do RFC 2550 correspondente.
Regras
- As soluções devem funcionar para qualquer entrada. As únicas limitações devem ser tempo e memória disponível.
- A entrada pode ser obtida em qualquer formato razoável e conveniente (como uma lista de números, uma lista de cadeias, uma cadeia delimitada por um único caractere que não seja um dígito, etc.).
- A entrada sempre conterá pelo menos um valor (o ano). Valores adicionais estão sempre em ordem decrescente de significância (por exemplo, a entrada nunca conterá um valor de dia sem um valor de mês ou um segundo valor seguido por um valor de mês).
- A entrada sempre será válida (por exemplo, não haverá registro de data e hora para 30 de fevereiro).
- São proibidos os componentes internos que calculam carimbos de data e hora do RFC 2550.
Exemplos
Esses exemplos usam a entrada como uma única sequência, com os valores individuais separados por pontos ( .
).
1000.12.31.13.45.16.8 -> 10001231134516008
12.1.5.1 -> 0012010501
45941 -> A45941
8675309.11.16 -> C86753091116
47883552573911529811831375872990.1.1.2.3.5.8.13 -> ^B478835525739115298118313758729900101020305008013
4052107100422150625478207675901330514555829957419806023121389455865117429470888094459661251.2.3.5.7.11 -> ^^BI40521071004221506254782076759013305145558299574198060231213894558651174294708880944596612510203050711
-696443266.1.3.6.10.15.21.28 -> *V3035567330103061015021028
-5342 -> /4657
-4458159579886412234725624633605648497202 -> !Q5541840420113587765274375366394351502797
Implementação de referência
#!/usr/bin/env python
import string
# thanks to Leaky Nun for help with this
def base26(n):
if n == 0:
return ''
digits = []
while n:
n -= 1
n, digit = divmod(n, 26)
digit += 1
if digit < 0:
n += 1
digit -= 26
digits.append(digit)
return ''.join(string.ascii_uppercase[x-1] for x in digits[::-1])
year, *vals = input().split('.')
res = ""
negative = False
if year[0] == '-':
negative = True
year = year[1:]
if len(year) < 5:
y = "{0:0>4}".format(year)
elif len(year) <= 30:
y = "{0}{1}".format(string.ascii_uppercase[len(year)-5], year)
else:
b26len = base26(len(year)-30)
y = "{0}{1}{2}".format('^'*len(b26len), b26len, year)
if negative:
y = y.translate(str.maketrans(string.ascii_uppercase+string.digits+'^', string.ascii_uppercase[::-1]+string.digits[::-1]+'!'))
if len(year) == 4:
y = '/' + y
if y[0] not in ['/', '!']:
y = '*' + y
res += y
for val in vals[:5]: #month, day, hour, minute, second
res += '{0:0>2}'.format(val)
for val in vals[5:]: #fractional seconds
res += '{0:0>3}'.format(val)
print(res)
-696443266.1.3.6.10.15.21.28
deveria ser*V3035567339896938984978971
?