¿Qué fecha es esa otra vez?


10

En mi sitio web, los usuarios ingresan su fecha de nacimiento en el estilo xx.xx.xx: tres números de dos dígitos separados por puntos. Desafortunadamente, olvidé decirles a los usuarios exactamente qué formato usar. Todo lo que sé es que una sección se usa para el mes, otra para la fecha y otra para el año. El año definitivamente es en el siglo 20 (1900-1999), por lo que el formato 31.05.75significa 31 May 1975. Además, supongo que todos usan el calendario gregoriano o juliano.

Ahora, quiero revisar mi base de datos para aclarar el desorden. Me gustaría comenzar tratando con los usuarios con las fechas más ambiguas, es decir, aquellas donde el rango de fechas posibles es el mayor.

Por ejemplo, la fecha 08.27.53significa 27 August 1953en el calendario gregoriano o juliano. La fecha en el calendario juliano es 13 días después, por lo que el rango es justo 13 days.

En contraste, la notación 01.05.12puede referirse a muchas fechas posibles. Lo primero es 12 May 1901 (Gregorian), y lo último es 1 May 1912 (Julian). El rango es 4020 days.

Reglas

  • La entrada es una cadena en el formato xx.xx.xx, donde cada campo tiene dos dígitos y está rellenado con ceros.
  • La salida es el número de días en el rango.
  • Puede suponer que la entrada siempre será una fecha válida.
  • No puede usar ninguna fecha incorporada o funciones de calendario.
  • El código más corto (en bytes) gana.

Casos de prueba

  • 01.00.31 => 12
  • 29.00.02=> 0(La única posibilidad es 29 February 1900 (Julian))
  • 04.30.00 => 13
  • 06.12.15 => 3291

¿Se 5, May 1975supone que debe ser 31st? Además, ¿tenemos que tener en cuenta los años bisiestos?
Maltysen

@ Maltysen Sí, arreglado. Si.
Ypnypn

¿Por qué no podría ser en el siglo XXI?
ElefantPhace

@ElefantPhace Las reglas establecen que se supone el siglo XX; de lo contrario no habría fecha máxima.
Ypnypn

Respuestas:


6

Pyth, 118 bytes

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

Pruébelo en línea: Demostración o Test Suite .

Conocimiento necesario de los calendarios juliano y gregoriano.

Calendario juliano y gregoriano son bastante similares. Cada calendario divide un año en 12 meses, cada uno con 28-31 días. Los días exactos en un mes son [31, 28/29 (depends on leap year), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]. La única diferencia entre los calendarios es su definición de año bisiesto. En el calendario juliano, cualquier año divisible por 4 es un año bisiesto. El calendario gregoriano es un poco más específico. Cualquier año divisible por 4 es un año bisiesto, excepto el año divisible por 100 y no divisible por 400.

Entonces, en el siglo XX, solo un año es diferente. El año 1900, que es un año bisiesto en el calendario juliano, pero no un año bisiesto en el calendario gregoriano. Entonces, la única fecha que existe en un calendario pero no en el otro calendario es el día 29.02.1900.

Debido a la definición de año bisiesto diferente, hay una diferencia entre una fecha en el calendario juliano y el calendario gregoriano. 12 días de diferencia para una fecha anterior al 29.02.1900, y 13 días de diferencia para fechas posteriores al 29.02.1900.

Pseudocó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

Explicación detallada del código

La primera parte M++28@j15973358 4G&qG2!%H4define una función g(G,H), que calcula el número de días en un mes Gde un año Hen el calendario 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)

Y la siguiente parte es solo el bucle for y los ifs. Tenga en cuenta que interpreto Nen el formato (month, year, day). Solo porque ahorra algunos 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

Pruébalo en línea!

298 bytes cuando se eliminan espacios, líneas nuevas y comentarios.

Las líneas 1-4 inicializan (si no se hace) los hashes %gy %jdonde los valores son los números de los días gregoriano y juliano, contando desde Jaunary 1st 1900 hasta el 31 de diciembre de 1999.

La línea 5 pone la fecha de entrada en $ 1, $ 2 y $ 3.

La línea 9 enumera las seis permutaciones de esos tres números de entrada.

La línea 8 convierte esos seis en dos números cada uno, los números de los días gregoriano y juliano, pero solo aquellos que son fechas válidas.

La línea 7 se asegura de eso, filtra los números de día no existentes.

La línea 6 ordena la lista de números de fecha válidos desde el más pequeño hasta el más grande.

La línea 10 devuelve la diferencia entre el último y el primero (máximo y mínimo), que era el rango deseado.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.