RFC 2550 es una propuesta satírica (publicada el 1 de abril de 1999) para una representación ASCII de marcas de tiempo que ahorre espacio y que pueda admitir cualquier fecha (incluso las anteriores al comienzo del universo y las que están más allá del final previsto del universo). El algoritmo para calcular una marca de tiempo que cumple con RFC 2550 es el siguiente (nota: todos los rangos incluyen el inicio pero excluyen el final - 0 a 10,000 significa todo n
donde 0 <= n < 10000
):
- Formato de año
- Años 0 a 10,000: un número decimal de 4 dígitos, rellenado con ceros a la izquierda.
- Años 10,000 a 100,000: un número decimal de 5 dígitos, prefijado con el carácter A.
- Años 100,000 a 10 30 : el número decimal para el año, prefijado con la letra mayúscula ASCII cuyo índice en el alfabeto inglés es igual al número de dígitos en el año decimal, menos 5 (B para años de 6 dígitos, C para 7 -de años dígitos, etc.).
- Años 10 30 a 10 56 : el mismo formato que 10,000 a 10 30 , comenzando las letras de nuevo con A, y adicionalmente un prefijo caret (
^
) a la cadena (de modo que el año 10 30 está representado por^A1000000000000000000000000000000
, y el año 10 31 está representado por^B10000000000000000000000000000000
). - Años 10 56 a 10 732 : el año está precedido por dos símbolos y dos letras mayúsculas ASCII. Las letras mayúsculas forman un número de base 26 que representa el número de dígitos en el año, menos 57.
- Años 10 732 en adelante: se usa el mismo formato para 10 56 a 10 732 , extendiéndolo agregando un intercalado adicional y una letra mayúscula cuando sea necesario.
- BCE años (antes del año 0): calcule la cadena del año del valor absoluto del año. Luego, reemplace todas las letras por su complemento de base 26 (A <-> Z, B <-> Y, etc.), reemplace todos los dígitos por su complemento de base 10 (0 <-> 9, 1 <-> 8, etc.), y reemplace las marcas con signos de exclamación (
!
). Si la cadena del año tiene 4 dígitos o menos (es decir, -1 a -10,000), anteponga una barra diagonal (/
). Si la cadena del año no está precedida por una barra diagonal o un signo de exclamación, anteponga un asterisco (*
).
- Meses, días, horas, minutos y segundos : dado que estos valores tienen solo 2 dígitos como máximo, simplemente se agregan a la derecha de la cadena del año, en orden decreciente de importancia, se rellenan con ceros a la izquierda si es necesario para formar Cadenas de 2 dígitos.
- Precisión adicional : si se necesita precisión adicional (en forma de milisegundos, microsegundos, nanosegundos, etc.), esos valores se rellenan a la izquierda con ceros a 3 dígitos (porque cada valor es
1/1000
del valor anterior, y por lo tanto es como máximo999
) y se adjunta al final de la marca de tiempo, en orden decreciente de importancia.
Este formato tiene la ventaja de que la ordenación léxica es equivalente a la ordenación numérica de la marca de tiempo correspondiente: si el tiempo A llega antes que la hora B, entonces la marca de tiempo para A aparecerá antes de la marca de tiempo para B cuando se aplique la ordenación léxica.
El reto
Dada una lista arbitrariamente larga de valores numéricos (correspondientes a valores de tiempo en orden decreciente de importancia, por ejemplo [year, month, day, hour, minute, second, millisecond]
), genera la marca de tiempo RFC 2550 correspondiente.
Reglas
- Las soluciones deben funcionar para cualquier entrada dada. Las únicas limitaciones deberían ser el tiempo y la memoria disponible.
- La entrada puede tomarse en cualquier formato razonable y conveniente (como una lista de números, una lista de cadenas, una cadena delimitada por un solo carácter que no sea un dígito, etc.).
- La entrada siempre contendrá al menos un valor (el año). Los valores adicionales siempre están en orden decreciente de importancia (por ejemplo, la entrada nunca contendrá un valor de día sin un valor de mes, o un segundo valor seguido de un valor de mes).
- La entrada siempre será una hora válida (por ejemplo, no habrá ninguna marca de tiempo para el 30 de febrero).
- Las construcciones que calculan las marcas de tiempo RFC 2550 están prohibidas.
Ejemplos
Estos ejemplos usan la entrada como una sola cadena, con los valores individuales separados por puntos ( .
).
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
Implementación de referencia
#!/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
debería ser*V3035567339896938984978971
?