Calcule la marca de tiempo RFC 2550

26

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 ndonde 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/1000del valor anterior, y por lo tanto es como máximo 999) 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)
Mego
fuente
Seguramente -696443266.1.3.6.10.15.21.28debería ser *V3035567339896938984978971?
Neil
11
@Neil Hasta que inventemos meses negativos. Negember
Mego
1
@TaylorScott 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.
Mego
2
Me parece que la especificación dada en la pregunta no coincide con RFC2550. Según tengo entendido, una vez que pases las tres letras, el número de letras debería aumentar más rápido que las letras, porque se deriva de la serie Fibonacci (4 letras significa 5 letras, 5 letras significa 8 letras, etc.) ¿Es seguro ¿Asumimos que deberíamos ignorar ese aspecto del RFC?
James Holderness
1
@JamesHolderness Tienes razón, estropeé la especificación. Sin embargo, es demasiado tarde para corregirlo, ya que ya hay respuestas que serían invalidadas.
Mego

Respuestas:

5

JavaScript (ES6), 325 bytes

f=
s=>s.split`.`.map((n,i)=>i?`00${n}`.slice(i>5?-3:-2):n<'0'?g(n.slice(1),'!','*','/').replace(/\w/g,c=>c>'9'?(45-parseInt(c,36)).toString(36):9-c):g(n),g=(n,c='^',d='',e='',l=n.length)=>l<5?e+`000${n}`.slice(-4):l<31?d+(l+5).toString(36)+n:h(l-30,c)+n,h=(n,c)=>n?c+h(--n/26|0,c)+(n%26+10).toString(36):'').join``.toUpperCase()
;
<input oninput=o.value=f(this.value);><input id=o>

Sorprendentemente largo.

Neil
fuente
¿Le importaría agregar un Fragmento de pila para realizar pruebas fácilmente?
Mego
@Mego hecho. También se corrigieron algunos errores tipográficos que se deslizaron (borré accidentalmente parte del código al copiar y pegar porque el ajuste de línea me confundió. ¡Vaya!)
Neil
3

Befunge, 418 384 bytes

Es difícil saber de antemano qué tan grande es probable que termine un programa Befunge, y cuando comencé a trabajar en esto pensé que en realidad podría tener alguna posibilidad de competir. Resulta que estaba equivocado.

~:59*-!:00p:2*1\-10p:9*68*+20p>0>#~$_v
68*-:0\`30p\>>:"P"%\"P"/9+p30g#v_1+:~>
0\`v`\0:\p04<<:+1g04-$<_\49+2*v>0>+#1:#\4#g\#0`#2_130p040p5-::01-`\49+2*-:
v:$_\50p\$:130g:1+30p:!^!:-1\*<>g*"A"++\49+2*/50g1-:
_$1+7g00g40g!**:!>_40g:!v!:\g8<^00*55*g01%*2+94:p05
|#9/"P"\%"P":<:_,#!>#:<$_1-00g^v3$\_\#`\0:>#g+
>10g*20g+,1+:^v\&\0+2`4:_@#`<0+<
/*v*86%+55:p00<_$$>:#,_$1+~0^
^!>+\55+/00g1-:^

Pruébalo en línea!

James Holderness
fuente
3

Perl 5 , 328 322 317 301 + 1 ( -a) = 302 bytes

$_=shift@F;if(($l=y/-//c)<5){s/^/0 x(4-$l)/e}elsif($l<57){s/^/'^'x($l>30).chr 65+($l-5)%26/e}else{$l-=57;do{s/\^*\K/'^'.chr 65+$l%26/e}while$l=int$l/26;s/^\^\K\D-?\d/^A$&/}if(s/-//){s%^....$%/$&%;eval join'',reverse'!/',0..9,A..Z,"y/A-Z0-9^/";s%^[^!/]%*$&%}printf$_.'%02d'x(@F>5?5:@F).'%03d'x(@F-5),@F

Pruébalo en línea!

Sin golf

$_=shift@F; # Store the year in the default variable for easier regex

if(($l=y/-//c)<5){      # if the length of the year is less than 5
    s/^/0 x(4-$l)/e         # pad with leading zeros to 4 digits
}elsif($l<57){          # if the length is less than 57
    s/^/'^'x($l>30).chr 65+($l-5)%26/e  # put a carat at the front if there are more than 30 characters
                        # and map the length minus 5 to A-Z
}else{
    $l-=57;         # offset the length by 57
    do{         
        s/\^*\K/'^'.chr 65+$l%26/e # put a carat at the front and map the length to base 26 (A-Z)
    }while$l=int$l/26;  # until the length is down to 0
    s/^\^\K\D-?\d/^A$&/ # insert an extra '^A' to pad the result to at least 2 characters if there was only 1
}
if(s/-//){          # if the year is negative
    s%^....$%/$&%;          # put a '/' in front of a 4 digit year
    eval join'',reverse'!/',0..9,A..Z,"y/A-Z0-9^/"; # map A-Z,0-9, and ^ to Z-A,9-0, and ! respectively
    s%^[^!/]%*$&%           # add a * at the front if there are no other indicators
}
printf$_.           # output the year
'%02d'x(@F>5?5:@F).             # followed by the month, day, hour, and minutes, padded to 2 digits
'%03d'x(@F-5),@F                # followed by fractional seconds, padded to three digits
Xcali
fuente
3

Java 8, 653 640 637 623 bytes

s->{String r="",q="ABCDEFGHIJKLMNOP",z=q+"QRSTUVWXYZ",y="0123456789",x;int i=0,f=0,t,u;for(String p:s){if(p.charAt(0)<46){p=p.substring(1);f=1;}t=p.length();if(i++<1){r+=(t<5?"000".substring(t-1):t<32?(char)(t+60):t<58?"^"+(char)(t+34):"");if(t>57){for(r+="^^",u=675;u<t-57;u*=26)r+="^";x="";for(String c:Long.toString(t-57,26).toUpperCase().split(""))x+=z.charAt((y+q).indexOf(c));r+=x;}r+=p;if(f>0){x=t<5?"/":t<32?"*":r.replace("^","!").replaceAll("[^!]","");for(char c:r.toCharArray())x+=c>93?"":"ZYXWVUTSRQPONMLKJIHGFEDCBA9876543210".charAt((z+y).indexOf(c));r=x;}}else r+=i>6?t<2?"00"+p:t<3?0+p:p:t<2?0+p:p;}return r;}

Ingrese como String-array y return-type como String.

Resultó ser bastante largo (como se esperaba), pero definitivamente se puede jugar un poco más. Me alegro de que funcione después de jugar con él durante bastante tiempo ...

Pruébalo aquí

Explicación:

  • for(String p:s){: Bucle sobre las partes
    • if(p.charAt(0)<46){p=p.substring(1);f=1;}: Determine si es negativo y, si lo es, elimine el signo menos y establezca un indicador para reducir bytes
    • t=p.length();: Obtener la cantidad de dígitos
    • if(i++<1){: Si es el primer número (el año):
      • t<5?"000".substring(t-1): Si es 0-100,000 (exclusivo): agregue ceros a la izquierda si es necesario
      • t<32?(char)(t+60): Si es 100,000-10 30 (exclusivo): agregue una letra inicial
      • t<58?"^"+(char)(t+34): Si se trata de 10 30 -10 732 (exclusivo): Añadir un literal "^"carta que lleva +
      • if(t>57)for(r+="^^",u=675;u<t-57;u*=26)r+="^";: Agregue la cantidad apropiada de literal "^"+ x="";for(String c:Long.toString(t-57,26).toUpperCase().split(""))x+=z.charAt((y+q).indexOf(c));r+=x;: letras iniciales (conversión de base 26 a alfabeto)
      • r+=p;: Agregar el año en sí mismo a la cadena de resultados
      • if(f>0){: Si el año fue negativo:
        • x=t<5?"/":t<32?"*":r.replace("^","!").replaceAll("[^!]","");: Cree una cadena temporal xcon la correcta /, *o una o varias!
        • for(char c c:r.toCharArray())x+=c>93?"":"ZYXWVUTSRQPONMLKJIHGFEDCBA9876543210".charAt((z+y).indexOf(c));: Realice la conversión (A↔Z, B↔Y, 0↔9, 1↔8, etc.)
        • r=x;: Y luego establezca el resultado en esta cadena temporal x
    • else: Si es el mes, días, horas, minutos, segundos, milisegundos, microsegundos, nanosegundos o menos:
      • i>6?t<2?"00"+p:t<3?0+p:p: Si es milisegundos o menor: agregue ceros a la izquierda si es necesario
      • :t<2?0+p:p;: Lo demás (mes, días, horas, minutos, segundos): agregue un cero inicial si es necesario
  • return r: Devolver el resultado
Kevin Cruijssen
fuente
Input may be taken in any reasonable, convenient format (such as a list of numerics, a list of strings, a string delimited by a single non-digit character, etc.).- podría tomar la entrada como una lista de números y omitir la costosa división y conversión.
Mego
1
@Mego Desafortunadamente, los números predeterminados ( longcon 64 bits son los más grandes) son demasiado pequeños en Java para algunas de las entradas, por lo que Stringson más cortos que java.math.BigInteger. StringSin embargo, lo cambié a una matriz, así que no necesito hacer la división por puntos, lo que ahorró algunos bytes, así que gracias.
Kevin Cruijssen
2

Excel VBA, 500 486 485 470 Bytes

Función de ventana inmediata anónima de VBE

La función de ventana inmediata anónima de VBE que toma la entrada como año desde [A1], mes desde [B1], días desde [C1], horas desde [D1], minutos desde [E1], segundos desde [F1]y una matriz de precisión adicional opcional desde [G1:Z1], calcula la marca de tiempo RFC2550 y las salidas a la ventana inmediata VBE. Utiliza la función auxiliar declarada a continuación.

n=Left([A1],1)="-":y=Mid([A1],1-n):l=Len(y):o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y):For Each c In[B1:Z1]:j=j+1:p=p+IIf(c,Format(c,IIf(j>5,"000","00")),""):Next:If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:?IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))Replace(o,"=","!")p:Else?o;p

Función auxiliar

Función auxiliar declarada que toma un número de entrada y devuelve ese número en base-26 tal que 1->Ay26->Z

Debe colocarse en un módulo público.

Function b(n)
While n
n=n-1
d=n Mod 26+1
n=Int(n/26)
d=d+26*(d<0):n=n-(d<0)
b=Chr(64+d)+b
Wend
End Function

Uso

Debe usarse en un módulo transparente, o el módulo debe borrarse antes de la ejecución como vars j, oy pse supone que se encuentra en su estado predeterminado, no inicializado al comienzo de la ejecución del código. Para j, que es una Variant\Integervariable, este valor predeterminado es 0y para oy p, que son Variant\Stringvariables, este valor predeterminado es la cadena vacía ( "").

La entrada, una matriz de cadenas, se toma de 1:1ActiveSheet y la salida se dirige a la ventana inmediata de VBE.

Muestra de E / S

[A1:F1]=Split("4052107100422150625478207675901330514555829957419806023121389455865117429470888094459661251.2.3.5.7.11",".")
n=Left([A1],1)="-":y=Mid([A1],1-n):l=Len(y):o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y):For Each c In[B1:ZZ1]:j=j+1:p=p+IIf(c,Format(c,IIf(j>5,"000","00")),""):Next:If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:?IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))Replace(o,"=","!")p:Else?o;p
^^BI40521071004221506254782076759013305145558299574198060231213894558651174294708880944596612510203050711021028

Cells.Clear:j=0:o="":p="" '' clear the worksheet and vars
[A1:H1]=Array("-696443266","1","3","6","10","15","21","28")
n=Left([A1],1)="-":y=Mid([A1],1-n):l=Len(y):o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y):For Each c In[B1:ZZ1]:j=j+1:p=p+IIf(c,Format(c,IIf(j>5,"000","00")),""):Next:If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:?IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))Replace(o,"=","!")p:Else?o;p
*V3035567330103061015021028

Cells.Clear:j=0:o="":p="" '' clear the worksheet and vars
[A1]="45941"
n=Left([A1],1)="-":y=Mid([A1],1-n):l=Len(y):o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y):For Each c In[B1:ZZ1]:j=j+1:p=p+IIf(c,Format(c,IIf(j>5,"000","00")),""):Next:If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:?IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))Replace(o,"=","!")p:Else?o;p
A45941

Cells.Clear:j=0:o="":p="" '' clear the worksheet and vars
[A1:F1]=Split("4052107100422150625478207675901330514555829957419806023121389455865117429470888094459661251.2.3.5.7.11",".")
n=Left([A1],1)="-":y=Mid([A1],1-n):l=Len(y):o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y):For Each c In[B1:ZZ1]:j=j+1:p=p+IIf(c,Format(c,IIf(j>5,"000","00")),""):Next:If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:?IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))Replace(o,"=","!")p:Else?o;p
^^BI40521071004221506254782076759013305145558299574198060231213894558651174294708880944596612510203050711

SubVersión de rutina

La subrutina declarada que toma la entrada como año desde [A1], mes desde [B1], días desde [C1], horas desde [D1], minutos desde [E1], segundos desde [F1]y una matriz de precisión adicional opcional desde [G1:Z1], calcula la marca de tiempo RFC2550 y las salidas a la ventana inmediata de VBE.

Sub R(x)
a=x(0)
n=Left(a,1)="-"'<- that `"` is only there to make sure highlighting is correct
y=Mid(a,1-n)
l=Len(y)
o=IIf(l<5,Right("000"&y,4),IIf(l<31,"",String(Len(b(l-30)),94))&B(l-IIf(l<31,4,30))&y)
If n Then For i=1To Len(o):c=Asc(Mid(o,i,1)):Mid$(o,i,1)=Chr(IIf(c<60,105,155)-c):Next:o=IIf(l<5,"/",IIf(InStr(1,o,"="),"","*"))&Replace(o,"=","!")
For j=1To UBound(x)
o=o+IIf(x(j),Format(x(j),IIf(j>5,"000","00")),"")
Next
[A2]=o
End Sub
Function b(n)
While n
n=n-1
d=n Mod 26+1
n=Int(n/26)
d=d+26*(d<0):n=n-(d<0)
b=Chr(64+d)+b
Wend
End Function

Uso

La entrada al rango [A1:ZZ1]puede hacerse manualmente, escribiendo en las celdas, de la izquierda a la derecha, según sea necesario o asignando desde la ventana inmediata de VBE.

Es de destacar que, debido a los números de conversión automática de Excel en notación científica, cualquier número que tenga una longitud de base 10 igual o mayor a 12 dígitos debe insertarse explícitamente en la celda como texto configurando la celda para que sea una celda de texto o al anteponer el literal 'al comienzo del valor de la celda

Muestra de E / S

r Split("4052107100422150625478207675901330514555829957419806023121389455865117429470888094459661251.2.3.5.7.11",".")
?[A2]  '' <- print output to VBE console
^^BI40521071004221506254782076759013305145558299574198060231213894558651174294708880944596612510203050711 ''  <- Output

r Array("47883552573911529811831375872990","1","1","2","3","5","8","13")
?[A2]
^B478835525739115298118313758729900101020305008013

r Array("-696443266","1","3","6","10","15","21","28")
?[A2]
*V3035567330103061015021028

r Array("45941")
?[A2]
A45941

Sin golfed y explicado

''  Returns RFC2550 timestamp corresponding to passed vars
Public Function RFC2550(ByVal pYear As String, ParamArray Extra() As Variant) As String

    ''  Declare Vars
    Dim Negative As Boolean, _
        leny As Long, _
        i As Long, _
        c As Byte, _
        s As Variant, _
        out As String

    ''  Check if year is negative and store the absolute value of the year
    Let Negative = Left(pYear, 1) = "-"
    Let pYear = Mid(pYear, 1 - Negative)

    ''  Take the length of the year
    Let leny = Len(pYear)
    If leny < 5 Then
        ''  If the length is less than 5, pad the year left to 4 characters 
        ''  using zeros
        Let out = Format("0000", pYear)
    Else
        ''  If the length of the year is greater than 30, then set out to be 
        ''  as string comprised of length-30 instances of `^`
        Let out = IIf(leny < 31, "", String(Len(Base26(leny - 30)), 94)) 
        ''  append the Base26 representation of the length of the year,
        ''  minus 30, if the length is greater than 30
        Let out = out & Base26(leny - IIf(leny < 31, 4, 30)) 
        ''  append the year to out
        Let out = out & pYear
    End If


    If Negative Then
        ''  iterate across out
        For i = 1 To Len(out)
            ''  store the char code for the current char
            Let c = Asc(Mid(out, i, 1))
            ''  swap letter/number with its inverse (0->9,A->Z)
            Mid$(out, i, 1) = Chr(IIf(c < 60, 105, 155) - c)
        Next i

        ''  replace `=` (the inverse of `^`) with `!`
        Let out = Replace(out, "=", "!")
        ''  Prepend either `/`, `*`, or nothing depending on length and 
        ''  start of out
        Let out = IIf(leny < 5, "/", IIf(InStr(1, out, "!"), "", "*")) & out
    End If

    Let i = 1
    For Each s In Extra
        ''  append all of the extra precision data - padding to 2 chars for 
        ''  the first 5 elements in the array (month, day, hour, minute and 
        ''  second) and to 3 chars for all following elements (milli, micro, 
        ''  nano, pico, femto, atto, zepto, yocto - seconds) with the char 0
        Let out = out & IIf(s, Format(s, IIf(i > 5, "000", "00")), "")
        Let i = i + 1
    Next

    ''  return out
    Let RFC2550 = out 

End Function


''  returns non-standard base26 version of input number 
''  1->A, 2->B,... 26->Z
Function Base26(ByVal n As Long) As String

    ''  declare vars
    Dim out As String, _
        digit As Integer

    ''  init out, digit
    Let out = ""
    Let digit = 0

    ''  iterate through n 
    While n
        ''  Decrement, hold the value of the digit
        Let n = n - 1
        Let digit = n Mod 26 + 1

        ''  divide by 26
        Let n = Int(n / 26)

        ''  correct for negative numbers
        If digit < 0 Then Let n = n + 1: Let digit = digit - 26

        ''  prepend char corresponding to the digit to out
        Let out = Chr(64 + digit) & out
    Wend

    ''  return out
    Let Base26 = out
End Function
Taylor Scott
fuente
2

Jalea , 165126 bytes

ḣ5ṫ€3
ØD,“^ /*!”,ØA
_µ‘l26Ċṗ@€ØAẎị@
Lµç30;€”^UZFµç4⁶;µ®L>30¤?µḟ®L>4¤?;®AṾ€¤µL=4”/x2£FiЀị€2£UF¤µ®S<0¤¡
4R¬+DU$UµḢ©Ç;Ñ;ṫ6ṫ€2$$F

Pruébalo en línea!

La línea 4 formatea el año con ayuda de las líneas 2 y 3. La primera y la última línea tratan con cero rellenando los elementos de la entrada a sus longitudes apropiadas y luego los concatena con el año formateado.

  • _µ‘l26Ċṗ@€ØAẎị@encuentra el prefijo base 26. Toma el poder cartesiano del alfabeto ( ØA) para cada número entre 1 y ceil (log 26 (floor (log 10 (year)) - n + 1)) (donde n es 30 o 4) luego obtiene índices en esta lista con piso (log 10 (año)) - n ( ị@).
  • ç30;€”^UZF formatos años> = 10 30 ( ®L>30¤?)
  • ç4⁶;formatos años <10 30 . ( Editar : guardado un byte usando en ⁶;lugar de ;@⁶)
  • 1RḊ da un prefijo vacío para años <10 5 ( ®L>4¤?). Toma la lista de dígitos y luego filtra cada elemento en sí mismo. Simplemente usando esto para ceder []porque no funciona aquí. Esto solo se evalúa como []. y []no funciona aquí y no pude encontrar otros 2 bytes que devuelven una lista vacía.
  • ;®AṾ€¤ agrega el año al prefijo y luego lo aplana.
  • L=4”/xprefijos a /si la duración del año es 4 en la declaración do de ®S<0¤¡.
  • 2£FiЀ¹ị€2£UF¤toma los complementos de A .. Z, 0 .. 9y ^ /*!si el año es negativo ( ®S<0¤¡). se refiere al segundo enlace, ØD,“^ *!”,ØAque es la lista [['0' .. '9'], ['^',' ','/','*','!'], ['A' .. 'Z']]. Con un año formateado como ^C125...este, el enlace encuentra el índice de cada carácter en la versión aplanada y luego usa esos índices para construir una nueva cadena a partir de la versión aplanada donde se invierte cada sublista, es decir ['9' .. '0','!','*','/',' ','^','Z' .. 'A'], cede !X874.... /se asigna a sí mismo porque tiene el prefijo antes de que todo tome su complemento.
  • L=4a®S<0x@”/;agrega un /al comienzo de años negativos en [-9999 .. -0001]. Supongo que esto se puede acortar. Terminé incluyendo esto en la declaración do anterior ( ¡) y guardé 7 bytes porque luego no tuve que probar dos años negativos.

Hay muchos usos ¡en la línea 4 y creo que podrían comprimirse usando en su ?lugar, pero no estoy seguro de cómo hacer que funcionen. Me puse ?a trabajar y guardé algunos bytes.

James Holderness señaló que mi primera presentación no manejó años con 30 dígitos correctos. Resultó que el error era para cualquier año que necesitara un Zprefijo en la base 26. Resulta que no pude usar porque cuando conviertes 26 a base 26 te da en [1,0]lugar de 26(duh). En cambio, usé pares ordenados con reemplazo. No creo que haya un átomo para eso, pero si lo hay, puedo guardar algunos bytes. Arreglar esto terminó costándome ~ 40 bytes. Definitivamente mi programa de gelatina más largo hasta ahora. Editar : se encontró una forma más corta de hacer el producto cartesiano. Me di cuenta de que no estaba seguro de que el último funcionara para prefijos con más de dos letras de todos modos, pero la nueva forma funciona.

Perdón por las muchas veces que he editado esta publicación, sigo descubriendo formas de acortarla.

dylnan
fuente