Calcular o carimbo de data / hora do RFC 2550

26

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 nque 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 ^A1000000000000000000000000000000e 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/1000do valor anterior e, portanto, é no máximo 999) 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)
Mego
fonte
Certamente -696443266.1.3.6.10.15.21.28deveria ser *V3035567339896938984978971?
305 Neil
11
@ Neil Até inventarmos meses negativos. Dezembro.
Mego 30/05
1
@TaylorScott 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.
Mego
2
Parece-me que as especificações fornecidas na pergunta não correspondem à RFC2550. Pelo que entendi, assim que você passar dos três pontos, o número de letras deve aumentar mais rapidamente do que os números, porque é derivado da série Fibonacci (4 caracteres significa 5 letras, 5 caracteres significa 8 letras, etc.) É seguro suponha que deveríamos estar ignorando esse aspecto da RFC?
James Holderness
1
@JamesHolderness Você está certo, eu estraguei as especificações. No entanto, é tarde demais para corrigi-lo, pois já existem respostas que seriam invalidadas.
Mego

Respostas:

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>

Chocantemente longo.

Neil
fonte
Você se importaria em adicionar um snippet de pilha para facilitar o teste?
Mego 31/05
@Mego Done. Também corrigidos alguns erros que penetrou em (I acidentalmente apagou parte do código ao copiar e colar porque a quebra de linha me confundiu Opa..)
Neil
3

Befunge, 418 384 bytes

É difícil dizer com antecedência o tamanho de um programa Befunge e, quando comecei a trabalhar nisso, pensei que poderia ter alguma chance de competir. Acontece que eu estava errado.

~: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-:^

Experimente online!

James Holderness
fonte
3

Perl 5 , 328322231301 + 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

Experimente online!

Ungolfed

$_=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
fonte
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;}

Insira como Stringmatriz e retorne como String.

Acabou sendo bastante longo (como esperado), mas definitivamente pode ser jogado um pouco mais. Estou feliz que funcione depois de mexer nele por um bom tempo ..

Experimente aqui.

Explicação:

  • for(String p:s){: Loop sobre as peças
    • if(p.charAt(0)<46){p=p.substring(1);f=1;}: Determine se é negativo e, se for, remova o sinal de menos e defina um sinalizador para reduzir bytes
    • t=p.length();: Obtenha a quantidade de dígitos
    • if(i++<1){: Se for o primeiro número (o ano):
      • t<5?"000".substring(t-1): Se for de 0 a 100.000 (exclusivo): adicione zeros à esquerda, se necessário
      • t<32?(char)(t+60): Se for 100.000-10 30 (exclusivo): adicione uma letra inicial
      • t<58?"^"+(char)(t+34): Se for 10 30 -10 732 (exclusivo): adicione uma letra literal "^"+ à esquerda
      • if(t>57)for(r+="^^",u=675;u<t-57;u*=26)r+="^";: Adicione a quantidade apropriada de letras iniciais literais "^"+ x="";for(String c:Long.toString(t-57,26).toUpperCase().split(""))x+=z.charAt((y+q).indexOf(c));r+=x;: (conversão de base 26 em alfabeto)
      • r+=p;: Adicione o próprio ano ao resultado-String
      • if(f>0){: Se o ano foi negativo:
        • x=t<5?"/":t<32?"*":r.replace("^","!").replaceAll("[^!]","");: Crie uma String temporário xcom o correto /, *ou um ou múltiplos!
        • for(char c c:r.toCharArray())x+=c>93?"":"ZYXWVUTSRQPONMLKJIHGFEDCBA9876543210".charAt((z+y).indexOf(c));: Faça a conversão (A↔Z, B↔Y, 0↔9, 1↔8 etc.)
        • r=x;: E defina o resultado para esta temperatura String x
    • else: Se for o mês, dias, horas, minutos, segundos, milissegundos, microssegundos, nanossegundos ou menor:
      • i>6?t<2?"00"+p:t<3?0+p:p: Se for milissegundos ou menor: adicione zeros à esquerda, se necessário
      • :t<2?0+p:p;: Outro (mês, dias, horas, minutos, segundos): adicione zero inicial simples, se necessário
  • return r: Retornar o resultado
Kevin Cruijssen
fonte
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.).- você pode considerar a entrada como uma lista de números e pular a divisão e a conversão dispendiosas.
Mego
1
@Mego Infelizmente, numéricos padrão ( longcom 64 bits sendo o maior) são muito pequenos em Java para algumas das entradas, portanto, Stringsão mais curtos que java.math.BigInteger. Eu mudei para um Stringarray, no entanto, não preciso dividir por pontos, o que salvou alguns bytes, então obrigado.
Kevin Cruijssen
2

Excel VBA, 500 486 485 470 bytes

Função de janela imediata VBE anônima

A função de janela imediata VBE anônima, que recebe entrada como ano [A1], mês [B1], dias [C1], horas [D1], minutos [E1], segundos [F1]e uma matriz de precisão extra opcional [G1:Z1], calcula o carimbo de data / hora do RFC2550 e envia para a janela imediata do VBE. Faz uso da função auxiliar declarada abaixo.

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

Função auxiliar

Função auxiliar declarada que pega um número de entrada e retorna esse número na base-26, de modo que 1->Ae26->Z

Deve ser colocado em um 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

Deve ser utilizado em um módulo clara, ou o módulo deve ser limpo antes da execução como os vars j, oe pestão a ser assumida em seu padrão, o estado não inicializado no início da execução do código. Para j, que é uma Variant\Integervariável, esse valor padrão é0 e para oe p, que são Variant\Stringvariáveis, esse valor padrão é a sequência vazia ( "").

A entrada, uma matriz de cadeias, é retirada do 1:1ActiveSheet e a saída é para a janela imediata do VBE.

E / S de amostra

[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

SubVersão de rotina

Sub-rotina declarada que recebe entrada como ano [A1], mês [B1], dias [C1], horas [D1], minutos [E1], segundos [F1]e uma matriz de precisão extra opcional [G1:Z1], calcula o carimbo de data / hora do RFC2550 e é enviado para a janela imediata do 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

A entrada no intervalo [A1:ZZ1]pode ser feita manualmente, digitando nas células, da esquerda para a direita, conforme necessário ou atribuindo a partir da janela imediata do VBE.

Observe que, devido à conversão automática de números do Excel em notação científica, qualquer número que tenha um comprimento de base 10 igual ou superior a 12 dígitos deve ser inserido explicitamente na célula como texto, definindo a célula como uma célula de texto ou anexando o literal 'ao início do valor da célula

E / S de amostra

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

Ungolfed And Explained

''  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
fonte
2

Geléia , 165 126 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

Experimente online!

A linha 4 faz a formatação do ano com a ajuda das linhas 2 e 3. A primeira e a última linha lidam com zero preenchendo os elementos da entrada nos comprimentos adequados e concatenando-os com o ano formatado.

  • _µ‘l26Ċṗ@€ØAẎị@encontra o prefixo 26 base. É necessário o poder cartesiano do alfabeto ( ØA) para cada número entre 1 e teto (log 26 (piso (log 10 (ano)) - n + 1)) (onde n é 30 ou 4) e, em seguida, obtém índices nessa lista com piso (log 10 (ano)) - n (ị@ ).
  • ç30;€”^UZF formata anos> = 10 30 ( ®L>30¤?)
  • ç4⁶;formata anos <10 30 . ( Editar : salvou um byte usando em ⁶;vez de ;@⁶)
  • 1RḊ fornece um prefixo vazio para anos <10 5 ( ®L>4¤?). Ele pega a lista de dígitos e filtra todos os elementos em si. Basta usar isso para produzir, []porque não funciona aqui. Isso apenas avalia como []. e []não trabalhe aqui e não consegui encontrar outros 2 bytes que retornam uma lista vazia.
  • ;®AṾ€¤ acrescenta o ano ao prefixo e depois o nivela.
  • L=4”/xprefixa a /se a duração do ano for 4 na declaração do ®S<0¤¡.
  • 2£FiЀ¹ị€2£UF¤leva os complementos de A .. Z, 0 .. 9e ^ /*!se o ano é negativo ( ®S<0¤¡). refere-se ao segundo link, ØD,“^ *!”,ØAque é a lista [['0' .. '9'], ['^',' ','/','*','!'], ['A' .. 'Z']]. Com um ano formatado como ^C125...esse link, o índice de cada caractere na versão achatada usa esses índices para construir uma nova sequência a partir da versão achatada de onde cada sublist é revertida, ou seja ['9' .. '0','!','*','/',' ','^','Z' .. 'A'], produzindo !X874.... /mapeia para si mesmo porque é prefixado antes que tudo seja executado.
  • L=4a®S<0x@”/;adiciona um /ao início de anos negativos em [-9999 .. -0001]. Meu palpite é que isso pode ser reduzido. Acabei incluindo isso na declaração do (anterior ¡) e salvei 7 bytes, porque não precisava testar os anos negativos duas vezes.

Existem muitos usos ¡na linha 4 e acho que eles podem ser compactados usando, ?mas não sei como fazê-los funcionar. Eu comecei ?a trabalhar e salvei alguns bytes.

James Holderness apontou que minha primeira submissão não lidou com anos com 30 dígitos corretos. Aconteceu que o bug era para qualquer ano que precisasse de um Zprefixo 26 na base. Acontece que eu não poderia usar, porque quando você converte 26 em base 26, ele fornece em [1,0]vez de 26(duh). Em vez disso, usei pares encomendados com reposição. Eu não acho que exista um átomo para isso, mas se houver, posso salvar alguns bytes. Corrigir isso acabou me custando ~ 40 bytes. Definitivamente, meu programa de geléia mais longo ainda. Edit : Encontrou uma maneira mais curta de fazer o produto cartesiano. Percebi que não tinha certeza de que o último funcionava para prefixos com mais de duas letras, mas a nova maneira funciona.

Desculpe pelas muitas vezes que editei este post, continuo descobrindo maneiras de reduzi-lo.

dylnan
fonte