Какая дата это снова?

10

На моем сайте пользователи вводят дату своего рождения в стиле xx.xx.xx- три двузначных числа, разделенных точками. К сожалению, я забыл сказать пользователям, какой именно формат использовать. Все, что я знаю, это то, что один раздел используется для месяца, один для даты и один для года. Год определенно наступил в 20 веке (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, где каждое поле состоит из двух цифр и дополняется нулями.
  • Выход - количество дней в диапазоне.
  • Вы можете предположить, что ввод всегда будет действительной датой.
  • Вы не можете использовать какие-либо встроенные функции даты или календаря.
  • Самый короткий код (в байтах) выигрывает.

Testcases

  • 01.00.31 => 12
  • 29.00.02=> 0(Единственная возможность 29 February 1900 (Julian))
  • 04.30.00 => 13
  • 06.12.15 => 3291
Ypnypn
источник
Это 5, May 1975должно быть 31st? Кроме того, мы должны учитывать високосные годы?
Maltysen
@ Maltysen Да, исправлено. Да.
Ypnypn
Почему этого не может быть в 21 веке?
ElefantPhace
@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))
Jakube
источник
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хэш , где значения являются григорианскими и Julian числа дня соответственно считая от Jaunary первых до 1900 по 31 декабря 1999 года.

В строке 5 вводится дата ввода в $ 1, $ 2 и $ 3.

В строке 9 перечислены все шесть перестановок этих трех входных чисел.

Строка 8 преобразует эти шесть в два числа каждое, номера григорианского и юлианского дней, но только те, которые являются действительными датами.

Строка 7 удостоверяется в этом, она отфильтровывает несуществующие номера дней.

Строка 6 сортирует список допустимых чисел даты от наименьшего к наибольшему.

Строка 10 возвращает разницу между последним и первым (максимум и минимум), который был желаемым диапазоном.

Кжетил С.
источник