A última segunda-feira

27

Segunda-feira, 31 de outubro, é o Halloween. E isso me fez pensar - eu me pergunto que outros meses o último dia do mês também será uma segunda-feira?

Entrada

  • Um número inteiro positivo em qualquer formato conveniente que represente um ano 10000 > y > 0,.
  • A entrada pode ser preenchida com zeros (por exemplo, 0025para o ano 25), se necessário.

Saída

  • Uma lista dos meses desse ano em que o último dia do mês é uma segunda-feira.
  • Pode ser como nomes de mês (por exemplo, January, March, October) ou nomes abreviados ( Jan, Mar, Oct) ou números ( 1, 3, 10), como linhas separadas ou uma lista ou delimitada etc. etc., desde que não seja ambíguo para o leitor.
  • O formato de saída deve ser consistente:
    • Para todos os anos de entrada (ou seja, não é possível gerar nomes de meses para algumas entradas e números de meses para outras entradas)
    • Bem como consistente por saída (ou seja, não é possível saída 1para Januaryna mesma saída Julpara July)
    • Basicamente, escolha um formato e cumpra-o.

Regras

  • Suponha que o calendário gregoriano para entrada / saída, até y = 1.
  • Os anos bissextos devem ser adequadamente contabilizados (como um lembrete: todos os anos divisíveis por 4, exceto os não divisíveis por 100, a menos que também divisíveis por 400 - 1700, 1800, 1900, todos não foram bissextos, mas 2000 foi).
  • Você pode usar quaisquer ferramentas internas ou outras ferramentas de cálculo de data que desejar.
  • Um programa completo ou uma função são aceitáveis. Se uma função, você pode retornar a saída em vez de imprimi-la.
  • As brechas padrão são proibidas.
  • Isso é portanto todas as regras usuais de golfe se aplicam e o código mais curto (em bytes) vence.

Exemplos

   1 --> Apr, Dec
 297 --> May
1776 --> Sep
2000 --> Jan, Jul
2016 --> Feb, Oct
3385 --> Jan, Feb, Oct

Entre os melhores

AdmBorkBork
fonte
1
Relacionados 1 e Relacionados 2 .
AdmBorkBork 26/10
1
Relacionados, mas não duplicados ou?
ElPedro 26/10
@ElPedro Relacionado, mas não duplicado. O primeiro não permite nenhum built-in e solicita uma combinação fixa de data / dia (sexta-feira 13), enquanto o segundo solicita o último domingo de cada mês do ano, limitado entre 1900 e 3015.
AdmBorkBork
Desculpe @TimmD. Meu mal-entendido do seu comentário.
ElPedro 26/10
1
@ElPedro Sem problemas! Eu preferiria ter uma pergunta e deixar claro, do que não ter uma pergunta e ter algo incerto.
AdmBorkBork 26/10

Respostas:

2

Dyalog APL com dfns 's cal , Versão 15.0: 22; Versão 16.0: 19 bytes

A função cal vem com uma instalação padrão, basta digitar )copy dfns.

Versão 15.0: ∊⎕{⍵/⍨2=≢⍎⊢⌿cal⍺⍵}¨⍳12

alistar-se (achatar)

⎕{... entrada numérica como argumento esquerdo para a seguinte função anônima, assumindo cada um dos valores do lado direito como argumento direito

⍵/⍨ o argumento if (fornece uma lista vazia, se não)

2= dois (domingo e segunda-feira) é igual a

a contagem de

os números em

⊢⌿ a linha mais baixa de

cal o calendário para

⍺⍵ ano argumento à esquerda, mês argumento à direita, sendo este último

⍳12 1 a 12

Versão 16.0: ⍸2=⎕{≢⍎⊢⌿cal⍺⍵}¨⍳12

os índices onde

2= dois iguais (ou seja, domingo e segunda-feira)

⎕{... entrada numérica como argumento esquerdo para a seguinte função anônima, assumindo cada um dos valores do lado direito como argumento direito

a contagem de

os números em

⊢⌿ a linha mais baixa de

cal o calendário para

⍺⍵ ano argumento à esquerda, mês argumento à direita, sendo este último

⍳12 1 a 12

Adão
fonte
19

JavaScript (Firefox 30+), 112 109 103 95 bytes

Olha ma, não tem embutidos!

y=>[for(m of(i=0,y%4|y%400*!(y%100)&&6)+"63153042641")if((i++,y+(y>>2)-(y/100|0)*3/4|0)%7==m)i]

Aqui está uma versão ES6 de 107 bytes:

y=>[...(y%4|y%400*!(y%100)&&6)+"63153042641"].map((m,i)=>(y+(y>>2)-(y/100|0)*3/4|0)%7-m?0:i+1).filter(x=>x)

E aqui está a minha tentativa anterior, 123 113 bytes de ES6:

y=>[(l=y%4|y%400*!(y%100))?[7]:[1,7],[4,12],[9],[3,6],[8,11],[5],l?[1,2,10]:[2,10]][(y+(y>>2)-(y/100|0)*3/4|0)%7]

Explicação

O dia da semana de um determinado ano é calculado da seguinte forma:

y+(y>>2)-(y/100|0)*3/4|0)%7

Em outras palavras:

  • Tome y.
  • Adicione o número do quarto ano anterior y( y>>2).
  • Subtraia o número dos 100 anos antes y( y/100|0).
  • Adicione novamente o número de 400 anos antes y; isso é 1/4 de y/100|0, então usamos *3/4|0.

Em seguida, modulamos o resultado por 7. Se deixarmos 0dizer domingo, 1segunda segunda, etc., o resultado corresponderá ao dia da semana de 31 de dezembro daquele ano. Portanto, para dezembro, queremos verificar se o resultado é 1. Isso nos dá o último caractere na string.

O último dia de novembro é 31 dias antes do último dia de dezembro. Isso significa que para o último dia de novembro ser uma segunda-feira, 31 de dezembro precisa ser uma (1 + 31) % 7 = 4= quinta-feira.

Este procedimento é repetido até voltarmos a março (a 3). Independentemente de haver ou não um dia bissexto, o último dia de fevereiro é 31 dias antes do último dia de março, para que possamos calcular isso também (é (3 + 31) % 7 = 6). A parte complicada é encontrar o valor correto para janeiro:

  • Se for um ano bissexto, o último dia de janeiro será 29 dias antes do último dia de fevereiro, resultando em (6 + 29) % 7 = 0.
  • Caso contrário, serão 28 dias antes do último dia de fevereiro, resultando em (6 + 28) % 7 = 6.

Podemos calcular se é ou não um ano bissexto com o seguinte snippet:

!(y%400)|y%100*!(y%4)

Isso indica 0se ynão é um ano bissexto e, se não, um número inteiro positivo. Isso nos leva a

!(y%400)|y%100*!(y%4)?0:6

para calcular o dia de janeiro. No entanto, podemos fazer melhor revertendo as condições:

y%4|y%400*!(y%100)?6:0

Como o resultado falso é sempre 0, podemos reduzi-lo para

y%4|y%400*!(y%100)&&6

economizando mais um byte precioso.

Juntando tudo, percorremos cada caractere na string, verificando se cada um é igual ao dia da semana de 31 de dezembro. Mantemos os índices dos que correspondem, retornando essa matriz no final. E é assim que você faz cálculos de ano bissexto sem embutidos.

ETHproductions
fonte
Owww ... Meu cérebro, você contabilizou anos bissextos em tudo isso?
Magic Octopus Urn
2
@carusocomputing É para isso que !(y%4)*y%100|!(y%400)serve. cada divisível ano a 4, com excepção não anos divisíveis por 100, a menos que também divisível por 400
mbomb007
Esperamos que y+(y>>2)+(z=y/25>>2)+(z>>2)ainda economize um byte.
Neil
@ Neil Obrigado, mas eu encontrei uma maneira melhor :-)
ETHproductions 26/16
Agradável; Salvei 6 bytes na minha porta Batch usando (y*5/4-(y/100)*3/4).
Neil
11

JavaScript (Firefox 30-57), 67 65 64 63 61 bytes

y=>[for(_ of(m='')+1e11)if(new Date(y+400,++m).getDay()==2)m]

Guardado 2 4 6 bytes graças a @ETHproductions. Economizou outro byte, exibindo os meses na ordem inversa.

Neil
fonte
Eu acho que você pode salvar 2 bytes ao .keys()y=>[for(_ of(m=0,Array(12)))if(new Date(y+400,++m).getDay()==2)m]
voar
@ETHproductions Posso salvar mais um byte, revertendo o pedido!
Neil
A ordem inversa está correta. Formatar a saída não é a parte interessante desse desafio.
AdmBorkBork 27/10
Qual é a nossa política sobre as compreensões de matriz agora que elas foram removidas das especificações?
MayorMonty 27/10/16
Você pode salvar outros 2 bytes ignorando Array(12)completamente: y=>[for(_ of(m=0,1e11+""))if(new Date(y+400,++m).getDay()==2)m]
ETHproductions
8

MySQL, 183 134 129 106 bytes

SET @y=2016;SELECT help_topic_id AS m FROM mysql.help_topic HAVING m BETWEEN 1 AND 12 AND 2=DAYOFWEEK(LAST_DAY(CONCAT(@y,-m,-1)))

Substitua 2016pelo ano desejado. Corre.

Rev. 2: Usou a help_topicstabela na instalação padrão em vez de criar uma tabela temporária.

Rev.3: Adotou o truque de aross- e percebeu que também posso omitir as aspas de "-1".
No entanto, -1é necessário no MySQL: eu preciso de uma data completa.

Rev.4: A restrição m BETWEEN 1 AND 12pode ser feita como m>0 AND m<13(-6), mas não é necessária - valores inválidos serão ignorados; os avisos serão contados, mas não listados.

Titus
fonte
Você realmente precisa da tabela shema mysql? mariadb.com/kb/en/mariadb/mysqlhelp_topic-table
Jörg Hülsermann 27/10
@ JörgHülsermann Não entendi seu ponto.
Titus
Deve FROM help_topicsem mysql.trabalho? Eu tentei não
Jörg Hülsermann 28/10
@ JörgHülsermann apenas se você pré-anexar USE mysql;O banco de dados correto deve ser selecionado de alguma forma.
Titus
5

Perl, 64 bytes

Inclui +1 para -n

Dê entrada no STDIN:

perl -M5.010 mon.pl <<< 2016

mon.pl:

#!/usr/bin/perl -n
map$b.=$/.gmtime$_.e4,-7e6..3e7;say$b=~/on (\S+ )\S.* $_.* 1 /g
Ton Hospel
fonte
5

Lote, 160 152 bytes

@set/ay=%1,m=0,j=6*!(!(y%%4)*(y%%100)+(y%%400)),y=(y*5/4-y/100*3/4)%%7
@for %%d in (%j% 6 3 1 5 3 0 4 2 6 4 1)do @set/am+=1&if %%d==%y% call echo %%m%%

Porto da resposta da @ ETHproduction. Com abreviações de mês para 197 189 bytes:

@set/ay=%1,j=6*!(!(y%%4)*(y%%100)+(y%%400)),y=(y*5/4-y/100*3/4)%%7
@for %%m in (Jan.%j% Feb.6 Mar.3 Apr.1 May.5 Jun.3 Jul.0 Aug.4 Sep.2 Oct.6 Nov.4 Dec.1)do @if %%~xm==.%y% call echo %%~nm
Neil
fonte
4

J, 48 34 33 bytes

[:I.(2=7|_2#@".@,@{.])&>@calendar

Economizou 15 bytes com a ajuda de @ Adám .

Usa o calendário interno para gerar uma matriz de seqüências representando os meses e analisa cada sequência para determinar se a última segunda-feira é o último dia do mês. Ele gera cada mês como o número do mês de cada um. Ou seja, Jan = 0, Feb = 1, ..., Dec = 11.

A saída de calendaré

   _3 ]\ calendar 2016
┌─────────────────────┬─────────────────────┬─────────────────────┐
│         Jan         │         Feb         │         Mar         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                 1  2│     1  2  3  4  5  6│        1  2  3  4  5│
│  3  4  5  6  7  8  9│  7  8  9 10 11 12 13│  6  7  8  9 10 11 12│
│ 10 11 12 13 14 15 16│ 14 15 16 17 18 19 20│ 13 14 15 16 17 18 19│
│ 17 18 19 20 21 22 23│ 21 22 23 24 25 26 27│ 20 21 22 23 24 25 26│
│ 24 25 26 27 28 29 30│ 28 29               │ 27 28 29 30 31      │
│ 31                  │                     │                     │
├─────────────────────┼─────────────────────┼─────────────────────┤
│         Apr         │         May         │         Jun         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                 1  2│  1  2  3  4  5  6  7│           1  2  3  4│
│  3  4  5  6  7  8  9│  8  9 10 11 12 13 14│  5  6  7  8  9 10 11│
│ 10 11 12 13 14 15 16│ 15 16 17 18 19 20 21│ 12 13 14 15 16 17 18│
│ 17 18 19 20 21 22 23│ 22 23 24 25 26 27 28│ 19 20 21 22 23 24 25│
│ 24 25 26 27 28 29 30│ 29 30 31            │ 26 27 28 29 30      │
│                     │                     │                     │
├─────────────────────┼─────────────────────┼─────────────────────┤
│         Jul         │         Aug         │         Sep         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                 1  2│     1  2  3  4  5  6│              1  2  3│
│  3  4  5  6  7  8  9│  7  8  9 10 11 12 13│  4  5  6  7  8  9 10│
│ 10 11 12 13 14 15 16│ 14 15 16 17 18 19 20│ 11 12 13 14 15 16 17│
│ 17 18 19 20 21 22 23│ 21 22 23 24 25 26 27│ 18 19 20 21 22 23 24│
│ 24 25 26 27 28 29 30│ 28 29 30 31         │ 25 26 27 28 29 30   │
│ 31                  │                     │                     │
├─────────────────────┼─────────────────────┼─────────────────────┤
│         Oct         │         Nov         │         Dec         │
│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│ Su Mo Tu We Th Fr Sa│
│                    1│        1  2  3  4  5│              1  2  3│
│  2  3  4  5  6  7  8│  6  7  8  9 10 11 12│  4  5  6  7  8  9 10│
│  9 10 11 12 13 14 15│ 13 14 15 16 17 18 19│ 11 12 13 14 15 16 17│
│ 16 17 18 19 20 21 22│ 20 21 22 23 24 25 26│ 18 19 20 21 22 23 24│
│ 23 24 25 26 27 28 29│ 27 28 29 30         │ 25 26 27 28 29 30 31│
│ 30 31               │                     │                     │
└─────────────────────┴─────────────────────┴─────────────────────┘

Uso

   f =: [:I.(2=7|_2#@".@,@{.])&>@calendar
   f 1
3 11
   f 297
4
   f 1776
8
   f 2000
0 6
   f 2016
1 9
   f 3385
0 1 9

Explicação

[:I.(2=7|_2#@".@,@{.])&>@calendar  Input: year Y
                         calendar  Get 12 boxes each containing a month
    (                )&>@          Operate on each box
                    ]                Identity, get the box
         _2       {.                 Take the last two strings
                ,@                   Flatten it
             ".@                     Parse it into an array of integers
           #@                        Get the length
       7|                            Take it modulo 7
     2=                              Test if it equals 2 - it will either
                                     have two days or 9 days in the last
                                     two lines if the end is on a Monday
[:I.                               Return the indices containing a true value
milhas
fonte
espere, o calendário realmente produz arte ASCII?
Destructible Lemon
@DestructibleWatermelon Para ser exato, o formato de saída calendaré uma matriz de 12 caixas em que cada caixa contém uma matriz 2D de caracteres
milhas
Eu nem sei como fazer "cada" em J, mas isso já é muito mais curto: I.7=;#&.>".&.>,&.>_2{.&.>calendar 2016se você combinar todos os "sub-abertos", deverá conseguir abreviá-lo.
Adám 27/10/16
@ Adám Obrigado, ele usa um método melhor, mas não é um verbo em J. Acho que ainda ajudará
miles
Minha intenção era apenas inspirar. Eu sei que não é um verbo.
Adám 27/10/16
4

Mathematica, 62 57 bytes

DayName@DayRange[{#},{#+1},"EndOfMonth"]~Position~Monday&

Função anônima. Pega um número como entrada e retorna uma lista de listas de números de elemento único como saída. Sinceramente, não tenho mais certeza de como funciona.

LegionMammal978
fonte
4

Perl + cal, 46 bytes

say`cal $_ $ARGV[0]`=~/\n.{5}\n/&&$_ for 1..12

Exemplo:

$ perl -E 'say`cal $_ $ARGV[0]`=~/\n.{5}\n/&&$_ for 1..12' 2016

2







10


$
Steve
fonte
1
A rigor, isso é perl + cal, não apenas perl :-p. Por exemplo, minha máquina Windows possui perl, mas isso não funciona lá.
26416 philomory
Ponto justo, atualizei essa e minha tentativa do bash.
steve
4

Java 7,186 182 172 bytes

Obrigado a Kevin por salvar 4 bytes
Obrigado a @cliffroot por salvar 10 bytes

int[]f(int n){int c=n-1,x=c*365+c/4+c/400-c/100,k=0,b[]={3,(n%4<1&n%100>0)|n%400<1?1:0,3,2,3,2,3,3,2,3,2,3},a[]=new int[12];for(int i:b)a[k++]=(x+=i+28)%7==1?1:0;return a;}

destroçado

int[] f(int n) {
 int c=n-1,x=c*365+(c/4)+(c/400)-(c/100),k=0,
   b[] = {3,(n % 4 < 1 & n % 100 > 0) | n % 400 < 1 ? 1 : 0
                                     ,3,2,3,2,3,3,2,3,2,3},a = new int[ 12 ];

 if ( (n % 4 < 1 & n % 100 > 1) | n % 400 < 1 )
     b[ 1 ] = -1;
 for (int i : b)
    a[ k++ ] = (x += i + 28) % 7 == 1 ? 1 : 0;

return a;
     }

Esta versão é fornecida por @cliffroot ( 168 bytes )

 static int[] f(int n) {
 int b = 13561787 | ( (n%4 < 1 & n%100 > 0) | n%400 < 1 ? 1 << 20 : 0 ),
           x = --n*365 + n/4 + n/400 - n/100,a[]=new int[12],k=0;
    while (k < 12)
    a[k++] = (x += (b >> 24 - k*2&3 ) + 28) % 7 == 1 ? 1 : 0;
  return a;   }
    }

amostra de saída

1 1 0 0 0 0 0 0 0 1 0 0(for input 3385)
Numberknot
fonte
1
Depois que eu escrevi a minha resposta eu sabia calcular tudo sozinho seria mais curto .. :) Btw, você pode golfe n%4==0para n%4<1; n%400==0para n%400<1e int c=...;int[]b=...,a=...para int c=...,b[]=...,a[]=....
Kevin Cruijssen 27/10
1
be apode ser definido na intparte assim:int ... ,b[]=...,a[]=...
Olivier Grégoire
1
int[]f(int n){int x=--n*365+n/4+n/400-n++/100,k=0,b[]={1,(n%4<1&n%100>0)|n%400<1?-1:-2,1,0,1,0,1,1,0,1,0,1},a[]=new int[12];for(int i:b)a[k++]=(x+=i+30)%7==1?1:0;return a;}poucos bytes salvos
cliffroot 27/10
1
Também é possível alterar ba b[]={3,(n%4<1&n%100>0)|n%400<1?1:0,3,2,3,2,3,3,2,3,2,3}e i+30a i+28para mais 2 bytes
cliffroot
1
e mais 3 bytesint[]f(int n){int b=13561787|((n%4<1&n%100>0)|n%400<1?1<<20:0),x=--n*365+n/4+n/400-n/100,a[]=new int[12],k=0;while(k<12)a[k++]=(x+=(b>>24-k*2&3)+28)%7==1?1:0;return a;}
cliffroot 27/10
3

Python 2, 100 bytes

Ugh. Matemática com datas não é tão simples quanto eu gostaria.

lambda y:[m+1for m in range(12)if(date(y,12,31)if m>10else(date(y,m+2,1)-timedelta(1))).weekday()<1]

Experimente online

Mesmo comprimento:

lambda y:[m-1for m in range(2,14)if(date(y,12,31)if m>12else(date(y,m,1)-timedelta(1))).weekday()<1]
mbomb007
fonte
Eu nem tentaria Python com este. Bom esforço.
ElPedro 26/10
3

MATL , 21 bytes

12:"G@QhO6(YO9XO77=?@

Os meses são exibidos como números.

Experimente online! Ou verifique todos os casos de teste .

Explicação

Isso usa funções internas de conversão de data. Para o ano determinado, ele testa quais os últimos dias do mês é segunda-feira.

Em vez de especificar explicitamente o último dia do mês k(que pode ser 28, 29, 30 ou 31), especificamos o 0-ésimo dia do mês k+1, que é equivalente e não depende do mês ou do ano.

12:      % Push [1 2 ... 12] (months)
"        % For each month k
  G      %   Push input
  @Q     %   Push k+1
  h      %   Concatenate
  O6(    %   Postpend four zeros. For example, for input 2016 and month k=1 
         %   (first iteration) this gives [2016 2 0 0 0 0] (year, month, day,
         %   hour, min, sec). The 0-th day of month k+1 is the same as the
         %   last day of month k.
  YO     %   Convert the above 6-element date vector to date number
  9XO    %   Convert date number to date string with output format 9, which 
         %   is weekday as a capital letter
  77=    %   Is it an 'M'?
  ?      %   If so
    @    %     Push current month (will be implicitly displayed)
Luis Mendo
fonte
3

Utilitários Bash + GNU, 56 bytes

seq -f1month-1day$1-%g-1 12|date -f- +%B%u|sed -n s/1//p

Parece exigir a dateversão 8.25. A versão 8.23 ​​do Ideone não funciona.

Trauma Digital
fonte
3

Excel, 537 bytes

Porque - você sabe - Excel!

Recebe o ano de entrada em A1. Retorna a lista hexadecimal de meses; 1 = janeiro, C = dezembro. Como cada mês é um dígito, não é necessário separador.

=IF(2=WEEKDAY(EOMONTH(DATE(A1,1,1),0)),1,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,2,1),0)),2,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,3,1),0)),3,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,4,1),0)),4,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,5,1),0)),5,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,6,1),0)),6,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,7,1),0)),7,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,8,1),0)),8,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,9,1),0)),9,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,10,1),0)),"A","")&IF(2=WEEKDAY(EOMONTH(DATE(A1,11,1),0)),"B","")&IF(2=WEEKDAY(EOMONTH(DATE(A1,12,1),0)),"C","")

Exemplo: A1 contém 2016. B1 contém a fórmula acima e é exibida como 2A, significando fevereiro e outubro.

Adão
fonte
3

PHP, 109 180 159 bytes

for($z=$argv[1];$m++<12;)if(date(N,strtotime(sprintf("%04d-$m-",$z).cal_days_in_month(0,$m,$z)))<2)echo"$m,";
  • Produz o ano fornecido, nem todos (... sempre lê a pergunta)
  • Avisos ignorados (obrigado Titus)
  • Mude whilepara forcomo agora é um ano (mais uma vez, obrigado Titus)

2 velhos

$z=0;while($z++<9999){$o=[];$m=0;while($m++<12)if(date("N",strtotime(sprintf("%04d-$m-","$z").cal_days_in_month(0,$m,$z)))<2)$o[]=$m;echo count($o)>0?"$z:".implode(",",$o)."
":"";}

Suporta todos os anos, do ponto ao 10000, também se livrou de um aviso indefinido de var que eu não conhecia em um PC. Sim, é mais longo que a versão antiga, mas é mais robusta.

Antigo 1

while($z++<9999){$o=[];$m=0;while($m++<12)if(date("N",strtotime("$z-$m-".cal_days_in_month(0,$m,$z)))<2)$o[]=$m;echo count($o)>0?"$z:".implode(",",$o)."
":"";}

Se estiver rodando no Windows ou em um sistema de 32 bits, haverá o temido bug de 2038, mas em um sistema Linux de 64 bits, tudo bem.

Tentei usar o date("t"...que deve representar a última data do mês especificado, mas os resultados não coincidem com os mencionados anteriormente neste tópico.

CT14.IT
fonte
2
-2: "$ z" não precisa de aspas -7: ignora os avisos (eles não são impressos com as configurações padrão: não iniciam $z, sem aspas para N) -1: em forvez de while -43 : recebe a entrada conforme solicitado em vez de repetir os anos -3: em joinvez de implode-16: saída direta: for($z=$argv[1];$m++<12;)if(date(N,strtotime(sprintf("%04d-$m-",$z).cal_days_in_month(0,$m,$z)))<2)echo"$m,";+9 se você insistir em não ter vírgula à direita:echo$o=$o?",$m":$m;
Titus
Ahh interpretou mal a pergunta! Pensei que era para todos os anos .. oops: B Obrigado pelas outras sugestões também, as seguirá
CT14.IT 27/10/16
3

PHP, 92 bytes

for($d=new DateTime("$argv[1]-1-1");$i++<12;)$d->modify("1month")->format(w)!=2?:print"$i,";

verificar 12 vezes 1 mês após o primeiro dia do ano é terça-feira Se for, então é o dia anterior ao último dia do mês é uma segunda-feira.

Jörg Hülsermann
fonte
Você poderia usar eco em vez de imprimir e salvar 1
Octopus
1
@ Octopus não está dentro do operador ternário
Jörg Hülsermann 28/10
3

C, 214 bytes

main(int a,char *b[]){for(int x,y,d,m=12;m;m--){y=atoi(b[1]);x=m-1;d=x==1?(y%4==0?(y%100==0?(y%400==0?29:28):29):28):(x==3||x==5||x==10?30:31);if((d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7==1)printf("%d\n",m);}}

Compilar

gcc -std=c99 -o foo foo.c

Ungolfed

Com créditos para os gurus relevantes.

Michael Keith e Tom Craver, do Programa C, para encontrar o dia da semana com data .

Collin Biedenkapp para perguntas e respostas: Como faço para descobrir qual é o último dia do mês?

/* credit to Collin Biedenkapp */
short _get_max_day(short x, int z) {
    if(x == 0 || x == 2 || x == 4 || x == 6 || x == 7 || x == 9 || x == 11)
        return 31;
    else if(x == 3 || x == 5 || x == 8 || x == 10)
        return 30;
    else {
        if(z % 4 == 0) {
            if(z % 100 == 0) {
                if(z % 400 == 0)
                    return 29;
                return 28;
            }
            return 29;
        }
        return 28;
    }
}

main(int argc,char *argv[]) {
 for(int y,d,m=12;m;m--) {
  y=atoi(argv[1]);
  d=_get_max_day(m-1,y);
  /* credit to Michael Keith and Tom Craver */
  if ((d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7 == 1)
    printf("%d\n",m);
 }
}
Steve
fonte
1
E se você virar ifa outra direção, para ter o seu elseretorno 31e, portanto, puder eliminar a grande ==cadeia?
AdmBorkBork 27/10
1
seria melhor se (x == 1) {z part} else if (x == 3 || x == 5 || x == 8 || x == 10) retorne 30 else retorne 31
RosLuP
1
que tal: retornar x == 1? (z% 4 == 0? (z% 100 == 0? (z% 400 == 0? 29: 28): 29): 28) :( x == 3 | | x == 5 || x == 8 || x == 10? 30: 31)
RosLuP
TimmyD + RosLuP: obrigado pelos pontos de retorno (), 100 bytes agora salvos.
Steve #
1
é possível continuar reduzindo até que: u (y, m) {retorne m-1? 30 + ((2773 >> m) & 1): 28+ (y% 4 == 0 && y% 100 || y% 400 == 0);} onde y é o ano e o mês
RosLuP 28/10
3

C, 119 bytes

t=1248700335,m;main(y){for(scanf("%d",&y),t+=y&3||y%25<1&&y&15;m++,(6+y+y/4-y/100+y/400+t)%7||printf("%d,",m),t;t/=7);}

Isso usa uma tabela que contém o deslocamento dos dias da semana do último dia de cada mês para um ano bissexto, codificado em uma palavra de 32 bits assinada usando a base 7. Se não for um ano bissexto, adicionamos 1 ao deslocamento de janeiro (como você pode ver, y&3||y%25<1&&y&15é usado para verificar anos sem dias bissextos). Simplesmente percorremos todos os meses e verificamos se o último dia é segunda-feira. Muito simples, na verdade, sem truques ou truques feios. Aqui está um pouco não-destruído:

t=1248700335,m;
main(y){
  for(
    scanf("%d",&y),t+=y&3||y%25<1&&y&15;
    m++,(6+y+y/4-y/100+y/400+t)%7||printf("%d,",m),t;
    t/=7
  );
}

Eu poderia revisitar isso para reescrevê-lo como uma função para salvar alguns caracteres. O printftambém ocupa um pouco de espaço demais ...

Para s
fonte
O printf ( "% d", m) iria imprimir algo como 1, ou 2, 3, por isso há sempre um '' mais ... Eu prefiro uso somente espaços
RosLuP
Na verdade, eu também prefiro espaços na saída, mas geralmente escrevo minhas soluções C golfadas para que elas não precisem de espaço em branco, para que eu possa usar apenas o espaço em branco da versão semi-golfada quando quiser verificar minha contagem de caracteres .
Fors
3

PHP, 96 95 76 71 69 64 61 bytes

Nota: os números do ano devem ser preenchidos com 4 caracteres, como 0070.

for(;13+$i-=1;)date(N,mktime(0,0,0,1-$i,0,$argn))-1||print$i;

Execute assim:

echo 3385 | php -nR 'for(;13+$i-=1;)date(N,mktime(0,0,0,1-$i,0,$argn))-1||print$i;';echo
> -1-2-10

Explicação

Repete de -1 a -12. Crie a data usando mktime, dia 0(o último dia do mês anterior) e mês 2..13. Formate a data como número do dia e, se o resultado for 1, imprima o número atual. O sinal negativo -é usado como delimitador.

O bug do milênio ataca novamente!

Observe que, com esta versão, o intervalo 0..100é interpretado como 1970..2069. Isso não é problema para o intervalo 0..69, pois as semanas têm um padrão que se repete a cada 400 anos (146097 dias, exatamente 20871 semanas), mas para o intervalo 70..99, 1900 é adicionado ao número do ano, que não é múltiplo de 400. Para corrigir esse problema APENAS para números de 30 anos em um intervalo de 10k, a maneira mais simples é adicionar 400 ao número do ano para impedir a interpretação de 2 dígitos ( +4 bytes ):

for(;13+$i-=1;)date(N,mktime(0,0,0,1-$i,0,$argn+400))-1||print$i;

Tweaks

  • Salva um byte usando !~-$ipara comparar $icom 1( -1binário é negado 0, é logicamente negado é true; todos os outros números são false), portanto, parênteses não são necessários
  • Economizou 19 bytes usando a last day ofYYYY-mnotação para criar a data
  • Salva 5 bytes usando datee em strtotimevez dedate_create
  • Salva 2 bytes contando a partir de números negativos, usando o sinal negativo como delimitador de saída (os números negativos do mês não existem) e também como delimitador na YYYY-mparte da data
  • Salva 5 bytes usando em mktimevez de strtotime. Revertida para usar o dia 0( mktimetambém suporta o mês 13, então 0-13== 31-12)
  • Salva 3 bytes usando -Rpara $argndisponibilizar
aross
fonte
mktimeelimina a necessidade de preencher o ano, não é?
Titus
@ Titus, afiado. Bem, acabei de descobrir que mktimeé contra-intuitivo , porque os argumentos são tomados como INTs. Isso significa que você não pode completar o ano ... então tudo no intervalo 0..100é interpretado como 1970..2070. Isso não é problema para o intervalo, 0..70porque 400 anos têm um número exato de semanas (portanto, os calendários repetem o padrão a cada 400 anos), mas 70..99adicionam 1900 (não um múltiplo de 400!). Portanto, nova versão. tem um bug.
aross 28/10/16
A única solução que vejo para isso agora é $argv[1]+400... a menos que os dias da semana juliano e gregoriano sejam diferentes.
Titus
@ Titus, sim. As regras dizem usar cal Gregoriano
aross
3

Excel, 428 97 96 bytes

Entrada em A1. Valores hexadecimais não separados de saída (janeiro = 0, dezembro = B)

=IF(2=WEEKDAY(DATE(A1+2000,1,31)),0,"")&CHOOSE(WEEKDAY(DATE(A1+2000,3,0)),4,19,6,"3B",8,25,"7A")

Adicionados 10 bytes ("+2000") para permitir o tratamento de datas anteriores a 1990.

Economizou 11 bytes graças a @ Engineer Toast .


Primeira tentativa (428 bytes), emprestando fortemente a solução de @ Adám .

=IF(2=WEEKDAY(DATE(A1,1,31)),1,"")&IF(2=WEEKDAY(EOMONTH(DATE(A1,2,1),0)),2,"")&IF(2=WEEKDAY(DATE(A1,3,31)),3,"")&IF(2=WEEKDAY(DATE(A1,4,30)),4,"")&IF(2=WEEKDAY(DATE(A1,5,31)),5,"")&IF(2=WEEKDAY(DATE(A1,6,30)),6,"")&IF(2=WEEKDAY(DATE(A1,7,31)),7,"")&IF(2=WEEKDAY(DATE(A1,8,31)),8,"")&IF(2=WEEKDAY(DATE(A1,9,30)),9,"")&IF(2=WEEKDAY(DATE(A1,10,31)),"A","")&IF(2=WEEKDAY(DATE(A1,11,30)),"B","")&IF(2=WEEKDAY(DATE(A1,12,31)),"C","")
Wernisch
fonte
Como isso funciona anos antes de 1900? O caso de teste 297 -> Mayretorna 6com esta fórmula. Não deveria ser 4? 1776dá em 7Avez de apenas 8para setembro.
Engineer Toast
Se você obtê-lo para o trabalho, no entanto, provavelmente você pode usar Date(A1,3,0)em vez deEOMONTH(DATE(A1,2,1),0)
Engenheiro Toast
2

Bash + cal, 58 bytes

$ cat t.sh
for A in {1..12};do cal $A $1|grep -qx .....&&echo $A;done
$ bash t.sh 2016
2
10
$
Steve
fonte
+1 - funciona para BSD cal(por exemplo, OSX), mas observe os espaços à direita no GNU cal.
Digital Trauma
2

Python 2, 94 bytes

from datetime import*
lambda y:[m for m in range(1,13)if date(y+(m>11),m%12+1,1).weekday()==1]

repl.it

Uma função sem nome, leva um ano inteiro, gera uma lista dos números do mês [1-12].

Também tentei superar a contagem de bytes com aritmética sem êxito (110 bytes). :

lambda y:map(lambda x,v:(23*((x+2)%13or 1)/9+y-2*(0<x<11)+(x>10)+v/4-v/100+v/400)%7==4,range(12),[y-1]+[y]*11)

Uma função sem nome que retorna uma lista de valores booleanos que representam se os meses [Jan-Dec] terminam em uma segunda-feira

Jonathan Allan
fonte
2

Java 7, 200 249 bytes

import java.util.*;String c(int y){String r="";GregorianCalendar c=new GregorianCalendar();c.setGregorianChange(new Date(1L<<63));c.set(1,y);c.set(2,0);for(int i=0;i++<12;c.add(2,1)){c.set(5,c.getActualMaximum(5));if(c.get(7)==2)r+=i+" ";}return r;}

Em Java, GregorianCalendaré uma mistura entre um calendário gregoriano e juliano. Por esse motivo, o ano 1deu resultados incorretos. Alterar Calendar c=Calendar.getInstance();para GregorianCalendar c=new GregorianCalendar();c.setGregorianChange(new Date(1L<<63));corrigir isso, forçando o uso apenas do calendário gregoriano. Obrigado a @ JonSkeet no stackoverflow.com por me explicar isso.

Ungolfed & código de teste:

Experimente aqui.

import java.util.*;
class M{
  static String c(int year){
    String r = "";
    GregorianCalendar calendar = new GregorianCalendar();
    calendar.setGregorianChange(new Date(Long.MIN_VALUE));
    calendar.set(Calendar.YEAR, year);
    calendar.set(Calendar.MONTH, 0);
    for(int i = 0; i++ < 12; calendar.add(Calendar.MONTH, 1)){
      calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
      if(calendar.get(Calendar.DAY_OF_WEEK) == 2){
        r += i+" ";
      }
    }
    return r;
  }

  public static void main(String[] a){
    System.out.println(c(1));
    System.out.println(c(297));
    System.out.println(c(1776));
    System.out.println(c(2000));
    System.out.println(c(2016));
    System.out.println(c(3385));
  }
}

Saída:

4 12
5 
9 
1 7 
2 10 
1 2 10 
Kevin Cruijssen
fonte
2

C # 6 C #, 171 167 135 bytes

using System;
void d(int n){for(int i=0;++i<13;)if((int)new DateTime(n,i,DateTime.DaysInMonth(n,i)).DayOfWeek==1)Console.Write(i+" ");}

-32 bytes graças a Shebang

Imprima meses como números; com espaço delimitado; com espaço à direita. Agora, esta resposta também funciona para versões anteriores do C #.


Antigo, 167 bytes

using System;using System.Linq;
c(int n)=>string.Join(",",Enumerable.Range(1,12).Where(i=>new DateTime(n,i,DateTime.DaysInMonth(n,i)).DayOfWeek==(DayOfWeek)1));

-4 bytes graças a TimmyD

Os meses de saída são números na sequência de retorno, delimitados por vírgulas

Ungolfed

string c(int n)=>
    string.Join(",",                                        // Join them with commas
        Enumerable.Range(1,12)                              // For 1-12 inclusive
        .Where(                                             // Select only
            i=>new DateTime(n,i,DateTime.DaysInMonth(n,i)   // Get last day of that year-month
            ).DayOfWeek                                     // Get its day of week
            ==(DayOfWeek)1                              // Is Monday
        )
    )
;
Ng do link
fonte
@ TimmyD Sim, mas precisa de elenco explícito. Resposta atualizada
Link Ng
LINQ é divertido, mas este é de 126 bytes: void q(int y){for(int m=1;m<13;m++){if((int)new DateTime(y,m,DateTime.DaysInMonth(y,m)).DayOfWeek==1){Console.WriteLine(m);}}};) Além disso, seria mais curto para lançar o DayOfWeekque intdo que seria para lançar o intparaDayOfWeek
Kade
@Shebang Obrigado. Eu realmente não deveria jogar golfe em uma linha linq --- Somente Jon Skeet pode fazer isso. Veja se tenho tempo para atualizar amanhã. Cansado agora.
Link Ng
Você pode converter este seja um Action<int>para salvar alguns bytes
TheLethalCoder
2

Ruby, 54 + 6 = 60 bytes

λ cat monday.rb
p (1..12).select{|m|Date.new($*[0].to_i,m,-1).monday?}
λ ruby -rdate monday.rb 2016
[2, 10]

6 bytes para -rdatena linha de comando para obter a classe Date da biblioteca padrão.

Explicação: muito simples, graças à excelente Dateclasse do Ruby stdlib . Não apenas possui métodos como monday?, tuesday?etc, o construtor terá números negativos para qualquer campo do ano passado para significar 'conte esse campo de trás para frente a partir do final do período representado pelo campo anterior'. $*é uma abreviação de ARGV, então $*[0]é uma maneira rápida de obter o primeiro argumento de linha de comando.

filosofia
fonte
2

PHP, 84 bytes

for($m=1;$m++<14;){if(strftime('%w',strtotime($argv[1]."-$m-1"))==2)echo($m-1)." ";}

Meu primeiro código de golfe. Este é o PHP mais curto até agora nesta questão.

Edição: parece não funcionar para o ano 1. Vou ter que descobrir o porquê, mas agora eu tenho que ir.

Polvo
fonte
1
Eu diria "Bem-vindo ao PPCG!" mas você está registrado aqui há mais tempo do que eu! : D Bom primeiro golfe.
AdmBorkBork 27/10
Seu erro é que você cria 1-13-1 e 1-14-1 para o ano 1 <13 é suficiente. Se você resolver isso, você pode remover os suportes unnessary no momento e pensar em usar o operador ternário
Jörg Hülsermann
Isso deve fixo seus problemasfor(;$m++<12;)strftime("%w",strtotime($argv[1]+($m/12^0)."-".($m%12+1)."-1"))!=2?:print"$m ";
Jörg Hülsermann
2

R, 106 99 95 83 78 77 74 bytes

g=function(x)which(format(seq(as.Date(paste0(x,-2,-1)),,'m',12)-1,"%u")<2)

A sequência dos últimos dias de cada mês é dada por seq(as.Date(paste0(x,-2,-1)),,'m',12)-1:

  • paste0força -2 e -1 a caracteres. Se a xera 2016, por exemplo, paste0(x,-2,-1)"2016-2-1", que é então convertido para o 01 de fevereiro de 2016 por as.Date.

  • seqaplicado a um objeto POSIXct ou Date é seq(from, to , by, length.out): aqui tonão é fornecido, byé fornecido como 'm'correspondido 'month'graças à correspondência parcial e, length.outé claro , é 12.

  • A sequência resultante é o primeiro dia dos 12 meses a partir de fevereiro do ano em questão. -1nos dá o último dia dos 12 meses a partir de janeiro do ano em questão.

Casos de teste:

> g(1)
[1]  4 12
> g(25)
[1] 3 6
> g(297)
[1] 5
> g(2000)
[1] 1 7
> g(2016)
[1]  2 10
> g(3385)
[1]  1  2 10
> g(9999)
[1] 5

Versão antiga em 95 bytes, exibindo os nomes dos meses em vez de apenas seus números:

g=function(x)format(S<-seq(as.Date(sprintf("%04i-02-01",x)),,'m',12)-1,"%B")[format(S,"%u")==1]
plannapus
fonte
Esta resposta é simplesmente brilhante. Eu não tinha idéia de sequm método para Date-objects e isso resolve o problema de as.Datenão tratar anos acima 10000na minha resposta excluída.
Billywob
@ Billywob sim seq.Datee seq.POSIXtsão bastante impressionantes: eles podem até processar comandos como seq(time1, time2, by="10 min")ou seq(date1, date2, by="quarter"). Muito útil ao plotar uma série temporal.
plannapus
2

Japt, 24 bytes

Do1 £Ov"Ð400+U"+X e ¥2©X

Teste online! Gera uma matriz de números,falseno lugar de meses que não terminam na segunda-feira.

Houve um erro no intérprete que não me permitiu usar Ðno corpo da função £. Após a correção do bug e outra adição de recurso, são 18 bytes no commit atual:

Do1@Ð400+UX e ¥2©X
ETHproductions
fonte
1

Java, 143 129 bytes

Isso usa a nova API de horário do Java 8.

y->{String s="";for(int m=0;++m<13;)if(java.time.YearMonth.of(y,m).atEndOfMonth().getDayOfWeek().ordinal()==0)s+=m+" ";return s;}

Saída

Observe que cada linha tem um espaço extra no final.

4 12 
5 
9 
1 7 
2 10 
1 2 10 

Ungolfed and testing

import java.time.*;
import java.util.function.*;

public class Main {
    public static void main (String[] args) {
        IntFunction<String> func = year -> {
          String result = "";
          for (int month=1; month <= 12; month++) {
            if (YearMonth.of(year, month).atEndOfMonth().getDayOfWeek().ordinal() == 0) {
              result += month + " ";
            }
          }
          return result;
        };
        System.out.println(func.apply(1));
        System.out.println(func.apply(297));
        System.out.println(func.apply(1776));
        System.out.println(func.apply(2000));
        System.out.println(func.apply(2016));
        System.out.println(func.apply(3385));
    }
}

Barbear

  1. 143 a 129 bytes: use DayOfWeek::ordinalpara comparar com uma constante numérica em vez da constante enum.
    Obrigado @ TimmyD pela idéia geral, se não a solução exata! ;-)
Olivier Grégoire
fonte
@ TimmyD, infelizmente, é um enum. getValue()Porém, ele possui um método que salvaria alguns bytes.
Celos
O @Celos ordinal()economiza mais 1 byte em comparação com getValue(), mesmo que seja sugerido que nunca o use.
Olivier Grégoire
sim, bom pensamento. Publiquei meu comentário sem primeiro atualizar, para não ver sua resposta e edição.
Celos
1

GNU awk, 80 bytes

{for(;m<13;a=mktime($0" "++m" 1 9 0 0")){if(strftime("%w",a-8e4)~1){print m-1}}}

Exemplo

$ gawk '{for(;m<13;a=mktime($0" "++m" 1 9 0 0")){if(strftime("%w",a-8e4)~1){print m-1}}}' <<<2016
2
10
$
Steve
fonte