Следующий государственный праздник

18

Австралийцы любят праздничные дни и пьют. Вчера, 26 января, был день Австралии, который является выходным днем. Я был рад, что вчера не был на работе, и хотел знать, когда в следующий раз у меня будет выходной день! К сожалению, я выпил слишком много, и я не могу решить это для себя.

Напишите программу, которая будет принимать дату в австралийской записи даты / времени (дд / мм) в качестве входных данных и выводить количество дней до следующего государственного праздника. Поскольку я являюсь резидентом Квинсленда (Квинсленд), меня интересуют только праздничные дни, которые затрагивают жителей Квинсленда :

25/03 | Страстная пятница
26/03 | Пасхальная суббота
28/03 | Пасхальный понедельник
25/04 | День Анзака
02/05 | День труда
03/10 | День рождения королевы
25/12 | Рождество
26/12 | День подарков
27/12 | Праздник Рождества

Обратите внимание на следующее с сайта:

Праздник Рождества

Дополнительный праздничный день, который будет добавлен, когда Новый год, Рождество или День подарков выпадают на выходные.

Поскольку Рождество в воскресенье, есть дополнительная выходной день. Рождество все еще является государственным праздником.

Поскольку я человек утренний, вы должны указать текущую дату как день (так как это наиболее вероятное время, когда я проверю вашу программу на следующий государственный праздник). То есть, если введена дата выходного дня, ваш вывод должен быть 0; если за день до праздничного дня, ваш вывод будет1 .

Я больше заинтересован только в датах между предприятием (с 27/01) до конца года. Конечная дата, которую вам нужно будет учесть, - 31/12, где будут ваши выходные данные 1(на Новый год).

Стандартные лазейки запрещены.

вход

  • Ввод всегда будет 5 символов: 4 буквы, разделенные дефисом -или косой чертой/
  • Ввод будет только дата между 27/01 и 31/12

Выход

  • Количество дней до следующего государственного праздника в Квинсленде, Австралия, включая дату ввода: должно быть числом между 0и153 (самый большой разрыв)
  • Нет новых строк или ошибок

Примеры

01-05 = 1  
02-05 = 0  
03-05 = 153  
25/12 = 0
26-12 = 0
27/12 = 0
30/12 = 2
31-12 = 1

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

Tas
источник
@insertusernamehere Спасибо за отличное предложение! Я добавил даты в вопрос
Tas
@ Ты уверен, что эти даты верны? Те, что в примерах, не соответствуют цитате, и оба они не соответствуют веб-сайту.
Адам Мартин
@AdamMartin Спасибо за указание на это. Я неправильно поставил декабрьские даты. В этом примере указаны просто даты, не относящиеся к праздничным дням. Это всего лишь примеры дат, которые могут быть введены, и каковы должны быть выходные данные. Приведенные цитаты должны (и, надеюсь, соответствуют) соответствовать тем, которые есть на сайте.
Tas
Вы отмечаете день рождения королевы в октябре в Квинсленде? Это так странно, но кажется правильным по ссылке.
Уровень Река Сент
Ух, у вас, ребята, нет выходных с июня по сентябрь? Это грубо.
Джо З.

Ответы:

2

Pyth , 98 84 62 67 байт

Обновление: сохранено 14 байт за счет сокращения списка количества дней для всех 12 месяцев для расчета номера дня. Не нашел хорошего способа сжать другой список, но все еще пытаюсь!

Обновление 2: еще 22 байта сохранены путем конечного кодирования списка номеров дней в виде строки base256.

J30KhJ=Yc:z"\W"dd=N+s<[KtJKJKJKKJKJK)tseYshY-hfgTNCMc"UVXt{ĕŨũŪů"1N

Попробуйте онлайн!

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

Denker
источник
Кажется, ему не нравится ввод, разделенный дефисом, но в остальном это здорово
Tas
@Tas Спасибо за подсказку, полностью перечитал эту часть ... Исправлена ​​стоимость 5 дополнительных байтов. Возможно, вам следует добавить несколько дефисов в тестовые наборы, так как вы хотите, чтобы они охватывали все возможные варианты ввода.
Денкер
5

Visual Basic для приложений, 155 или 118 байт

Версия 1 - не зависит от локали, 155 байт

Function h(d)
For i=0To 9
h=Array(0,1,3,31,38,192,275,276,277,282)(i)+42454-DateSerial(16,Val(Right(d,2)),Val(Left(d,2)))
If h>=0Goto 9
Next
9 End Function

Версия 2 - зависит от локали, 118 байт

Function h(d)
For i=0To 9
h=Array(0,1,3,31,38,192,275,276,277,282)(i)+42454-CDate(d)
If h>=0Goto 9
Next
9 End Function

Количество байт для окончательного файла .BAS, включая символы перевода строки. Редактируется вне стандартного редактора VBA (поскольку он налагает дополнительные пробелы и подробные формы некоторых ключевых слов) - но импортирует и работает без проблем в любом приложении Office (для проверки типа, например, ? h("10/08")в непосредственном окне или в Excel, используется непосредственно в формуле ячейки).

(ИЗМЕНЕНО) Первоначально я решил использовать DateSerialэту функцию, чтобы сделать функцию безопасной на региональном уровне (версия 1). Поскольку я живу в Бразилии, и, таким образом, моя система настроена на использование формата «дд / мм / гг» для дат (как в Австралии), я мог бы CDateвместо этого написать еще меньшую версию (версия 2). CDateиспользует информацию о локали системы для преобразования текста в дату. В этой версии я также предполагал, что код будет выполняться только в течение 2016 года (если пропустить год (-6 байт), то CDateтекущий год соответствует системным часам).

Число 42454 в третьей строке представляет собой сумму 42450, которая является числовым представлением 01.01.2016 на VBA, и 84, которая является днем ​​года для первого праздника. Массив содержит день года для каждого выходного дня (включая 01.01.2017), смещенный на -84, так как это отнимает несколько цифр. Использование 16 вместо 2016 DateSerialприводит к удалению еще двух байтов.

Создание идентичного массива девять раз внутри итерации - «плохой» код, но он работает и сохраняет еще 3 байта (один для имени массива и один для знака равенства вне цикла, и еще один для ссылки на массив внутри цикла).

«Пропущенные» пробелы между 0 и последующим ключевым словом во второй и четвертой строках не нужны, поскольку они автоматически вводятся VBE при импорте модуля. Используется устаревшим, но байтово-дешевым, If <...> Goto <linenumber>чтобы вырваться из цикла (оба If <...> Then Exit Forи If <...> Then Exit Functionиспользовать больше символов).

Также использовался тот факт, что имя функции в VBA ведет себя как локальная переменная, и ее значение автоматически возвращается функцией в конце выполнения.

dnep
источник
Добро пожаловать в PPCG! Здесь мы определяем язык программирования интерпретатором, поэтому вполне допустимо требовать определенной локали.
lirtosiast
Благодарность! Отредактировано, чтобы добавить меньшую версию, зависящую от локали.
dnep
4

JavaScript (ES6), 131 128 байт

d=>[56,57,59,87,94,248,331,332,333,338].map(n=>r=r||(q=1454e9+n*864e5-new Date(d[3]+d[4]+`/${d[0]+d[1]}/16`))>=0&&q/864e5,r=0)|r

объяснение

Использует встроенный Dateконструктор JavaScript для преобразования входной строки в количество миллисекунд с начала эпохи, а затем сравнивает это число с количеством миллисекунд для каждого выходного дня.

Это достигается путем сохранения выходных дней в массиве в виде количества дней с даты ссылки. Я выбрал 2016-01-29контрольную дату, потому что количество миллисекунд с начала эпохи может быть сокращено до кратчайшего для этой даты. Любое количество миллисекунд между этим днем ​​и следующими работами, потому что результат округляется в меньшую сторону, а сохранение среднего значения позволяет избежать эффекта перехода на летнее время (хотя часовой пояс OP не имеет перехода на летнее время). Число этого дня 1453986000000и округление его до 1454000000000(добавив пару часов) означает, что оно может быть записано как 1454e9.

d=>
  [56,57,59,87,94,248,331,332,333,338]             // list of day offsets from 01/29
  .map(n=>                                         // for each public holiday offset n
    r=r||                                          // if r is already set, do nothing
      (q=                                          // q = approximate difference in ms
        1454e9+n*864e5                             // time of public holiday
        -new Date(d[3]+d[4]+`/${d[0]+d[1]}/16`)    // time of input date
      )
      >=0&&                                        // if q >= 0
        q/864e5,                                   // r = q in days
    r=0                                            // r = result
  )
  |r                                               // floor and return r

Тестовое задание

Это решение зависит от часового пояса пользователя. Это работает в часовом поясе ОП (и моего) (GMT +1000). Если вы хотите проверить его в другом часовом поясе, добавивnumberOfHoursDifferentFromGMT1000 * 60 * 60 * 1000 к номеру контрольной даты должно работать. (например, GMT +0430 будет -5.5 * 60 * 60 * 1000 + 1454e9+n*864e5)

user81655
источник
Это всегда дает 0, когда дата отделяется дефисом. Я уже попросил ОП отрегулировать его тестовые случаи, так как все они с косой чертой в качестве разделителя.
Денкер
@DenkerAffe О, я думал, он имел в виду, что мы можем выбрать разделитель. Между прочим, создание разделителя-амбивалента сэкономило мне 3 байта, так что спасибо!
user81655
1
Похоже, правило separated with a hyphen - or slash /немного амбициозно. Для меня это означает, что мы должны иметь дело с обоими, но я определенно вижу вашу сторону. Угадай, ОП должен уточнить это.
Денкер
3

T-SQL, 210 , 206 , 194 байта

(Первый пост здесь, надеюсь, это нормально, но, пожалуйста, будьте добры :)

Ввод идет @i, обслуживает как /и -как разделитель. Я в Австралии, поэтому мой формат даты такой же, как у @Tas

DECLARE @i CHAR(5)='23-09';DECLARE @c INT=DATEPART(dy,CAST(REPLACE(@i,'-','/')+'/2016' AS DATE))-1;SELECT MIN(b)-@c FROM(VALUES(84),(85),(87),(115),(122),(276),(359),(360),(361))a(b)WHERE b>=@c;

Обновление varchar до charсохраняет 3 байт плюс удалил пробел :)

Обновление 2 объявлять @cи назначать без выбора

Лизель
источник
2

T-SQL, 296 байт

Создан как табличная функция

create function d(@ char(5))returns table return select min(o)o from(select datediff(day,cast('2016'+right(@,2)+left(@,2)as date),cast(right('2016'+right('0'+cast(d as varchar(4)),4),8)as datetime)+1)o from(values(324),(325),(327),(424),(501),(1002),(1224),(1225),(1226),(1231))d(d))d where 0<=o

Используется следующим образом

SELECT *
FROM (
    VALUES
        ('01/05') --= 1  
        ,('02/05') --= 0  
        ,('03/05') --= 153  
        ,('25/12') --= 0
        ,('26/12') --= 0
        ,('27/12') --= 0
        ,('30/12') --= 2
        ,('31/12') --= 1
    )testData(i)
    CROSS APPLY (
        SELECT * FROM d(t)
    ) out

i     o
----- -----------
01/05 1
02/05 0
03/05 153
25/12 0
26/12 0
27/12 0
30/12 2
31/12 1

(8 row(s) affected)

Краткое объяснение

create function d(@ char(5)) returns table  -- function definition
return 
select min(o)o -- minimum set value
from(
    select datediff( -- date difference
        day, -- day units
        cast('2016'+right(@,2)+left(@,2)as date), -- convert input parameter to date
        cast(right('2016'+right('0'+cast(d as varchar(4)),4),8)as datetime)+1 -- convert int values into datetimes and add a day
        )o 
    from(
        values(324),(325),(327),(424),(501),(1002),(1224),(1225),(1226),(1231) -- integers representing the day before public holidays
        )d(d)
    )d 
where 0<=o -- only for values >= 0
MickyT
источник
2

JavaScript (ES6), 134 байта

x=>[0,1,3,31,38,192,275,276,277,282].find(z=>z>=(q=x[0]+x[1]- -[...'20212122121'].slice(0,x[3]+x[4]-1).reduce((a,b)=>+b+a+29,0)-85))-q

user81655 по-прежнему заставляет меня биться на 3 байта, но я не могу найти где-нибудь еще, чтобы выжать что-то отсюда Работает, вычисляя количество прошедших дней вместо использования даты, затем сравнивая его с массивом смещений праздничных дней.

Mwr247
источник
2

Python 2, 204 185 165 166 байт

Обновление: уменьшил его на ~ 20 байт, рассчитав день года самостоятельно. Больше нет необходимости в долгом импорте :)

Обновление 2: еще 20 байтов, потому что я понимаю, что могу относиться к новым годам так же, как день 367, и внося некоторые другие небольшие изменения.

def f(d):d=[d[:2],d[3:]];y=sum([31,29,31,30,31,30,31,31,30,31,30,31][:int(d[1])-1])+int(d[0]);return filter(lambda n:n>=y,[85,86,88,116,123,277,360,361,362,367])[0]-y

Попробуйте онлайн!

Ungolfed:

def f(d):
    l=[85,86,88,116,123,277,360,361,362,367]
    d=[d[:2],d[3:]]
    y=sum([31,29,31,30,31,30,31,31,30,31,30,31][:int(d[1])-1])+int(d[0])
    f=filter(lambda n:n>=y,l)
    return f[0]-y

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

Denker
источник
1

PHP, 116 байт

Довольно прямой подход. Он хранит дни года для праздников и выводит их, пока они в прошлом. Наконец запрашиваемый день года вычитается.

for($x=[366,361,360,359,276,122,115,87,85,84];($a=date(z,strtotime($argv[1].'-2016')))>$t=array_pop($x););echo$t-$a;

Прошёл все тесты. Запускается из командной строки и принимает ввод с использованием дефиса, например:

$ php holidays.php "12-05"
insertusernamehere
источник
1

рубин 1.9.3, 155 153 байта

После праздника Рождества нам нужен наш супер-специальный день 366! Аналогичный случай, как @DenkerAffe.

require'date'
c=(Date.strptime(ARGV[0],'%d/%m')-Date.parse('01/01')).to_i
print [84,85,87,115,122,276,359,360,361,366].map{|i|(i-c)}.select{|i|i>=0}.min

Использование:

$ ruby i_want_to_break_free.rb "03/05"
Tarod
источник
Я не знаю много о Ruby, но я думаю, что вы можете сэкономить 3 байта, удалив пробелы в строках 1 и 3. Также вы должны указать, какой метод ввода вы используете, так как это не так очевидно в вашем коде. Вы можете сохранить несколько байтов, определив функцию, так что вы можете принять входные данные в качестве аргумента и использовать возвращаемое значение в качестве выходного.
Денкер
@DenkerAffe Большое спасибо! Я сохранил 2 байта, но я думаю, что функция увеличит число. Я обновил ответ с примером использования.
Тарод
0

05AB1E , 45 байт

•9JRt€ª´Q®Ië•368вDI„-/S¡`•Σ₁t•ºS₂+s<£O+©@Ïн®-

Это может быть уже не 2016, но что бы то ни было ..;) Тем не менее, предполагается, что это 2016 год ради високосного года с 29февраля.

Попробуйте онлайн или проверьте все контрольные примеры .

Объяснение:

9JRt€ª´Q®Ië•  # Push compressed integer 10549819042671399072072399
  368в         # Converted to base-368 as list: [85,86,88,116,123,277,360,361,362,367]
      D        # Duplicate this list
I              # Take the input
 „-/S¡         # Split it on ["-","/"]
      `        # Push both integer separated to the stack
•Σ₁t          # Push compressed integer 5354545
     º         # Mirror it without overlap: 53545455454535
      S        # Converted to a list of digits: [5,3,5,4,5,4,5,5,4,5,4,5,3,5]
       ₂+      # Add 26 to each: [31,29,31,30,31,30,31,31,30,31,30,31,29,31]
         s     # Swap to get the month-integer
          <    # Decrease it by 1
           £   # Only leave the first month-1 values from the integer-list
            O  # Sum that sublist
             + # And add it to the day-integer (so we now have the N'th day of the year)
©              # Save this in the register (without popping)
 @             # Do a >= check with each integer in the first (duplicated) list we created
  Ï            # Only leave the truthy values from the list
   н           # Then pop this sublist and only leave its first value
    ®-         # And subtract the integer we saved in the register (N'th day of the year)
               # (after which the result is output implicitly)

Смотрите этот 05AB1E наконечника шахты (разделы Как сжать большие целые числа? И Как сжать целые списки? ) , Чтобы понять , почему •9JRt€ª´Q®Ië•это 10549819042671399072072399; •9JRt€ª´Q®Ië•368весть [85,86,88,116,123,277,360,361,362,367]; и •Σ₁t•есть 5354545.

Кевин Круйссен
источник