Quando foi a última vez que a data foi divisível por n?


24

Uma data pode ser representada por um número inteiro não assinado como tal: AAAAMMDD. O que você precisa fazer é escrever o programa ou a função mais curta que identifique a data mais recente cujo número foi divisível por um determinado número n(incluindo a data de hoje) e, em seguida, retorna essa data no formato mostrado acima. Se nunca houve uma data (entre 00000101 e hoje inclusive) divisível pelo número inteiro especificado, você deve retornar -1.

Exemplos

Current Date     Input     Output

30 July, 2014      4       20140728
30 July, 2014      7       20140729
28 July, 2014      4       20140728
28 July, 2014      7       20140722
28 July,    5    90000     -1

Entrada

Você pode ler do STDIN ou usar um argumento de função ou até esperar que a entrada seja armazenada em uma variável. A entrada será um número inteiro não assinado.

Saída

Escreva para STDOUT ou retorne (ou salve em uma variável) o número inteiro que representa a data no formato AAAAMMDD.

Restrições

Você pode usar qualquer biblioteca padrão oferecida por seu idioma. Aplicam-se brechas padrão .

Condições vencedoras

Este é um , pelo que o menor programa (em bytes) vence. Em caso de empate, a resposta com mais votos vence.


4
A data 00000101 não existe. A contagem do ano começa em 1. en.wikipedia.org/wiki/0_%28year%29
edc65

11
@ edc65 podemos fingir que existe?
overactor

3
E o dia 29 de fevereiro? Precisamos aplicar regras de ano bissexto completo para verificar datas válidas? en.wikipedia.org/wiki/Leap_year
Digital Trauma

6
E os dias perdidos devido à mudança de calendário juliano-gregoriano? Ou vamos Gregoriano até o fim? en.wikipedia.org/wiki/Gregorian_calendar
Digital Trauma

11
Suas especificações de entrada / saída são bastante soltas. Por exemplo, o "espera que a entrada seja armazenada em uma variável" deve contar a declaração da variável em um idioma como C? Você diz "escreve um programa", mas diz "aceita um argumento de função" - isso significa que podemos escrever apenas uma função em vez de um programa completo?
30414 Bob

Respostas:


16

Mathematica, 93 60 bytes

For[i=0,(r=DatePlus@i--~FromDigits~100)>0&&!n∣r,];r~Max~-1

Espera que a entrada seja armazenada n.

Observe que a linha vertical é o caractere unicode para "divide", que contei como 3 bytes (UTF-8).

Edit: Encontrou um truque para evitar as DateStringespecificações inchadas e de formato :).

Edit: esqueci totalmente do -1requisito. Corrigido agora.

Aqui está uma explicação

For[i=0,            i--                        ,];         (* i is the number of days AFTER
                                                              today. Hence, we decrement 
                                                              it. *)
For[i=0,   DatePlus@i--                        ,];         (* If no reference date is
                                                              provided, DatePlus will add
                                                              the given number of days to
                                                              today's date. The result is a 
                                                              list of 3 integers, luckily 
                                                              in order {year,month,day} *)
For[i=0,   DatePlus@i--~FromDigits~100         ,];         (* Interpret these as the digits
                                                              of a base 100 number. The 
                                                              beauty is that FromDigits
                                                              doesn't care about digits 
                                                              greater than the base and 
                                                              just carries them over. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)        ,];         (* Store the number in r. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)>0      ,];         (* Make sure it's positive. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)>0&&!n|r,];         (* And keep going while n does 
                                                              not divide r. *)
For[i=0,(r=DatePlus@i--~FromDigits~100)>0&&!n|r,];r~Max~-1 (* Clamp result to -1. *)

Observe que eu usei, em |vez de na explicação, porque o Unicode mexe com monoespaçamento.


+ 1.Você tem um link indicando que deve contar caracteres unicode como 3 bytes?
22314 Dr. Belisarius

2
@belisarius O OP declarou que este código golf é contado por bytes e não por caracteres (este também é o padrão, conforme indicado na tag wiki).
Martin Ender

Eu nunca consegui ler até o final do wiki :) Obrigado!
22814 Dr. Belisarius

6

Python 2-150

import datetime as d,re
def f(n):
 t=d.date.today()
 while t:
    c=int(re.sub("-","",str(t)))
    if c%n<1:return c
    try:t-=d.timedelta(1)
    except:return-1

Obrigado @ chill0r pela sugestão de remover days = e Jason S pela dica de que o bloco try pode ser reduzido para uma linha.


Sim. Esse é um procedimento operacional padrão;). As guias são convertidas em espaços após colar.
Vetorizado

Você pode remover o days=no t-=d.timedelta(days=1). Isso funciona bem também (pelo menos em python3)
chill0r

@bitpwner ah eu vejo, não importa então.
Martin Ender

11
Você pode economizar mais: (1) use int(t.strftime("%Y%m%d"))e solte re, (2) use uma linha tryporque só t-=d.timedelta(1)precisa estar nela.
Jason S

11
O @bitpwner strftimeem datas mais antigas funciona em python3, verificado e eu recebo um erro em python2 #
Jason S

5

C # 136

Com as especificações revisadas, uma função que pega um int não assinado e retorna um int.

int F(uint n){var d=System.DateTime.Now;int i;try{while((i=int.Parse(d.ToString("yyyMMdd")))%n>0)d=d.AddDays(-1);}catch{i=-1;}return i;}

152 caracteres com entrada / saída variável

Aproveitando os requisitos fracos de entrada / saída, a entrada deve ser armazenada na variável n(atualmente contando todos os caracteres, exceto o literal inteiro), e a saída é fornecida com a variável s.

class P{static void Main(){var n=4;var d=System.DateTime.Now;string s;try{while(int.Parse(s=d.ToString("yyyMMdd"))%n>0)d=d.AddDays(-1);}catch{s="-1";}}}

204 caracteres com STDIN / STDOUT:

using System;class P{static void Main(){int n=int.Parse(Console.ReadLine());var d=DateTime.Now;string s;try{while(int.Parse(s=d.ToString("yyyMMdd"))%n>0)d=d.AddDays(-1);}catch{s="-1";}Console.Write(s);}}

11
Realmente, um voto negativo? Isso não resolve o problema corretamente? Por favor explique. Se alguém pensa que eu dupliquei a outra resposta em C #, na verdade escrevi isso cerca de uma hora antes da outra e até tentei usar o C # 6.0 para as expressões de declaração. Fui um pouco desviado, o que resultou em postar a resposta tarde. Mesmo assim, essa é uma razão bastante frágil para um voto negativo.
30414 Bob

4

T-SQL (2012) - 148

Supõe que há uma variável livre @n com o valor n.

declare @ date=getdate()while convert(char,@,112)%@n>0 and'00010101'<@ set @=dateadd(d,-1,@)print iif(convert(char,@,112)%@n=0,convert(char,@),'-1')

4

Golflua 90 86

n=I.r()d="%Y%m%d"i=O.d(d)+0j=0@i>0?i%n==0w(i)O.q()$j=j+1i=O.d(d,O.t()-j*86400)+0$w(-1)

Uma versão não-gasta de Lua seria,

n = io.read()
d = "%Y%m%d"
i = os.date(d)+0   -- implicitly casts os.date(d) to int
j = 0
while i>0 do
   if i % n == 0 then
      print(i)
      os.exit()
   end
   j = j+1
   i = os.date(d,os.time()-j*86400)+0
end
print(-1)

2
Testado aqui n = 20140699 saídas 20140699
William Barbosa

@WilliamBarbosa: Fixo; 20140699 retorna -1.
Kyle Kanos

4

MATLAB: 61

-1,s=str2num(datestr(1:now,'YYYYmmDD')),d=s(~mod(s,n)),d(end)

Assume que o divisor está armazenado n. O resultado será armazenado em uma variável chamada ans.


Versão comentada:

-1                                     % Store -1 in ans in case we don't find anything
s=str2num(datestr(1:now,'YYYYmmDD'))   % Make a list of date numbers
d=s(~mod(s,n)),                        % Select only those who are dividable and prepend -1
d(end)                                 % Store last found value in ans, if anything is found

Irá gerar um erro se nenhum resultado for encontrado, mas a resposta ainda está disponível na variável, apesar disso.


O erro pode ser evitado ao custo de 2 caracteres extras:

s=str2num(datestr(1:now,'YYYYmmDD')),d=[-1;s(~mod(s,n))],d(end)

@ MartinBüttner Hmm, resolveu esse problema, mas agora a solução está vinculada apenas a caracteres mínimos. Você consegue ver alguma melhoria?
Dennis Jaheruddin

11
Não, não do alto da minha cabeça. Mas minha motivação para ajudá-lo a me vencer é um pouco limitada. ;)
Martin Ender

4

PHP (92 = 85 + 7)

Espera que a entrada seja armazenada $n.

for($d=date("Ymd");!($d%$n==0&checkdate($d/100%100,$d%100,substr($d,0,4))|$d<0);$d--);echo$d

Acabei de me lembrar por que não gosto mais de PHP =)

EDIT: Agora o -1 das especificações também está implementado.


Não, apenas verifique, $ d será muito baixo ao ecoar. O que você quer dizer com 'você forja'? (Desculpe, não inglês nativo =)
flawr

Ah, eu não vi essa especificação, é claro que isso deve ser adicionado, obrigado!
flawr

3

JavaScript (ES6) 115

Espera o número na variável n, resultado armazenado na variável r. Cada dia é verificado, começando com a data atual e diminuindo - deve haver uma maneira melhor.
Além disso, usando as funções de data javascript padrão, todas as datas são gregorianas até o ano 1 (com anos bissextos incorretos antes da reforma gregoriana).

for(z=new Date,t=n+1;t>n&&t%n;)
  d=z.getDate(),
  t=z.getFullYear()*1e4+(z.getMonth()+1)*100+d,
  z.setDate(d-1);
r=t>n?t:-1

3

C # - 144 (ou 124 no LINQPad) + 1 para cada dígito em n

Esta espera a entrada estar na variável n. Ao final da execução, o valor desejado estará na variável r. Isso considera 00010101a primeira data, no entanto, porque a data 00000101não existe. Sugestões para melhoria são sempre bem-vindas.

class P{static void Main(){int n=7,r;var d=System.DateTime.Now;try{for(;(r=int.Parse(d.ToString("yyyMMdd")))%n>0;d=d.AddDays(-1));}catch{r=-1;}}}

Versão do LINQPad:

int n=7,r;var d=System.DateTime.Now;try{for(;(r=int.Parse(d.ToString("yyyMMdd")))%n>0;d=d.AddDays(-1));}catch{r=-1;}r.Dump();

3

Groovy - 301 300 caracteres

Muito simples (e lento), sem truques para esconder o fato de que ele usa o Joda Time.

Golfe:

@Grab(group='joda-time', module='joda-time', version='2.3')
import org.joda.time.*
import org.joda.time.format.*
f={DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(it)) as int}
n=args[0] as int;b=0;x=-1;c=0
while(!b){if(f(c++)%n==0){x=f(--c);b=1};if(f(0)-c<=101){b=1}}
println x

Exemplo de execução (em 30/07/2014):

$ groovy D.groovy  7
20140729
$ groovy D.groovy  16
20140720
$ groovy D.groovy  90000
-1

Ungolfed:

@Grab(group='joda-time', module='joda-time', version='2.3')

import org.joda.time.*
import org.joda.time.format.*

f = { DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(it)) as int }

n = args[0] as int
b = 0 
x = -1
c = 0

while (!b) {
    if(f(c++)%n==0) { x=f(--c); b=1}
    if(f(0)-c<=101){b=1}
}

println x

3

R, 146 139

D=function(n){
z=as.double(gsub("-","",y<-Sys.Date()))
d=F
while(z>100&!d){
y=y-1 
z=as.double(gsub("-","",y))
d=!z%%n}
ifelse(z>100,z,-1)}

Boa sorte com uma data que não funciona. microbenchmarkrelatórios leva cerca de meio segundo para voltar 15 dias. Em 31 de julho de 2014, isso levaria cerca de 20 milhões de segundos (~ 23 dias) para cuspir -1, pelo menos de acordo com a parte de trás do envelope.

edit : alguns atalhos nos comentários


!dé menor que d==Fe !z%%nque z%%n==0. Além disso, transformar as.numeric(gsub("-","",...)uma função também deve reduzir a contagem de caracteres. Ainda bem, bom trabalho!
plannapus

Ah, e as.realmuitas vezes é uma alternativa boa e mais curta as.numeric.
plannapus

Infelizmente, as.realestá extinto a partir do R 3.0.0. Mas ainda temos as.doublequal é um personagem mais curto.
31814 Shadowtalker

Ah, eu não sabia disso, pois ainda estou usando o R 2.14 #
plannapus

11
Não estou trabalhando em um computador no qual tenho direitos administrativos, portanto não depende de mim. Mas eu já tenho paste0no meu .Rprofilenaturalmente :) #
plannapus

3

Matlab 104

function d=f(v);for d=fix(now):-1:1 d=str2num(datestr(d,'YYYYmmDD'));if~mod(d,v)return;end;end;d=-1;end

Ungolfed:

function d = f(v)
   for d=fix(now):-1:1
       d = str2num(datestr(d,'YYYYmmDD'));
       if ~mod(d,v)
          return; 
       end
   end
   d = -1;
end

EDIT: Consegui otimizar um pouco, mas @DennisJaheruddin tem a solução real aqui


Isso ainda pode ser bastante praticado, vou atualizá-lo.
Dennis Jaheruddin

@DennisJaheruddin Rejeitei sua edição com base neste meta post . Sugira suas melhorias em um comentário, para que o OP possa revisá-las antes de modificar sua resposta.
Martin Ender

Observe que você pode salvar caracteres de várias maneiras: use um script em vez de uma função, deixe que as coisas sejam atribuídas a ans, faça o loop de baixo para alto e deixe que cada resultado substitua o anterior para que você não precise quebrar o loop . - É claro que a vetorização também pode ajudar, veja minha resposta .
Dennis Jaheruddin

Aqui está uma versão mais curta, baseada em loop, de 67 caracteres:-1,for s=str2num(datestr(1:now,'YYYYmmDD'))',if~mod(s,n),+s,end,end
Dennis Jaheruddin 31/07

@ MartinBüttner Obrigado pelo comentário. Houve um erro como você disse. Agora deve ficar tudo bem.
Scott

3

Python 3 - 151 148 bytes, geradores

from datetime import*
t=date.today()
f=lambda n:next((y for y in(int((t-timedelta(o)).strftime("%Y%m%d"))for o in range(t.toordinal()))if y%n<1),-1)

Obrigado @ nyuszika7h pela import*sugestão


2

Ruby 103

require'date'
f=->{d=Date.today 
(s=d.strftime('%Y%m%d').to_i
return s if s%n<1
d-=1)while d.year>0
-1}

Entrada

Espera que o valor do divisor esteja presente na variável n.

Saída

O valor de retorno da ffunção

Exemplo online: http://ideone.com/LoYxG4


2

Java: 373 caracteres

Esta é uma porta da resposta Groovy e usa o Joda Time.

Golfe:

import org.joda.time.*;
import org.joda.time.format.*;
public class D {
static int f(int i){return Integer.parseInt(DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(i)));}
public static void main(String[] args){
int n=Integer.parseInt(args[0]);int b=0,c=0,x=-1;
while(b!=1){if(f(c++)%n==0){x=f(--c);b=1;};if(f(0)-c<=101){b=1;}}
System.out.println(x);}}

Amostras de execuções (com joda-time-2.4.jar no caminho de classe:

$ java D 7
20140729
$ java D 4
20140728
$ java D 16
20140720
$ java D 90000
-1

Ungolfed:

import org.joda.time.*;
import org.joda.time.format.*;

public class D {
    static int f(int i) {
        return Integer.parseInt(DateTimeFormat.forPattern("yyyyMMdd").print(new LocalDate().minusDays(i)));
    }

    public static void main(String[] args) {
        int n = Integer.parseInt(args[0]);
        int b = 0,c = 0,x = -1;

        while(b!=1) {
            if(f(c++)%n==0) { x=f(--c);b=1; }
            if(f(0)-c<=101) { b=1; }
        }

        System.out.println(x);
    }
}

3
Há também java.time.*na versão mais recente do Java.
Ntskrnl

2

Bash + coreutils (8.21), 67 bytes

seq -f-%gday $[9**9]|date -f- +[pq]sp[_1pq]sq%Y%m%ddA1=qd$1%%0=p|dc
  • seqgera números inteiros de 1 a 9 9 , um por linha e formata-o como-<x>day
  • canalize isso para o date -fqual interpreta cada linha e gera a data formatada em uma dcexpressão como [pq] sp [_1pq] sq 20140728 d A1 =q d 7% 0=p(espaços adicionados para facilitar a leitura)
    • [pq] defina uma macro para imprimir o topo da pilha e saia
    • sp salvar macro no registro p
    • [pq] defina uma macro para pressionar -1, imprima a parte superior da pilha e saia
    • sq salvar macro no registro q
    • 20140728 inteiro de data incorporado
    • d parte superior duplicada da pilha
    • A1 push 101 (00000101)
    • =qpop 2 principais valores da pilha: compare a data e 101 e chame a macro qse igual
    • 7 divisor de pressão
    • % divisor pop e divida, divida e empurre o restante
    • 0 empurre 0
    • =ppop 2 principais valores da pilha: compare o restante e 0 e chame a macro pse igual
    • d parte superior duplicada da pilha
    • a macro pé chamada: imprime a data inteira e fecha dccompletamente
  • dcexpressões são canalizadas dcpara avaliação. Depois de dcimprimir o valor certo e sair, o restante do pipeline é derrubado

Saída:

$ ./lastdivdate.sh 4
20140728
$ ./lastdivdate.sh 7
20140729
$ ./lastdivdate.sh 123456
17901120
$ ./lastdivdate.sh 77777
19910912
$ ./lastdivdate.sh 7777777
-1
$ 

Como esse programa gera números inteiros de 1 a 9 9 , ele será válido por mais de um milhão de anos no futuro. Espero que esta limitação seja aceitável ;-)


Obrigado @ WumpusQ.Wumbley por reduzir o retorno de -1.


@ MartinBüttner Curses! Agora sim, com uma penalidade de 19 bytes :)
Digital Trauma

Formas mais curtas para converter a saída vazia para -1: add |grep .||echo -1até o fim do pipeline, ou o uso zsh onde você pode expansões ninho como echo ${$(cmd):-1}(isso vai custar-lhe uma barra invertida em outros lugares ...)

@ WumpusQ.Wumbley Por que não pensei nisso? Obrigado!
Digital Trauma

11
A propósito, isso parece ser sensível à versão coreutils. A mina (8.15) se recusa a voltar antes de 1901 com a especificação "days ago".

11
Na verdade, parece ser um sizeof time_tproblema, já que o limite em que quebra é 2 ** 31 segundos antes de 1/1/1970. Minha instalação mais antiga também é pateticamente de 32 bits

2

PYTHON: 134 bytes

Não vou conseguir vencer o líder atual, e não é muito melhor do que a melhor resposta em Python, mas decidi postar minha melhor solução em Python.

from datetime import*
def y(a,n):
 s=a.strftime("%Y%m%d")
 if int(s)%n==0:yield s
 try:x=y(a-timedelta(1),n)
 except:yield -1
 yield x

Ungolfed:

from datetime import *
def y(a, n):
    s=int(a.strftime("%Y%m%d"))
    if s%n==0:
        yield s
    try:
        x=y(a-timedelta(1), n)
    except:
        yield -1
    yield x

Na verdade, são 138 bytes. Você pode salvar 4 bytes usando em from datetime import*vez de import datetime as d, em timedelta(1)vez de d.timedelta(1)e em yieldvez de return.
precisa saber é o seguinte

Estou usando um contador de bytes online aleatório. Existe uma opção melhor?
RageCage


O que torna esse diferente deste? bytecount.bluebus112.com
RageCage

Aquele não conta novas linhas, além de contar caracteres , não bytes. Para o texto ASCII, os dois são iguais, portanto, o último não faz diferença aqui. No code-golf , você costuma contar caracteres, a menos que o OP diga o contrário. (Além disso, o que eu ligada foi o primeiro resultado no Google para "contagem de bytes" aqui.)
nyuszika7h

2

JavaScript (ES5) - 94

Ele espera a entrada na variável xe coloca a saída em o.

for(i=Date.now();i>-7e13&&(o=(new Date(i)).toISOString().replace(/-|T.*/g,''))%x;i-=864e5)o=-1

2

k4 (84) (73)

f:{f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;.z.D];x]}

Este é apenas um corte inicial com o primeiro algoritmo que veio à mente; Tenho certeza de que é possível melhorar tanto em desempenho quanto em duração.

Esta versão codifica a parte "today" (essa é a .z.D); altere-o para uma data literal ( yyyy.mm.dd) ou um número inteiro no sistema q date (dias desde 1 de janeiro de 2000) para executar os casos de teste. (q não analisará literais de datas anteriores ao início do século XVIII, portanto, para datas anteriores a isso, você precisará calcular o valor e usar o número inteiro apropriado diretamente. 1 de janeiro de "AD 0", nas especificações, vira -se -730457, que é usado no código de função. 28 de julho, 5 AD, a partir do último caso de teste, acaba por ser -728450.)

Os casos de teste fornecidos:

  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.30];x]}4
20140728
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.30];x]}7
20140729
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.28];x]}4
20140728
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;2014.07.28];x]}7
20140722
  "d"$-728450
0005.07.28
  {f d@*|&~.q.mod[(f:{$[^x;-1;.($x)@&~"."=$x]})'d:{"d"$x+!1+"i"$y-x}[-730457;-728450];x]}90000
-1

editar:

g:.,/$`\:`$$:;f:{$[Z=r:{(z>x)&.q.mod[g z]y}[Z:-730458;y]{x-1}/x;-1;g"d"$r]}

Essa é uma abordagem diferente que usa um dos operadores de convergência para diminuir a data até encontrar uma divisível ou cruzar o limite de 1/1/0000. Também faz a conversão de data para número inteiro de maneira ligeiramente diferente.

Os casos de teste, desta vez todos de uma vez:

  g:.,/$`\:`$$:;{$[Z=r:{(z>x)&.q.mod[g z]y}[Z:-730458;y]{x-1}/x;-1;g"d"$r]}'[2014.07.30 2014.07.30 2014.07.28 2014.07.28,"d"$-728450;4 7 4 7 90000]
20140728 20140729 20140728 20140722 -1

1

VBA 343 bytes (módulo)

Sub divD(i As Long)
a = Now()
b = Format(a, "yyyymmdd")
    Do While b / i <> Int(b / i)
    a = DateAdd("d", -1, a)
    b = Format(a, "yyyymmdd")
        If b = "01000101" Then
            MsgBox -1
            Exit Sub
        End If
    Loop
MsgBox b
End Sub

Isto pode ser fortemente condensado até Sub d(i):a=Now:b=a:Do Until b/i=Int(b/i):a=DateAdd("d",-1,a):b=Format(a,"yyyymmdd"):If b="01000101"Then:b=-1:Exit Sub:Loop:Debug.?b:End Subpara 139 Bytes
Taylor Scott

1

PowerShell - 76

Isso depende do número que está sendo armazenado na variável $n.

try{@(0..$n|%{'{0:yyyyMMdd}'-f(date).AddDays(-$_)}|?{!($_%$n)})[0]}catch{-1}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.