Co to za data?

10

Na mojej stronie użytkownicy wpisują datę urodzenia zgodnie ze stylem xx.xx.xx- trzy dwucyfrowe liczby oddzielone kropkami. Niestety zapomniałem powiedzieć użytkownikom, jakiego formatu użyć. Wiem tylko, że jedna sekcja jest używana dla miesiąca, jedna dla daty, a druga dla roku. Rok jest zdecydowanie w XX wieku (1900-1999), więc format 31.05.75oznacza 31 May 1975. Zakładam też, że wszyscy używają kalendarza gregoriańskiego lub kalendarza juliańskiego.

Teraz chcę przejrzeć moją bazę danych, aby usunąć bałagan. Chciałbym zacząć od kontaktu z użytkownikami z najbardziej niejednoznacznymi datami, czyli tymi, w których zakres możliwych dat jest największy.

Na przykład data 08.27.53oznacza 27 August 1953w kalendarzu gregoriańskim lub juliańskim. Data w kalendarzu juliańskim to 13 dni później, więc zakres jest sprawiedliwy 13 days.

Natomiast notacja 01.05.12może odnosić się do wielu możliwych dat. Najwcześniejsza jest 12 May 1901 (Gregorian), a najnowsza jest 1 May 1912 (Julian). Zakres wynosi 4020 days.

Zasady

  • Dane wejściowe to ciąg znaków w formacie xx.xx.xx, w którym każde pole składa się z dwóch cyfr i jest uzupełnione zerami.
  • Dane wyjściowe to liczba dni w zakresie.
  • Możesz założyć, że dane wejściowe zawsze będą prawidłową datą.
  • Nie możesz używać żadnych wbudowanych funkcji daty ani kalendarza.
  • Najkrótszy kod (w bajtach) wygrywa.

Przypadki testowe

  • 01.00.31 => 12
  • 29.00.02=> 0(Jedyną możliwością jest 29 February 1900 (Julian))
  • 04.30.00 => 13
  • 06.12.15 => 3291
Ypnypn
źródło
Czy tak 5, May 1975powinno być 31st? Czy też musimy brać pod uwagę lata przestępne?
Maltysen
@Maltysen Tak, naprawiony. Tak.
Ypnypn
Dlaczego nie mogło tak być w XXI wieku?
ElefantPhace
@ElefantPhace Reguły stanowią, że przyjmuje się wiek XX; w przeciwnym razie nie byłoby maksymalnej daty.
Ypnypn

Odpowiedzi:

6

Pyth, 118 bajtów

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

Wypróbuj online: pakiet demonstracyjny lub testowy .

Niezbędna znajomość kalendarzy juliańskich i gregoriańskich

Kalendarz juliański i gregoriański są dość podobne. Każdy kalendarz dzieli rok na 12 miesięcy, z których każdy zawiera 28–31 dni. Dokładne dni w miesiącu to [31, 28/29 (depends on leap year), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]. Jedyną różnicą między kalendarzami jest ich definicja roku przestępnego. W kalendarzu juliańskim każdy rok podzielny przez 4 jest rokiem przestępnym. Kalendarz gregoriański jest nieco bardziej szczegółowy. Każdy rok podzielny przez 4 jest rokiem przestępnym, z wyjątkiem roku podzielnego przez 100 i niepodzielnego przez 400.

Tak więc w XX wieku tylko jeden rok jest inny. Rok 1900, który jest rokiem przestępnym w kalendarzu juliańskim, ale nie rokiem przestępnym w kalendarzu gregoriańskim. Tak więc jedyną datą, która istnieje w jednym kalendarzu, ale nie w drugim, jest dzień 29.02.1900.

Ze względu na inną definicję roku przestępnego istnieje różnica między datą w kalendarzu juliańskim a kalendarzem gregoriańskim. Różnica 12 dni dla daty poprzedzającej 29.02.1900i 13 dni różnica dla dat po 29.02.1900.

Uproszczony pseudo-kod

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

Szczegółowe objaśnienie kodu

Pierwsza część M++28@j15973358 4G&qG2!%H4określa funkcję g(G,H), która oblicza liczbę dni w miesiącu Groku Hw kalendarzu juliańskim.

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)

Następna część to tylko pętla for i ifs. Zauważ, że interpretuję Nw formacie (month, year, day). Tylko dlatego, że oszczędza niektóre bajty.

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))
Jakube
źródło
0

Perl 5 , 294 bajtów

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

Wypróbuj online!

298 bajtów po usunięciu spacji, znaków nowej linii i komentarzy.

Linie 1-4 inicjują (jeśli nie są wykonywane) %gi %jhashe, gdzie wartościami są gregoriańskie i juliańskie liczby dni, odpowiednio licząc od 1 stycznia 1900 r. Do 31 grudnia 1999 r.

W wierszu 5 wstawiana jest data 1, 2 i 3 USD.

W wierszu 9 wymieniono wszystkie sześć kombinacji tych trzech liczb wejściowych.

Wiersz 8 konwertuje te sześć na dwie liczby, gregoriańską i juliańską, ale tylko te, które są ważnymi datami.

Wiersz 7 zapewnia to, odfiltrowuje nieistniejące liczby dni.

Wiersz 6 sortuje listę prawidłowych numerów dat od najmniejszej do największej.

Linia 10 zwraca następnie różnicę między ostatnim a pierwszym (maks. I min.), Który był pożądanym zakresem.

Kjetil S.
źródło