Que data é essa de novo?


10

No meu site, os usuários inserem sua data de nascimento no estilo xx.xx.xx- três números de dois dígitos separados por pontos. Infelizmente, esqueci de dizer aos usuários exatamente qual formato usar. Tudo o que sei é que uma seção é usada para o mês, uma para a data e outra para o ano. O ano é definitivamente no século 20 (1900-1999), então o formato 31.05.75significa 31 May 1975. Além disso, suponho que todos usem o calendário gregoriano ou juliano.

Agora, quero examinar meu banco de dados para esclarecer a bagunça. Gostaria de começar lidando com os usuários com as datas mais ambíguas, ou seja, aquelas em que o intervalo de datas possíveis é maior.

Por exemplo, a data 08.27.53significa 27 August 1953no calendário gregoriano ou juliano. A data no calendário juliano é 13 dias depois, portanto o intervalo é justo 13 days.

Por outro lado, a notação 01.05.12pode se referir a muitas datas possíveis. O mais antigo é 12 May 1901 (Gregorian)e o mais recente é 1 May 1912 (Julian). O intervalo é 4020 days.

Regras

  • Entrada é uma sequência no formato xx.xx.xx, em que cada campo tem dois dígitos e preenchimento com zero.
  • Saída é o número de dias no intervalo.
  • Você pode assumir que a entrada sempre será uma data válida.
  • Você não pode usar nenhuma função interna de data ou calendário.
  • O código mais curto (em bytes) vence.

Casos de teste

  • 01.00.31 => 12
  • 29.00.02=> 0(A única possibilidade é 29 February 1900 (Julian))
  • 04.30.00 => 13
  • 06.12.15 => 3291

É 5, May 1975suposto ser 31st? Além disso, temos que dar conta de anos bissextos?
Maltysen

@ Maltysen Sim, corrigido. Sim.
Ypnypn

Por que não poderia ser no século 21?
ElefantPhace

@ElefantPhace As regras afirmam que o século 20 é assumido; caso contrário, não haveria data máxima.
Ypnypn 13/05

Respostas:


6

Pitão, 118 bytes

M++28@j15973358 4G&qG2!%H4FN.pmv>dqhd\0cz\.I&&&hN<hN13eN<eNhgFPNaYK+++*365JhtN/+3J4smghdJthNeNInK60aY-K+12>K60;-eSYhSY

Experimente on-line: Demonstration ou Test Suite .

Conhecimento necessário dos calendários juliano e gregoriano

O calendário juliano e gregoriano é bem parecido. Cada calendário divide um ano em 12 meses, cada um contendo de 28 a 31 dias. Os dias exatos em um mês são [31, 28/29 (depends on leap year), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]. A única diferença entre os calendários é a definição de ano bissexto. No calendário juliano, qualquer ano divisível por 4 é um ano bissexto. O calendário gregoriano é um pouco mais específico. Qualquer ano divisível por 4 é um ano bissexto, exceto o ano divisível por 100 e não divisível por 400.

Assim, no século 20, apenas um ano é diferente. O ano de 1900, que é um ano bissexto no calendário juliano, mas não um ano bissexto no calendário gregoriano. Portanto, a única data que existe em um calendário, mas não no outro calendário, é o dia 29.02.1900.

Devido à definição diferente do ano bissexto, há uma diferença entre uma data no calendário juliano e no calendário gregoriano. Diferença de 12 dias para uma data anterior a 29.02.1900e diferença de 13 dias para datas posteriores a 29.02.1900.

Pseudo-código simplificado

Y = []  # empty list
for each permutation N of the input date:
   if N is valid in the Julian Calendar:
      K = number of days since 0.01.1900
      append K to Y
      if K != 60:  # 60 would be the 29.02.1900
         L = K - (12 if K < 60 else 13) 
         append L to Y
print the difference between the largest and smallest value in Y

Explicação detalhada do código

A primeira parte M++28@j15973358 4G&qG2!%H4define uma função g(G,H), que calcula o número de dias no mês Gde um ano Hno calendário juliano.

M                            def g(G,H): return
      j15973358 4               convert 15973358 into base 4
     @           G              take the Gth element
  +28                           + 28
 +                &qG2!%H4      + (G == 2 and not H % 4)

E a próxima parte é apenas o loop for e os ifs. Observe que eu interpreto Nno formato (month, year, day). Só porque salva alguns bytes.

FN.pmv>dqhd\0cz\.
             cz\.        split input by "."
    mv>dqhd\0            map each d of ^ to: eval(d[d[0]=="0":])
FN.p                     for N in permutations(^):

I&&&hN<hN13eN<eNhgFPN   
I                          if 
    hN                        month != 0
   &                          and
      <hN13                   month < 13
  &                           and
           eN                 day != 0
 &                            and
             <eNhgFPN         day < 1 + g(month,year):

aYK+++*365JhtN/+3J4smghdJthNeN
          JhtN                    J = year
     +*365J   /+3J4               J*365 + (3 + J)/4
    +              smghdJthN      + sum(g(1+d,year) for d in [0, 1, ... month-2])
   +                        eN    + day
  K                               K = ^
aYK                               append K to Y

InK60aY-K+12>K60            
InK60                             if K != 60:
     aY-K+12>K60                    append K - (12 + (K > 60)) to Y

;-eSYhSY
;          end for loop
 -eSYhSY   print end(sorted(Y)) - head(sorted(Y))

0

Perl 5 , 294 bytes

sub f{map/(\d\d)(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])/             #1             
      &&$3<29+($2==2?!($1%4):2+($2/.88)%2)                        #2  
      &&($j{$_}=++$j+12)                                          #3
      &&$j!#1=60?$g{$_}=++$g:0,'000101'..'991231'if!%g;           #4
      pop=~/(\d\d).(\d\d).(\d\d)/;                                #5
      @n=sort{$a<=>$b}                                            #6
         grep$_,                                                  #7
         map{($j{$_},$g{$_})}                                     #8
         ("$1$2$3","$1$3$2","$2$1$3","$2$3$1","$3$1$2","$3$2$1"); #9
      $n[-1]-$n[0]}                                               #10

Experimente online!

298 bytes quando espaços, novas linhas e comentários são removidos.

As linhas 1-4 inicializam (se não concluídas) os hashes %ge %jonde os valores são os números dos dias gregoriano e juliano, contando de maneira correspondente desde o 1º de junho de 1900 até 31 de dezembro de 1999.

A linha 5 coloca a data de entrada em $ 1, $ 2 e $ 3.

A linha 9 lista todas as seis permutações desses três números de entrada.

A linha 8 converte esses seis em dois números cada, os números dos dias gregoriano e juliano, mas apenas aqueles com datas válidas.

A linha 7 garante isso, filtra os números de dias inexistentes.

A linha 6 classifica a lista de números de datas válidos, do menor para o maior.

A linha 10 retorna a diferença entre o último e o primeiro (máximo e mínimo), que era o intervalo desejado.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.