Próximo feriado

18

Os australianos adoram feriados e bebem. Ontem, 26 de janeiro, foi o dia da Austrália, que é feriado. Fiquei feliz por não estar trabalhando ontem e ansioso para saber da próxima vez que eu tiver um feriado! Infelizmente, bebi um pouco demais e não sou capaz de resolver isso sozinho.

Escreva um programa que tenha uma data na notação de data / hora australiana (dd / mm) como entrada e produza a quantidade de dias até o próximo feriado. Como sou residente em Queensland (QLD), só estou interessado em feriados que afetam Queenslanders :

25/03 Sexta-feira Santa
26/03 | Sábado de Páscoa
28/03 | Segunda-feira de Páscoa
25/04 | Dia Anzac
02/05 | Dia do Trabalho
03/10 | Aniversário da rainha
25/12 | Dia de natal
26/12 | Boxing Day
27/12 | Feriado do dia de Natal

Observe o seguinte no site:

Feriado do dia de Natal

Um feriado público adicional a ser adicionado quando o dia de ano novo, o dia de Natal ou o dia de boxe caem em um fim de semana.

Como o dia de Natal é no domingo, há um feriado público extra . O dia de Natal ainda é feriado.

Por ser uma pessoa matutina, você deve incluir a data atual como um dia (já que é a hora mais provável de verificar seu programa para o próximo feriado). Ou seja, se a data de um feriado público for inserida, sua saída deverá ser 0; se um dia antes da entrada de um feriado, sua saída será 1.

Só estou interessado em datas entre agora (27/01) até o final do ano. A data final que você precisará contabilizar é 31/12, onde estará sua produção 1(no dia de Ano Novo).

As brechas padrão são proibidas.

Entrada

  • A entrada sempre terá 5 caracteres: 4 letras, separadas por hífen -ou barra/
  • A entrada será apenas uma data entre 27/01 e 31/12

Resultado

  • O número de dias até o próximo feriado em Queensland na Austrália, incluindo a data de entrada: deve ser um número entre 0e 153(o intervalo mais longo)
  • Sem novas linhas ou erros

Exemplos

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

Espero que isso esteja claro e que nada se perca; no entanto, esta é a minha segunda pergunta, por isso aprecio qualquer feedback e faço o possível para corrigir problemas o mais rápido possível.

Tas
fonte
@insertusernamehere Obrigado pela ótima sugestão! Eu adicionei as datas à pergunta
Tas
@Tem certeza de que essas datas estão corretas? Os exemplos não correspondem à citação e os dois não correspondem ao site.
Adam Martin
@AdamMartin Obrigado por apontar isso. Coloquei incorretamente as datas de dezembro. As do exemplo são apenas quaisquer datas, não específicas para feriados. São apenas exemplos de datas que podem ser inseridas e qual deve ser a saída. Os citados devem (e esperamos) corresponder aos do site.
Tas
Você comemora o aniversário da rainha em outubro em Queensland? Isso é tão estranho, mas parece correto a partir do link.
Level River St
Uau, vocês não têm férias de junho a setembro? Isso é difícil.
Joe Z.

Respostas:

2

Pyth , 98 84 62 67 Bytes

Atualização: salvou 14 bytes reduzindo a lista da contagem de dias para todos os 12 meses para o cálculo do número do dia. Ainda não encontrei uma boa maneira de comprimir a outra lista, ainda tentando!

Atualização2: salvou outros 22 bytes codificando a lista dos números do dia como uma string base256.

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

Experimente online!

O mesmo algoritmo da minha resposta em Python. E não havia como criar o dia do ano, então tive que fazer isso sozinho. Criar essas 2 listas para o cálculo do dia do ano e para os dias de feriados é bastante caro ... vamos dar uma olhada novamente e tentar gerá-las em menos bytes.

Denker
fonte
Ele não parece como entrada separada com um traço, mas por outro lado é grande
Tas
@Tas Obrigado pela dica, substitua completamente essa parte ... Corrigida ao custo de mais 5 bytes. Talvez você deva adicionar alguns hífens aos casos de teste, pois deseja que eles cubram todas as variações de entrada possíveis.
Denker,
5

Visual Basic for Applications, 155 ou 118 bytes

Versão 1 - independente da localidade, 155 bytes

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

Versão 2 - dependente da localidade, 118 bytes

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

A contagem de bytes é para o arquivo .BAS final, incluindo caracteres de avanço de linha. Editado fora do editor VBA padrão (pois impõe espaços adicionais e formas detalhadas de algumas palavras-chave) - mas importa e executa sem problemas em qualquer Aplicativo do Office (para testar o tipo, por exemplo, ? h("10/08")em janela imediata ou no Excel, usar diretamente em uma fórmula de célula).

(EDITADO) Inicialmente, optei por usar DateSerialpara tornar a função segura de localidade (versão 1). Como eu moro no Brasil e, portanto, meu sistema está configurado para usar o formato "dd / mm / aa" para datas (assim como a Austrália), eu poderia escrever uma versão ainda menor usando em seu CDatelugar (versão 2). CDateusa informações de localidade do sistema para converter texto em data. Também assumi nesta versão que o código seria executado apenas em 2016 (se o ano for omitido (-6 bytes) CDateassume o ano atual conforme o relógio do sistema).

O número 42454 na terceira linha é a soma de 42450, que é a representação numérica de 01/01/2016 no VBA e 84, que é o dia do ano para o primeiro feriado. A matriz contém o dia do ano para cada feriado (incluindo 01/01/2017) compensado por -84, pois isso leva alguns dígitos. Usar 16 em vez de 2016 em DateSerialleva mais dois bytes.

Criar uma matriz idêntica nove vezes dentro da iteração é um código "ruim", mas funciona e salva mais 3 bytes (um para o nome da matriz e outro para o sinal de igual fora do loop e mais um para fazer referência à matriz dentro do loop).

Os espaços "ausentes" entre 0 e a palavra-chave a seguir na segunda e quarta linhas não são necessários, pois são reintroduzidos automaticamente pelo VBE quando o módulo é importado. Usado desatualizado, mas com byte-barato If <...> Goto <linenumber>para interromper o loop (ambos If <...> Then Exit Fore If <...> Then Exit Functionusar mais caracteres).

Também aproveitou o fato de que o nome da função no VBA se comporta como uma variável local e seu valor é retornado automaticamente pela função no final da execução.

dnep
fonte
Bem-vindo ao PPCG! Aqui, definimos uma linguagem de programação pelo intérprete, portanto, é perfeitamente aceitável exigir uma determinada localidade.
precisa saber é o seguinte
Obrigado! Editado para adicionar uma versão menor dependente da localidade.
dnep 27/01
4

JavaScript (ES6), 131 128 bytes

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

Explicação

Usa o Dateconstrutor interno JavaScript para converter a sequência de entrada em um número de milissegundos desde a época e depois compara isso com o número de milissegundos para cada feriado.

Isso é feito armazenando os feriados em uma matriz como o número de dias desde a data de referência. Eu escolhi 2016-01-29a data de referência porque o número de milissegundos desde a época pode ser condensado o mais curto nessa data. Qualquer número de milissegundos entre este dia e o próximo funciona porque o resultado é arredondado para baixo e manter o número no meio evita os efeitos do horário de verão (embora o fuso horário do OP não tenha horário de verão). O número deste dia é 1453986000000e arredondá-lo para 1454000000000(adicionando algumas horas) significa que ele pode ser escrito como 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

Teste

Esta solução depende do fuso horário do usuário. Isso funciona no fuso horário do OP (e meu) (GMT +1000). Se você quiser testá-lo em um fuso horário diferente, a adição numberOfHoursDifferentFromGMT1000 * 60 * 60 * 1000ao número da data de referência deve funcionar. (por exemplo, GMT +0430 seria -5.5 * 60 * 60 * 1000 + 1454e9+n*864e5)

user81655
fonte
Isso sempre dá 0 quando a data é separada por um hífen. Eu já pedi ao OP para ajustar suas caixas de teste, uma vez que estão todas com uma barra como separador.
Denker1 /
@ DenkerAffe Oh, eu pensei que ele queria dizer que estávamos livres para escolher um separador. Aliás, tornando-o separador-ambivalente me salvou 3 bytes, então obrigado!
User81655
1
Parece que a regra separated with a hyphen - or slash /é um pouco ambígua. Para mim, isso significa que temos que lidar com ambos, mas posso ver claramente o seu lado. Acho que o OP deve esclarecer isso.
Denker1
3

T-SQL, 210 , 206 , 194 bytes

(Primeiro post aqui, espero que esteja tudo bem, mas por favor seja gentil :)

A entrada entra @i, serve para ambos /e -como separador. Estou na Austrália, então meu formato de data é o mesmo que @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;

Atualizar varchar para charsalvar 3 bytes, além de remover um espaço :)

A atualização 2 declara @ce atribui sem uma seleção

Liesel
fonte
2

T-SQL, 296 bytes

Criado como uma função com valor de tabela

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

Utilizado da seguinte maneira

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)

Uma breve explicação

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
fonte
2

JavaScript (ES6), 134 bytes

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

O user81655 ainda me excedeu em 3 bytes, mas não consigo encontrar outro lugar para extrair nada daqui. Funciona calculando o número de dias passados ​​em vez de usar Data e comparando-o a uma matriz de compensações de feriados.

Mwr247
fonte
2

Python 2, 204 185 165 165 166 bytes

Atualização: reduziu em ~ 20 bytes calculando o dia do ano sozinho. Não há mais necessidade de longas importações :)

Atualização 2: Outros 20 bytes abaixo, percebendo que posso tratar o ano novo como no dia 367 e fazendo outros pequenos ajustes.

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

Experimente online!

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

Funciona armazenando o número do dia do ano dos feriados em uma lista, filtrando os que estão antes da data especificada, pegando o primeiro elemento nessa lista filtrada e subtraindo o dia do ano, que foi calculado a partir da entrada.

Denker
fonte
1

PHP, 116 bytes

Abordagem bastante direta. Ele armazena os dias do ano para os feriados e os exibe desde que estejam no passado. Finalmente, o dia do ano solicitado é subtraído.

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;

Após todos os casos de teste. Executa na linha de comando e aceita a entrada usando um hífen, como:

$ php holidays.php "12-05"
insertusernamehere
fonte
1

ruby 1.9.3, 155 153 bytes

Após o feriado do dia de Natal, precisamos do nosso dia super especial 366! Caso semelhante ao @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

Uso:

$ ruby i_want_to_break_free.rb "03/05"
Tarod
fonte
Não sei muito sobre Ruby, mas acho que você pode economizar 3 bytes removendo os espaços em branco nas linhas 1 e 3. Além disso, você deve especificar qual método de entrada está usando, pois não é tão óbvio no seu código. Você pode salvar alguns bytes definindo uma função, para poder receber a entrada como argumento e usar o valor de retorno como saída.
Denker
@DenkerAffe Muito obrigado! Eu salvei 2 bytes, mas acho que uma função aumentará o número. Atualizei a resposta com um exemplo de uso.
Tarod 28/01
0

05AB1E , 45 bytes

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

Pode não ser mais 2016, mas seja o que for ..;) Ainda assume que o ano é 2016 por ser um ano bissexto com 29fevereiro.

Experimente online ou verifique todos os casos de teste .

Explicação:

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)

Consulte esta dica 05AB1E (seções Como compactar números inteiros grandes? E Como compactar listas de números inteiros? ) Para entender por que •9JRt€ª´Q®Ië•é 10549819042671399072072399; •9JRt€ª´Q®Ië•368вé [85,86,88,116,123,277,360,361,362,367]; e •Σ₁t•é 5354545.

Kevin Cruijssen
fonte