Яка дата це знову?


10

На моєму веб-сайті користувачі вводять свою дату народження у стилі xx.xx.xx- три двоцифрових числа, розділених крапками. На жаль, я забув сказати користувачам, який саме формат використовувати. Я знаю лише те, що один розділ використовується на місяць, один на дату та один на рік. Рік, безумовно, XX століття (1900-1999), тому формат 31.05.75означає 31 May 1975. Крім того, я припускаю, що всі використовують або григоріанський, або юліанський календар.

Тепер я хочу пройти свою базу даних, щоб очистити безлад. Я б хотів розпочати, розглядаючи користувачів із самими неоднозначними датами, тобто тими, де діапазон можливих дат найбільший.

Наприклад, дата 08.27.53означає 27 August 1953або григоріанський, або юліанський календар. Дата в юліанському календарі на 13 днів пізніше, тож діапазон просто 13 days.

Навпаки, позначення 01.05.12можуть стосуватися багатьох можливих дат. Найдавніший є 12 May 1901 (Gregorian), а останній - 1 May 1912 (Julian). Асортимент є 4020 days.

Правила

  • Введення - це рядок у форматі xx.xx.xx, де кожне поле - це дві цифри та нульове значення.
  • Вихід - кількість днів у діапазоні.
  • Можна припустити, що вхід завжди буде дійсною датою.
  • Ви не можете використовувати будь-які вбудовані функції дати чи календаря.
  • Найкоротший код (у байтах) виграє.

Тестові шафи

  • 01.00.31 => 12
  • 29.00.02=> 0(Єдина можливість 29 February 1900 (Julian))
  • 04.30.00 => 13
  • 06.12.15 => 3291

Це 5, May 1975має бути 31st? Крім того, чи повинні ми враховувати високосні роки?
Малтісен

@Maltysen Так, виправлено. Так.
Ypnypn

Чому цього не могло бути у 21 столітті?
ElefantFhace

@ElefantPhace Правила стверджують, що 20 століття передбачається; інакше не було б максимальної дати.
Ypnypn

Відповіді:


6

Pyth, 118 байт

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

Спробуйте в Інтернеті: Демонстрація або Тестовий набір .

Необхідні знання Юліанського та Григоріанського календарів

Джуліан та Григоріанський календар досить схожі. Кожен календар ділиться на рік на 12 місяців, кожен містить 28-31 день. Точні дні в місяці - це [31, 28/29 (depends on leap year), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]. Єдина відмінність між календарями - їх визначення високосного року. У Юліанському календарі будь-який рік, розділений на 4, є високосним. Григоріанський календар трохи конкретніший. Будь-який рік, що ділиться на 4, - високосний рік, за винятком року, що ділиться на 100, а не ділиться на 400.

Тож у 20 столітті лише один рік відрізняється. 1900 рік, який є високосним у Юліанському календарі, але не високосним у григоріанському календарі. Отже, єдина дата, яка існує в одному календарі, а не в іншому, - це день 29.02.1900.

Через різні визначення високосного року існує різниця між датою в Юліанському календарі та Григоріанським календарем. 12-денна різниця для дати перед і 29.02.1900, і 13-денна різниця для дати після дати 29.02.1900.

Спрощений псевдокод

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

Детальне пояснення коду

Перша частина M++28@j15973358 4G&qG2!%H4визначає функцію g(G,H), яка обчислює кількість днів у місяці Gроку Hза Юліанським календарем.

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)

А наступна частина - це лише цикл for, і ifs. Зауважте, що я інтерпретую Nу форматі (month, year, day). Просто тому, що це економить кілька байт.

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 байти

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

Спробуйте в Інтернеті!

298 байт при видаленні пробілів, нових рядків та коментарів.

Рядки 1-4 ініціалізують (якщо не зроблено) значення %gта %jхеши, де значеннями є григоріанські та юліанські числа днів, відповідно рахуючи від Jaunary 1-го 1900 року до 31 грудня 1999 року.

У рядку 5 заносяться дати введення в $ 1, $ 2 і $ 3.

У рядку 9 перераховано всі шість перестановок цих трьох вхідних чисел.

Рядок 8 перетворює ці шість на два числа, григоріанські та юліанські дні, але лише ті, які є дійсними датами.

У рядку 7 це впевнене, він фільтрує неіснуючі номери дня.

У рядку 6 сортується список дійсних номерів дати від найменшого до найбільшого.

Рядок 10 повертає тоді різницю між останнім і першим (max і min), яка була шуканою.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.