Dia da semana do próximo 29 de fevereiro

14

Escreva uma função que tenha uma data e retorne o dia da semana do próximo 29 de fevereiro após essa data.

  • A entrada é uma sequência no formato ISO estendido: AAAA-MM-DD (por exemplo, 27 de maio de 2010 seria "2010-05-27").

  • A saída é uma string que é o nome do dia da semana (por exemplo, "segunda-feira"). Letras maiúsculas não importam, mas dê o nome completo em inglês.

  • Se a data especificada for 29 de fevereiro, retorne o dia da semana do próximo dia 29 de fevereiro .

  • Use os cálculos do Calendário Gregoriano Proléptico (portanto, ele usa os cálculos do ano bissexto gregoriano para toda a sua duração). Não se preocupe com o calendário juliano ou quando ocorreu a mudança de juliano para gregoriano. Apenas assuma gregoriano para tudo.

  • A função deve funcionar para pelo menos o intervalo de "0001-01-01" - "2100-01-01".

  • Sinta-se à vontade para usar as bibliotecas padrão fornecidas por seu idioma, mas não use bibliotecas de terceiros, a menos que queira incluir esse código como parte da sua solução.

  • O código mais curto (menos caracteres) vence.

Exemplos:

  • func("0001-01-01") -> "Sunday"
  • func("1899-12-03") -> "Monday"
  • func("1970-01-01") -> "Tuesday"
  • func("1999-07-06") -> "Tuesday"
  • func("2003-05-22") -> "Sunday"
  • func("2011-02-17") -> "Wednesday"
  • func("2100-01-01") -> "Friday"

(e não, você não precisa nomear a função func)

Dicas:

  • Lembre-se de que os anos terminados em 00, que não são divisíveis por 400, não são bissextos.
  • 1 de janeiro de 0001 é uma segunda-feira.
Jonathan M Davis
fonte

Respostas:

7

Windows PowerShell, 65

Bastante direto.

filter f{for($d=date $_;($d+='1').day*$d.month-58){}$d.dayofweek}

Como de costume, podemos cortar dois bytes se quisermos esperar muito tempo até a conclusão:

filter f{for($d=date $_;($d+=9).day*$d.month-58){}$d.dayofweek}

Teste:

> '0001-01-01','1899-12-03','1970-01-01','1999-07-06','2003-05-22','2011-02-17','2100-01-01'|f
Sunday
Monday
Tuesday
Tuesday
Sunday
Wednesday
Friday

História:

  • 2011-02-18 00:06 (65) Primeira tentativa.
Joey
fonte
Que caminho é necessário para que isso funcione? Tenho a data do GnuWin no meu caminho, que está quebrando.
Peter Taylor
@ Peter: Pode colidir com date. Basta remover o GNUWin32 do PATH e ele deve funcionar. Ou mude datepara Get-Date(esse tipo de comportamento de fallback só funciona quando nenhum comando é encontrado - para verificar, basta usar gcm date). De qualquer forma, não considero que um problema específico com esse script, pois o GNUWin32 não faça parte de nenhuma instalação padrão do Windows.
Joey
O motivo pelo qual perguntei foi porque eu já tentei usar get-datee recebi a mensagem de erro Method invocation failed because [System.Management.Automation.PSObject] doesn't contain a method named 'op_Addition'.Precisa de PS2 ou .Net 4 ou algo assim?
Peter Taylor
@ Peter: Eu tentei o PowerShell v2. O .NET 4 não funciona, pois o PowerShell está vinculado ao tempo de execução 2.0. Em qualquer caso, não deve haver um PSObject retornando, Get-Datemas a System.DateTime.
Joey
Isso é muito estranho. $d=Get-Date "0400-01-01"; $d++dá uma mensagem de erro sobre ++não estar definido no DateTime. O mesmo substituindo ++por +=1ou +="1"ou +='1'dá a mensagem de erro sobre o PSObject. E simplesmente +"1"funciona.
Peter Taylor
5

Ruby 1.9, 85 caracteres

f=->a{require"date";d=Date.parse(a,0,0)+1;d+=1until d.day*d.month==58;d.strftime"%A"}

Solução simples. Chame a função com f[args].

  • Edit: (87 -> 97) Corrigido o 0001-01-01testcase.
  • Edit 2: (97 -> 91) Date.parse também permite especificar a data da reforma do calendário.
  • Edit 3: (91 -> 87) Use uma lambda em vez de uma função. Obrigado Dogbert !
  • Editar 4: (87 -> 85) Remova espaços desnecessários. Mais uma vez obrigado, Dogbert !
Ventero
fonte
4
Falha na caixa de teste para "0001-01-01". O Ruby Date é muito poderoso, leva em consideração as datas julianas.
18711
@Ventero O que def * faz? Nunca vi isso antes.
18711
@steenslag: Obrigado, corrigimos esse caso de teste. def*apenas define uma função chamada *. Dessa forma, não preciso de um espaço entre defe o nome da função.
Ventero
1
Você não poderia simplesmente definir um lambda? a = -> {...}
Dogbert 17/02
1
Além disso, não há necessidade de espaço após o tempo de transmissão.
Dogbert
3

T-SQL 166 185 caracteres

CREATE PROCEDURE f29 (@d DATETIME) AS
DECLARE @i int
SET @i=YEAR(DATEADD(M,-2,@d)+3)
SET @i=@i+(4-@i%4)
IF @i%100=0 AND @i%400<>0 SET @i=@i+4
SELECT DATENAME(W,CAST(@i AS CHAR)+'-2-29')

Eu já estava mexendo com as funções de data do T-SQL, então imaginei por que não ...

A solução original estava incorreta ...

Aqui está o que eu realmente tenho que fazer para que essa estratégia funcione:

CREATE PROCEDURE f29 (@d DATE) AS
DECLARE @i int
SET @i = YEAR(@d)
BEGIN TRY 
SET @i=YEAR(DATEADD(D, 3, DATEADD(M,-2,@d)))
END TRY
BEGIN CATCH
END CATCH
SET @i=@i+(4-@i%4)
IF @i%100=0 AND @i%400<>0 SET @i=@i+4
SELECT DATENAME(W,CAST(@i AS CHAR)+'-2-29')
mootinator
fonte
Como crio um estouro subtraindo 2 meses de 0001-01-01, mesmo que eu use o tipo de dados correto, desisto de criar algo curto e válido para esta pergunta. O_o. Trixsy questiona.
mootinator 17/02
Adoro ver essas soluções T-SQL. :)
Steve
3

C #, 176

Func<String,String>f=(d)=>{DateTime n;for(n=DateTime.Parse(d).AddDays(307);!(DateTime.IsLeapYear(n.Year));n=n.AddYears(1)){}return new DateTime(n.Year,2,29).ToString("dddd");};
Kris Ivanov
fonte
Você pode salvar 8 bytes usando uma definição de função normal:string f(string d){...}
Joey
.ToString("dddd")imprime a data na localidade atual, porém, não em inglês.
Joey
165 caracteres => string f (string d) {var n = DateTime.Parse (d) .AddDays (307); while (! (DateTime.IsLeapYear (n.Year))) n = n.AddYears (1); return (new DateTime (n.Year, 2,29)). DayOfWeek.ToString ();}
Stephan Schinkel
Melhorado ainda para 127 caracteres:string f(string d){var n=DateTime.Parse(d).AddDays(1);return DateTime.IsLeapYear(n.Year)&&n.DayOfYear==60?n.DayOfWeek+"":f(n+"");}
Patrik Westerlund 29/08
3

Bash, 96 bytes

Obrigado Peter ... Versão altamente golfe, 96 bytes:

i=1;until [ `date -d"$1 $i days" +%m-%d` = "02-29" ];do((i++));done
date -d "${1} ${i} days" +%A

Versão antiga, 229 bytes

#!/bin/bash
from=$1
i=1
while [ "$isFeb" = "" ] || [ "$is29" = "" ]
do
isFeb=`date -d "${from} ${i} days" | grep Feb`
is29=`date -d "${from} ${i} days" +%Y-%m-%d | grep "\-29"`
((i++))
done
((i--))
date -d "${from} ${i} days" +%A

E / S DE AMOSTRA

:~/aman>./29Feb.sh 0001-01-01
Sunday
:~/aman>./29Feb.sh 1899-12-03
Monday
:~/aman>./29Feb.sh 1970-01-01
Tuesday
Aman ZeeK Verma
fonte
pode ter que definir TZ se nenhum fuso horário padrão é definido, aprendi cyberciti.biz/faq/... ao fazer isto em algum IDE on-line
Aman Verma Zeek
1
Você vai jogar isso? ; p Você pode substituir tudo antes da linha final pori=0;d=;until [ `date -d"$1 $i days" +%m-%d` = "02-29" ];do((i++));done
Peter Taylor
:-) como já discutimos sobre o meu estado bruto por causa do bash! ... Por alguma razão, eu não brinco muito com o bash .. eles são tão propensos a erros! .. Obrigado por sua sugestão .. atualizado!
Aman ZeeK Verma
1
Crueza com o bash não é desculpa para o uso de nomes de variáveis de quatro letras: P
Peter Taylor
sim senhor, entendi seu ponto.
Aman ZeeK Verma
2

Perl, sem biblioteca de datas: 160 159 155

sub f {($ y, $ m) = divisão / - /, @ _ ​​[0], 2; $ y ++ if ($ m> '02 -28 '); $ y = ($ y + 3)% 400 >> 2; $ y + = $ y &&! ($ Y% 25); @ r = (terça, quarta, quinta, sexta, sex, sáb, dom, seg); @ r [(5 * $ y - ($ y / 25 e 3))% 7]. "Dia";}

O benefício real dessas bibliotecas de datas é adiar a duração dos nomes dos dias para outra pessoa.

Por outro lado, acho que essa é a única solução até agora que funciona independentemente da localidade.

Peter Taylor
fonte
2

DATE e um pouco de cola BASHy (90)

A função:

f(){ while :;do $(date -d$1+1day +'set - %F %A 1%m%d');(($3==10229))&&break;done;echo $2;}

Teste:

$ for x in 0001-01-01 1899-12-03 1970-01-01 1999-07-06 2003-05-22 2011-02-17 2100-01-01 ; do f $x ; done
Sunday
Monday
Tuesday
Tuesday
Sunday
Wednesday
Friday

fonte
1

D: 175 caracteres

S f(S)(S s){auto d=Date.fromISOExtString(s)+days(1);while(d.month!=Month.feb||d.day!=29)d+=days(1);return["Sun","Mon","Tues","Wednes","Thurs","Fri","Sat"][d.dayOfWeek]~"day";}

Mais legivelmente:

S f(S)(S s)
{
    auto d = Date.fromISOExtString(s) + days(1);

    while(d.month != Month.feb || d.day != 29)
        d += days(1);

    return ["Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Sat"][d.dayOfWeek] ~ "day";
}

É muito fácil escrever em D, mas definitivamente não vai ganhar nenhum concurso de código de golfe. Ainda assim, fora do código de golfe, eu preferiria que fosse fácil escrever e entender, mas longo, do que conciso, mas difícil de escrever e entender.

Jonathan M Davis
fonte
1

Caracteres Java 8 - 252

Golfe:

import java.time.*;
import java.time.format.*;
public class S{public static void main(String[] a){LocalDate d=LocalDate.parse(a[0]).plusDays(1);while(d.getMonthValue()!=2||d.getDayOfMonth()!=29){d=d.plusDays(1);}System.out.println(d.getDayOfWeek());}}

Ungolfed:

import java.time.*;
import java.time.format.*;
public class S {
    public static void main(String[] a) {
        LocalDate d = LocalDate.parse(a[0]).plusDays(1);

        while(d.getMonthValue()!=2 || d.getDayOfMonth()!=29) {
            d = d.plusDays(1);
        }
        System.out.println(d.getDayOfWeek());
    }
}
Michael Easter
fonte
Aceito votos negativos, mas você pode explicar "o necro é real" e criar um link para uma FAQ que explica seu ponto de vista? Eu não pensei que venceria, mas achei interessante ver como o Java poderia fazer, esp. dado o Java 8. Eu vejo o código golf como tendo "classes de peso" versus uma competição direta. O Java raramente supera o Ruby ou o Python diretamente.
Michael Easter
O OP proíbe bibliotecas de terceiros, portanto, em 2011, uma solução Java seria desagradável, pois não se poderia usar a popular biblioteca Joda Time. No entanto, o Java 8 (lançado em março de 2014) contém a biblioteca JSR-310 DateTime - en.wikipedia.org/wiki/… . Minha razão é que pensei que o Java 8 seria divertido e potencialmente interessante para alguns leitores. (Se você não é um daqueles, bem: ainda há uma razão para o post.)
Michael Páscoa
1

Rebol - 78

f: func[d][system/locale/days/(until[d: d + 1 d/day * d/month = 58]d/weekday)]

Ungolfed:

f: func [d] [
    system/locale/days/(
        until [
            d: d + 1
            d/day * d/month = 58
        ]
        d/weekday
    )
]

Exemplo de uso (no console Rebol):

>> f 0001-01-01
== "Sunday"

>> f 2100-01-01
== "Friday"
draegtun
fonte
1

PHP, 104 bytes

function f($s){for($y=$s-(substr($s,5)<"02-29");!date(L,$t=strtotime(++$y."-2-1")););return date(l,$t);}

demolir

for($y=$s-;                 // "-" casts the string to int; decrement year if ...
    (substr($s,5)<"02-29")  // ... date is before feb 29
    !date(L,                        // loop while incremented $y is no leap year
        $t=strtotime(++$y."-2-1")   // $t=feb 01 in that year (same weekday, but shorter)
    );
);
return date(l,$t);          // return weekday name of that timestamp

date(L): 1para o ano bissexto,0 else
date(l): representação textual completa do dia da semana

Titus
fonte
0

Coreutils GNU, 71 bytes

f(){
seq -f "$1 %gday" 2921|date -f- +'%m%d%A'|sed 's/0229//;t;d;:;q'
}

Pesquisa linear dos próximos 8 anos (pior caso, em 2096-02-29). Sed encontra e gera a primeira linha que corresponde a 29 de fevereiro.

Fiquei surpreso ao descobrir que t;d;:;q era mais curto que o teste para ver se os dígitos permaneciam ( /[01]/d;q), apesar de ter o dobro de comandos.

Testes

Adicionei uma linha extra de testes para casos de canto difíceis:

for i in 0001-01-01.Sunday 1899-12-03.Monday \
    1970-01-01.Tuesday     1999-07-06.Tuesday \
    2003-05-22.Sunday      2011-02-17.Wednesday 2100-01-01.Friday \
    2000-02-28.Tuesday     2000-02-29.Sunday    2000-03-01.Sunday   2096-02-29.Friday
do
    printf "%s => %s (expected %s)\n" ${i%.*} $(f ${i%.*}) ${i#*.}
done
Toby Speight
fonte