Encontre a Data mais próxima, de acordo com a Data e o Dia da Semana

12

Encontre a Data mais próxima de uma TargetDate para um determinado dia da semana.

Por exemplo, com uma data 20161219e um dia da semana de Friday (6), a resposta é 20161216.

Outro exemplo, dada a data 20161219e o dia da semana de Wednesday (4), a resposta é 20161221.

Um exemplo final, dada a data 20161219e o dia da semana de Monday (2), a resposta é 20161219.

Regras:

  • O formato da data para entrada e saída deve corresponder. Nos exemplos, usei yyyymmdd, mas você pode usar qualquer formato, desde que o ano (pelo menos dois dígitos), o mês e o dia do mês sejam "legíveis por humanos".
  • O dia da semana é inserido como um número inteiro. No meu exemplo, domingo é o primeiro dia da semana, portanto, é o número do dia da semana 1. Você pode ter qualquer numeração do dia da semana, contanto que ela seja diferente do exemplo.
  • Os anos de 1970 a 2030 devem ser acomodados.
  • Ferramentas e bibliotecas comuns para a data do idioma são permitidas, mas o crédito de rua é concedido àqueles que optam por não usá-los.
  • Menor número de bytes ganhos.
Brett VanderVeen
fonte
2
As respostas poderiam levar a data de uma forma diferente, se conveniente? Também os dias da semana também foram inconvenientes para os idiomas que consideram segunda-feira o primeiro dia da semana
Blue
4
Sim, os rígidos requisitos de formato tornam essa tarefa mais sobre análise / conversão / formatação do que sobre a localização real da data. Teria sido melhor para a IMO especificá-lo de acordo com as linhas de " Você pode aceitar a data e o dia da semana em qualquer formato razoável, desde que use o mesmo formato para entrada e saída ". Mas como muitas pessoas já enviaram respostas, acho que deve ser mantido como está agora.
SMLS
@smls Eu concordo. Lição aprendida para a próxima vez.
precisa saber é o seguinte
1
@BrettVanderVeen Eu não acho que seja tarde demais para relaxar os requisitos. Você pode apenas adicionar um comentário a cada uma das respostas (atualmente 8) sobre as especificações atualizadas. Eu já fiz isso de vez em quando.
Adám

Respostas:

1

Perl 6 , 46 bytes

{~first *.day-of-week==$^b,Date.new($^a)-3..*}

Um lambda que aceita dois argumentos: uma sequência de datas no yyyy-mm-ddformato e um número de dia da semana entre 1= Segunda e 7= Domingo.

Explicação:

                           Date.new($^a)       # Construct Date object from first argument.
                                        -3     # Subtract 3 days.
                                          ..*  # Construct a Range from that, to infinity.
  first                   ,                    # Iterate the range, and return first date...
        *.day-of-week==$^b                     # whose weekday number equals the second arg.

Usando o formato de data e dia da semana usado nos exemplos, seriam 88 bytes:

{S:g/\-//with ~first *.day-of-week==($^b-2)%7+1,Date.new(|($^a~~/(....)(..)(..)/))-3..*}
smls
fonte
Para sua informação, facilitei as regras de formato de data e dia da semana. Sinta-se livre para reenviar.
Brett Vanderveen
@BrettVanderVeen: Atualizado.
SMLS
2

Perl 6 , 83 bytes

->$_,\w{~(Date.new(|m/(....)(..)(..)/)-3...*.day-of-week%7+1==w)[*-1]~~{S:g/"-"//}}

Tente

Expandido

->     # pointy block lambda
  $_,
  \w
{
  ~(  # turn into a Str

    Date.new( |m/(....)(..)(..)/ ) - 3 # three days earlier
    ...                                # generate a sequence
    *.day-of-week % 7 + 1 == w         # stop when the right day is found

  )[*-1]  # the last one

  ~~      # apply the following block

  {
    S:g/"-"//  # remove 「-」
  }
}
Brad Gilbert b2gills
fonte
Para sua informação, facilitei as regras de formato de data e dia da semana. Sinta-se livre para reenviar.
Brett Vanderveen
2

JavaScript (ES6), 93 bytes

(s,n,d=new Date(s))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toISOString().slice(0,10)

Usa o %Y-%m-%dformato da data. Se %a %b %d %Yé um formato de data aceitável, então para 82 bytes:

(s,n,d=new Date(s))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toDateString()

Eu poderia salvar mais 2 bytes exigindo domingo = 10 a sábado = 16, mas esse é um mapeamento tolo do dia da semana. Versão anterior 142 141 bytes (graças a @Guedes) que usava o formato de data AAAAMMDD específico, com sua explicação:

(s,n,d=new Date(s.replace(/(?=..(..)?$)/g,'-')))=>d.setDate(d.getDate()+(n+9-d.getDay())%7-3)&&d.toISOString().replace(/-(..)-(..).*/,'$1$2')

Isso parece muito longo. Explicação: Primeiro, insere -s na data para obtê-la no formato ISO, que new Datepode ser analisada. Em seguida, compare o dia desejado com o dia real para obter um valor entre -3e 3para o deslocamento real. A mágica 9vem de 7(porque %é o módulo da CPU, não é o módulo verdadeiro) mais 3(para o -3deslocamento) menos 1(porque né indexado em 1 e indexado em getDay0). A data é convertida novamente no formato ISO e os caracteres indesejados removidos.

Neil
fonte
Você pode salvar um byte alterando o primeiro substituir para.replace(/(?=..(..)?$)/g,'-')
Washington Guedes
Para sua informação, facilitei as regras de formato de data e dia da semana. Sinta-se livre para reenviar.
Brett Vanderveen
1

Python, 150 149 bytes

from datetime import*
lambda s,n,t='%Y%m%d':[d for d in[datetime.strptime(s,t)+timedelta(o-3)for o in range(7)]if(n-2)%7==d.weekday()][0].strftime(t)

Oouuf, 149. repl.it

Função sem nome que aceita uma string s, a data especificada (usando a string de formato t='%Y%m%d'para entrada e saída) e um número em [1,7] n,.
Inspeciona os sete dias, de três dias antes a três dias após o dado para o dia da semana solicitado.
A semana datetimecomeça na segunda-feira e é zero, portanto o teste é (n-2)%7==d.weekday().

Jonathan Allan
fonte
Para sua informação, facilitei as regras de formato de data e dia da semana. Sinta-se livre para reenviar.
Brett Vanderveen
1

Bash + coreutils, 50

date -d$1+$[($2-`date -d$1 +%u`+9)%7-3]day +%Y%m%d

Experimente online .

  • date -d$1 +%udá o dia da semana (1..7); 1 é segunda-feira
  • Isso é subtraído do dia da semana de entrada para fornecer uma diferença nos índices de dias. Queremos adicionar um fator no intervalo [-3, 3] à data de entrada para obter a data mais próxima; portanto, adicionamos um fator mágico 9, pegamos o módulo 7 e subtraímos 3. O fator mágico 9 é 3 + 7 - 1. O 3 ajusta a faixa de entrada para a faixa [-3, 3] e é subtraído novamente após o módulo. O 7 é necessário porque o módulo bash é o mesmo que o módulo da CPU e pode fornecer resultados positivos - adicionando 7 ajustes na faixa correta. O -1 é porque na entrada, 1 é domingo, mas com a saída% u, 1 é segunda-feira.
  • O exterior dateanalisa <input date> + <magic factor>dayse apresenta no formato AAAAMMDD.
Trauma Digital
fonte
Para sua informação, facilitei as regras de formato de data e dia da semana. Sinta-se livre para reenviar.
Brett Vanderveen
1

Linguagem de macro SAS, 110 bytes

%macro s(d,a);%put %sysfunc(putn(%sysfunc(intnx(week.&a.,%eval(%sysfunc(putn(&d,8.))-4),1)),yymmddn8.));%mend;

Uma linguagem de golfe terrível, mas aqui está a explicação (de dentro para fora):

Crie uma macro sque aceite uma entrada de data de um dia da semana numérico a. Em seguida, %eval(%sysfunc(putn(&d,8.))-4)converte a data em uma data numérica do SAS e a diminui em 4 dias. A intnxfunção retorna a próxima ocorrência do dia da semana especificado. putndepois formata a data de volta para aaaammdd e %putimprime a saída no log.

J_Lard
fonte
Para sua informação, facilitei as regras de formato de data e dia da semana. Sinta-se livre para reenviar.
Brett Vanderveen
1

Mathematica, 85 49 bytes

#~DatePlus~Mod[#2-#~DateValue~"ISOWeekDay",7,-3]&

O formato de entrada para datas é uma lista como {2016, 12, 16}uma real DateObject(acho que algumas outras funcionam também, mas as testei). Nos dois casos, o formato de saída corresponderá automaticamente. A numeração do dia começa 1às segundas-feiras.

A idéia é calcular a diferença entre o dia da semana de entrada e o dia da semana de destino com #2-#~DateValue~"ISOWeekDay"e depois mapeá-lo [-3, 3]usando um módulo com deslocamento (ou seja Mod[...,7,-3]). O resultado é simplesmente adicionado à data de entrada (a unidade padrão para a adição de objetos de data é dias).

Martin Ender
fonte
Para sua informação, facilitei as regras de formato de data e dia da semana. Sinta-se livre para reenviar.
Brett Vanderveen
@BrettVanderVeen thanks, edited.
Martin Ender
1

R, 119 77 56 bytes

Função sem nome que recebe duas entradas, a data D(string) e o dia d(numérico).

function(D,d,s=-3:3+as.Date(D))s[lubridate::wday(s)==d]

Usa a função wday()do lubridatepacote. Ele pode convenientemente converter Dateobjetos em dias da semana, 1sendo tratado como domingo por padrão.

Edit: I / O agora é o padrão da as.Date()função:"YYYY-mm-dd"

Ungolfed e Explained

function(D,d){
    D=as.Date(D);            # Format input date
    s=-3:3+D;                # Generate sequence of +- 3 days
    s[lubridate::wday(s)==d] # Match the weekday that equals to target day                                    
}

Editar: Agora cria uma sequência de +-3dias para a qual qualquer dia da semana é garantido. Subseqüentemente, precisamos apenas corresponder um dia que facilitou o problema.

Billywob
fonte
Para sua informação, facilitei as regras de formato de data e dia da semana. Sinta-se livre para reenviar.
Brett Vanderveen
@BrettVanderVeen Obrigado, atualizado.
Billywob