Senin Terakhir


27

Senin, 31 Oktober, adalah Halloween. Dan itu membuat saya berpikir - Saya ingin tahu bulan apa di hari terakhir bulan itu yang juga menjadi hari Senin?

Memasukkan

  • Bilangan bulat positif dalam format apa pun yang mewakili satu tahun 10000 > y > 0,.
  • Input dapat diisi dengan nol (misalnya, 0025untuk tahun 25) jika diperlukan.

Keluaran

  • Daftar bulan dalam tahun itu di mana hari terakhir bulan itu adalah hari Senin.
  • Ini bisa berupa nama bulan (mis., January, March, October), Atau nama pendek ( Jan, Mar, Oct), atau angka ( 1, 3, 10), sebagai baris terpisah atau daftar atau dibatasi, dll., Asalkan tidak ambigu bagi pembaca.
  • Format output harus konsisten:
    • Untuk input semua tahun (artinya, Anda tidak dapat menampilkan nama bulan untuk beberapa input, dan angka bulan untuk input lainnya)
    • Serta konsisten per keluaran (yang berarti, Anda tidak bisa output 1untuk Januarydi output yang sama seperti Juluntuk July)
    • Pada dasarnya, pilih satu format dan pertahankan.

Aturan

  • Asumsikan kalender Gregorian untuk input / output, bahkan hingga y = 1.
  • Tahun kabisat harus diperhitungkan dengan benar (sebagai pengingat: setiap tahun dapat dibagi dengan 4, kecuali tidak tahun dibagi dengan 100, kecuali juga dibagi oleh 400 - 1700, 1800, 1900 semua bukan tahun kabisat, tetapi tahun 2000 adalah).
  • Anda dapat menggunakan alat penghitung tanggal atau built-in apa saja yang Anda suka.
  • Program lengkap atau fungsi dapat diterima. Jika suatu fungsi, Anda dapat mengembalikan output daripada mencetaknya.
  • Celah standar dilarang.
  • Ini adalah sehingga semua aturan golf biasa berlaku, dan kode terpendek (dalam byte) menang.

Contohnya

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

Papan peringkat



1
Terkait tetapi tidak duplikat atau?
ElPedro

@ ElPedro Terkait tetapi tidak duplikat. Yang pertama tidak memungkinkan built-in dan meminta kombo tanggal / hari yang tetap (Jumat tanggal 13), sedangkan yang kedua meminta hari Minggu terakhir setiap bulan, dibatasi antara 1900 hingga 3015.
AdmBorkBork

Maaf @TimmD. Kesalahpahaman saya tentang komentar Anda.
ElPedro

1
@ ElPedro Tidak masalah! Saya lebih suka memiliki pertanyaan dan menjelaskannya, daripada tidak memiliki pertanyaan dan memiliki sesuatu yang tidak jelas.
AdmBorkBork

Jawaban:


2

Dyalog APL dengan dfns 's kal , Versi 15.0: 22; Versi 16.0: 19 byte

Fungsi cal dilengkapi dengan instalasi default, cukup masukkan )copy dfns.

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

minta (ratakan)

⎕{... input numerik sebagai argumen kiri ke fungsi anonim berikut, dengan mengambil masing-masing nilai sisi kanan sebagai argumen kanan

⍵/⍨ argumen jika (memberikan daftar kosong jika tidak)

2= dua (yaitu hari Minggu dan Senin) sama dengan

penghitungan

angka dalam

⊢⌿ baris paling bawah dari

cal kalender untuk

⍺⍵ tahun kiri-argumen, bulan kanan-argumen, yang terakhir adalah

⍳12 1 hingga 12

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

indeks mana

2= dua sama dengan (yaitu hari Minggu dan Senin)

⎕{... input numerik sebagai argumen kiri ke fungsi anonim berikut, dengan mengambil masing-masing nilai sisi kanan sebagai argumen kanan

penghitungan

angka dalam

⊢⌿ baris paling bawah dari

cal kalender untuk

⍺⍵ tahun kiri-argumen, bulan kanan-argumen, yang terakhir adalah

⍳12 1 hingga 12


19

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

Lihat bu, tidak ada built-in!

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]

Berikut adalah versi ES6 107-byte:

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)

Dan inilah upaya saya sebelumnya, 123 113 byte 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]

Penjelasan

Hari dalam minggu tahun tertentu dihitung seperti ini:

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

Dengan kata lain:

  • Ambil y.
  • Tambahkan jumlah tahun ke-4 sebelum y( y>>2).
  • Kurangi angka 100 tahun sebelumnya y( y/100|0).
  • Tambahkan kembali dalam jumlah 400 tahun sebelumnya y; ini 1/4 dari y/100|0, jadi kami gunakan *3/4|0.

Kemudian kita memodulasi hasilnya dengan 7. Jika kita membiarkan 0hari Minggu berarti, 1berarti Senin, dll, hasilnya sesuai dengan hari minggu 31 Desember tahun itu. Karena itu, untuk bulan Desember, kami ingin memeriksa apakah hasilnya 1. Ini memberi kita karakter terakhir dalam string.

Hari terakhir bulan November adalah 31 hari sebelum hari terakhir bulan Desember. Ini berarti bahwa untuk hari terakhir bulan November menjadi hari Senin, 31 Desember harus menjadi (1 + 31) % 7 = 4= Kamis.

Prosedur ini diulang sampai kami kembali ke bulan Maret (a 3). Ada atau tidak ada hari kabisat, hari terakhir bulan Februari adalah 31 hari sebelum hari terakhir bulan Maret, jadi kita juga bisa menghitungnya (3 + 31) % 7 = 6. Bagian yang sulit adalah menemukan nilai yang benar untuk bulan Januari:

  • Jika ini adalah tahun kabisat, hari terakhir bulan Januari adalah 29 hari sebelum hari terakhir bulan Februari, menghasilkan (6 + 29) % 7 = 0.
  • Kalau tidak, itu adalah 28 hari sebelum hari terakhir bulan Februari, menghasilkan (6 + 28) % 7 = 6.

Kami dapat menghitung apakah ini tahun kabisat dengan potongan berikut:

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

Ini memberi 0jika ybukan tahun kabisat, dan bilangan bulat positif sebaliknya. Ini membawa kita ke

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

untuk menghitung hari untuk bulan Januari. Namun, kami dapat melakukan yang lebih baik dengan membalik kondisi:

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

Karena hasil falsy selalu 0, kita dapat menguranginya menjadi

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

menghemat satu byte lagi yang berharga.

Menyatukan semuanya, kami mengulangi masing-masing karakter dalam string, memeriksa apakah masing-masing sama dengan hari di minggu 31 Desember. Kami menyimpan indeks yang cocok, mengembalikan array ini pada akhirnya. Dan itu adalah bagaimana Anda melakukan perhitungan tahun kabisat tanpa built-in.


Owww ... Otak saya, apakah Anda memperhitungkan tahun kabisat di semua itu?
Magic Gurita Guci

2
@carusocomputing Itulah gunanya !(y%4)*y%100|!(y%400). setiap tahun dapat dibagi dengan 4, kecuali bukan tahun yang dapat dibagi dengan 100, kecuali juga dapat dibagi oleh 400
mbomb007

Semoga y+(y>>2)+(z=y/25>>2)+(z>>2)masih menghemat satu byte.
Neil

@Neil Terima kasih, tapi saya menemukan cara yang lebih baik :-)
ETHproduksi

Bagus; Saya menyimpan 6 byte pada port Batch saya menggunakan (y*5/4-(y/100)*3/4).
Neil

11

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

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

Disimpan 2 4 6 bytes berkat @ETHproductions. Menyimpan byte lain dengan mengeluarkan bulan dalam urutan terbalik.


Saya pikir Anda dapat menyimpan 2 byte dengan menaruhnya tanpa .keys():y=>[for(_ of(m=0,Array(12)))if(new Date(y+400,++m).getDay()==2)m]
ETHproduksi

@ ETHproductions Saya dapat menyimpan byte lebih lanjut dengan membalik urutan!
Neil

Pesanan terbalik baik-baik saja. Memformat output bukan bagian yang menarik dari tantangan ini.
AdmBorkBork

Apa kebijakan kami tentang Pemahaman Array sekarang setelah mereka dihapus dari spek?
MayorMonty

Anda dapat menyimpan 2 byte lagi dengan melompati Array(12)semuanya: y=>[for(_ of(m=0,1e11+""))if(new Date(y+400,++m).getDay()==2)m]
ETHproduksi

8

MySQL, 183 134 129 106 byte

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)))

Ganti 2016dengan tahun yang diinginkan. Menjalankan.

Rev 2: Menggunakan help_topicstabel dalam instalasi default alih-alih membuat tabel sementara.

Rev.3: Trik yang diadopsi aross- dan perhatikan saya juga bisa menghilangkan tanda kutip untuk "-1".
Namun, -1diperlukan di MySQL: Saya perlu tanggal penuh.

Rev.4: Pembatasan m BETWEEN 1 AND 12dapat dilakukan sebagai m>0 AND m<13(-6), tetapi tidak diperlukan sama sekali - nilai yang tidak valid akan diabaikan; peringatan akan dihitung tetapi tidak terdaftar.


Anda benar-benar membutuhkan tabel shema mysql? mariadb.com/kb/en/mariadb/mysqlhelp_topic-table
Jörg Hülsermann

@ JörgHülsermann Saya tidak mengerti maksud Anda.
Titus

Haruskah FROM help_topictanpa mysql.kerja? Saya belum mencobanya
Jörg Hülsermann

@ JörgHülsermann hanya jika Anda menambahkan USE mysql;database yang benar entah bagaimana harus dipilih.
Titus

5

Perl, 64 byte

Termasuk +1 untuk -n

Berikan masukan pada 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

5

Batch, 160 152 byte

@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%%

Port of @ ETHproduksi jawaban. Dengan singkatan bulan untuk 197 189 byte:

@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

4

J, 48 34 33 byte

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

Disimpan 15 byte dengan bantuan dari @ Adám .

Menggunakan kalender bawaan untuk menghasilkan array string yang mewakili bulan, lalu mem-parsing setiap string untuk menentukan apakah Senin terakhir adalah hari terakhir dalam sebulan. Output setiap bulan sebagai jumlah bulan masing-masing. Artinya, Jan = 0, Feb = 1, ..., Dec = 11.

Output dari calendaris

   _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               │                     │                     │
└─────────────────────┴─────────────────────┴─────────────────────┘

Pemakaian

   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

Penjelasan

[: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

tunggu, apakah kalender benar-benar menampilkan seni ascii?
Lemon Destructible

@DestructibleWatermelon Tepatnya, format output calendaradalah array dari 12 kotak di mana setiap kotak berisi array karakter 2d
mil

Saya bahkan tidak tahu bagaimana melakukan "masing-masing" dalam J, tetapi ini sudah jauh lebih pendek: I.7=;#&.>".&.>,&.>_2{.&.>calendar 2016Jika Anda menggabungkan semua "kurang terbuka", Anda harus bisa membuatnya cukup singkat.
Adám

@ Adám Terima kasih, ini menggunakan metode yang lebih baik tapi itu bukan kata kerja dalam J. Saya pikir itu masih akan membantu
mil

Niat saya hanya untuk menginspirasi. Saya tahu itu bukan kata kerja.
Adám

4

Mathematica, 62 57 byte

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

Fungsi anonim. Mengambil nomor sebagai input dan mengembalikan daftar daftar elemen tunggal angka sebagai output. Sejujurnya saya tidak yakin lagi bagaimana cara kerjanya.


4

Perl + cal, 46 byte

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

Contoh:

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

2







10


$

1
Sebenarnya, ini perl + cal, bukan hanya perl :-p. Misalnya, mesin Windows saya memiliki perl, tetapi ini tidak akan berfungsi di sana.
philomory

Titik adil, memperbarui ini dan upaya bash saya.
steve

4

Java 7,186 182 172 byte

Terima kasih kepada kevin untuk menyimpan 4 byte
Terima kasih kepada @cliffroot karena telah menghemat 10 byte

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;}

ungolfed

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;
     }

Versi ini disediakan oleh @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;   }
    }

sampel keluaran

1 1 0 0 0 0 0 0 0 1 0 0(for input 3385)

1
Setelah saya menulis jawaban saya saya tahu menghitung semuanya sendiri akan lebih pendek .. :) Btw, Anda dapat golf n%4==0untuk n%4<1; n%400==0ke n%400<1dan int c=...;int[]b=...,a=...ke int c=...,b[]=...,a[]=....
Kevin Cruijssen

1
bdan adapat didefinisikan pada intbagian seperti ini: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;}beberapa byte disimpan
cliffroot

1
juga dapat mengubah bke b[]={3,(n%4<1&n%100>0)|n%400<1?1:0,3,2,3,2,3,3,2,3,2,3}dan i+30ke i+28untuk 2 byte lagi
cliffroot

1
dan 3 byte lainnyaint[]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

3

Python 2, 100 byte

Ugh. Matematika dengan tanggal tidak sesederhana yang saya inginkan.

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]

Cobalah online

Sama panjang:

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]

Saya bahkan tidak akan mencoba Python dengan yang ini. Usaha yang bagus.
ElPedro

3

MATL , 21 byte

12:"G@QhO6(YO9XO77=?@

Bulan ditampilkan sebagai angka.

Cobalah online! Atau verifikasi semua kasus uji .

Penjelasan

Ini menggunakan fungsi bawaan konversi tanggal. Untuk tahun tertentu ia menguji hari terakhir bulan mana adalah Senin.

Alih-alih secara eksplisit menentukan hari terakhir bulan k(yang mungkin 28, 29, 30 atau 31), kami menentukan 0hari ke-bulan k+1, yang setara dan tidak tergantung pada bulan atau tahun.

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)

3

Utilitas Bash + GNU, 56 byte

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

Tampaknya membutuhkan dateversi 8.25. Versi 8.23 ​​di Ideone tidak memotongnya.


3

Excel, 537 byte

Karena - Anda tahu - Excel!

Mengambil tahun input dalam A1. Mengembalikan daftar bulan heksadesimal; 1 = Januari, C = Desember. Karena setiap bulan adalah satu digit, tidak diperlukan separator.

=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","")

Contoh: A1 berisi 2016. B1 berisi rumus di atas, dan ditampilkan sebagai 2A, artinya Februari dan Oktober.


3

PHP, 109 180 159 byte

for($z=$argv[1];$m++<12;)if(date(N,strtotime(sprintf("%04d-$m-",$z).cal_days_in_month(0,$m,$z)))<2)echo"$m,";
  • Keluaran tahun yang disediakan, tidak semuanya (... selalu baca pertanyaannya)
  • Pemberitahuan yang diabaikan (terima kasih Titus)
  • Ubah whilemenjadi forsekarang satu tahun (sekali lagi, terima kasih Titus)

2 tahun

$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)."
":"";}

Mendukung semua tahun dari titik ke 10.000, juga menyingkirkan peringatan var tidak terdefinisi yang tidak saya sadari pada satu PC. Ya itu lebih lama dari versi yang lama, tetapi lebih kuat.

1 tahun

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)."
":"";}

Jika berjalan pada Windows atau sistem 32bit akan ada bug 2038 yang ditakuti, tetapi pada sistem linux 64bit tidak apa-apa.

Saya memang mencoba menggunakan date("t"...yang dimaksudkan untuk mewakili tanggal terakhir dari bulan yang diberikan, tetapi hasilnya tidak cocok dengan yang disebutkan sebelumnya di utas ini.


2
-2: "$ z" tidak perlu tanda kutip -7: abaikan pemberitahuan (tidak dicetak dengan pengaturan default: jangan init $z, tidak ada tanda kutip untuk N) -1: forbukannya while -43 : ambil input seperti yang diminta alih-alih berulang tahun -3: joinbukannya implode-16: output langsung: 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 jika Anda bersikeras tidak memiliki tanda koma:echo$o=$o?",$m":$m;
Titus

Ahh salah baca pertanyaannya! Pikir itu selama bertahun-tahun .. oops: B Terima kasih atas saran lain juga, akan menerimanya
CT14.IT

3

PHP, 92 Bytes

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

periksa 12 kali 1 bulan setelah hari pertama tahun adalah hari Selasa. Jika demikian maka hari sebelum hari terakhir dalam bulan adalah Senin.


Anda dapat menggunakan gema alih-alih mencetak dan menyimpan 1
Octopus

1
@Octopus tidak di dalam Operator ternary
Jörg Hülsermann

3

C, 214 byte

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);}}

Menyusun

gcc -std=c99 -o foo foo.c

Tidak disatukan

Dengan kredit untuk guru yang relevan.

Michael Keith dan Tom Craver untuk Program C mencari tanggal hari dalam seminggu .

Collin Biedenkapp untuk T&J: Bagaimana cara mengetahui apa hari terakhir bulan itu?

/* 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);
 }
}

1
Bagaimana jika Anda membalikkan ifarah Anda yang lain, agar Anda elsekembali 31, dan karenanya Anda bisa menghilangkan ==rantai besar ?
AdmBorkBork

1
akan lebih baik jika (x == 1) {z bagian} lain jika (x == 3 || x == 5 || x == 8 || x == 10) mengembalikan 30 yang lain mengembalikan 31
RosLuP

1
bagaimana dengan: return 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: terima kasih atas pengembalian () poin, 100 byte sekarang disimpan.
steve

1
adalah mungkin untuk terus mengurangi akhirnya sampai ini: u (y, m) {return m-1? 30 + ((2773 >> m) & 1): 28+ (y% 4 == 0 && y% 100 || y% 400 == 0);} di mana y adalah tahun dan m bulan
RosLuP

3

C, 119 byte

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);}

Ini menggunakan tabel yang berisi offset hari kerja dari hari terakhir setiap bulan untuk tahun kabisat, disandikan dalam kata 32-bit yang ditandatangani menggunakan basis 7. Jika ini bukan tahun kabisat, kami menambahkan 1 ke offset Januari (seperti yang dapat Anda lihat y&3||y%25<1&&y&15 digunakan untuk memeriksa selama bertahun-tahun tanpa hari kabisat). Kemudian kami cukup memutari setiap bulan dan memeriksa apakah hari terakhir adalah hari Senin. Sebenarnya cukup sederhana, tidak ada retas atau trik jelek. Ini sedikit ungolfed:

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
  );
}

Saya mungkin mengunjungi kembali ini untuk menulis ulang sebagai fungsi untuk menyimpan beberapa karakter. The printfjuga memakan terlalu banyak ruang ...


Printf ("% d,", m) akan mencetak sesuatu sebagai 1, atau 2, 3, jadi selalu ada satu ',' lagi ... Saya lebih suka menggunakan spasi saja
RosLuP

Memang, saya juga lebih suka spasi di output sebenarnya, tapi saya biasanya menulis solusi C golf saya sehingga mereka tidak memerlukan spasi, jadi saya bisa nuke semua spasi putih dari versi setengah-golf saya ketika saya ingin memeriksa jumlah karakter saya .
Fors

3

PHP, 96 95 76 71 69 64 61 byte

Catatan: angka tahun harus diisi hingga 4 karakter 0070.

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

Jalankan seperti ini:

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

Penjelasan

Iterasi dari -1 hingga -12. Buat tanggal menggunakan mktime, hari 0(hari terakhir bulan sebelumnya) dan bulan 2..13. Format tanggal sebagai nomor hari , dan jika hasilnya 1, cetak nomor saat ini. Tanda negatif -digunakan sebagai pembatas.

Bug Milenium Menyerang Lagi!

Perhatikan bahwa dengan versi ini, kisaran 0..100ditafsirkan sebagai 1970..2069. Ini bukan masalah untuk rentang 0..69, karena minggu memiliki pola yang berulang setiap 400 tahun (146097 hari, tepatnya 20871 minggu), tetapi untuk rentang 70..99, 1900 ditambahkan ke nomor tahun, yang bukan kelipatan 400. Untuk memperbaikinya masalah itu HANYA untuk angka 30 tahun dalam kisaran 10k, cara paling sederhana adalah menambahkan 400 ke nomor tahun untuk mencegah penafsiran 2 digit ( +4 byte ):

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

Tweaks

  • Menyimpan byte dengan menggunakan !~-$iuntuk membandingkan $idengan 1( -1binary dinegasikan 0, secara logika dinegasikan adalah true; setiap nomor lainnya adalahfalse ), sehingga tanda kurung tidak diperlukan
  • Disimpan 19 byte dengan menggunakan last day ofYYYY-mnotasi untuk membuat tanggal
  • Disimpan 5 byte dengan menggunakan datedan strtotimebukannyadate_create
  • Disimpan 2 byte dengan menghitung dari angka negatif, menggunakan tanda negatif sebagai pembatas output (angka bulan negatif tidak ada) dan juga sebagai pembatas di YYYY-mbagian tanggal
  • Disimpan 5 byte dengan menggunakan mktimebukan strtotime. Dikembalikan ke penggunaan hari 0( mktimejuga mendukung bulan 13, jadi 0-13== 31-12)
  • Disimpan 3 byte dengan menggunakan -Ragar $argntersedia

mktimemenghapus keharusan untuk menutup tahun, bukan?
Titus

@Itus, tajam. Yah aku hanya tahu bahwa mktimeadalah kontra-intuitif , karena argumen diambil sebagai INTs. Itu berarti Anda tidak dapat menghitung tahun ... jadi semua yang ada dalam jangkauan 0..100diartikan sebagai 1970..2070. Itu bukan masalah untuk rentang 0..70karena 400 tahun memiliki jumlah minggu yang tepat (jadi kalender ulangi pola setiap 400 tahun), tetapi 70..99tambahkan 1900 (bukan kelipatan 400!). Oleh karena itu baru ver. memiliki bug.
aross

Satu-satunya solusi yang saya lihat untuk saat ini adalah $argv[1]+400... kecuali hari kerja Julian dan Gregorian berbeda.
Titus

@Itus, ya. Aturan mengatakan gunakan Gregorian cal
aross

3

Excel, 428 97 96 byte

Masukan dalam A1. Menghasilkan nilai Hexadecimal yang tidak dipisahkan (Januari = 0, Desember = B)

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

Menambahkan 10 byte ("+2000") untuk memungkinkan penanganan tanggal pra-1990.

Disimpan 11 byte berkat @ Engineer Toast .


Upaya pertama (428 bytes), banyak meminjam dari solusi @ 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","")

Bagaimana cara kerjanya pada tahun lebih awal dari tahun 1900? Kasing uji 297 -> Maykembali 6dengan rumus ini. Bukankah seharusnya 4? 1776memberi 7Abukan hanya 8untuk bulan September.
Engineer Toast

Namun, jika Anda berhasil, Anda mungkin dapat menggunakannya Date(A1,3,0)sebagai gantinyaEOMONTH(DATE(A1,2,1),0)
Engineer Toast

2

Bash + cal, 58 byte

$ cat t.sh
for A in {1..12};do cal $A $1|grep -qx .....&&echo $A;done
$ bash t.sh 2016
2
10
$

+1 - berfungsi untuk BSD cal(mis. OSX), tetapi perhatikan spasi tambahan di GNU cal.
Digital Trauma

2

Python 2, 94 byte

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

Fungsi yang tidak disebutkan namanya, membutuhkan tahun integer, menampilkan daftar angka bulan [1-12] .

Saya juga mencoba untuk mengalahkan jumlah byte dengan aritmatika tanpa hasil (110 byte). :

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)

Fungsi tanpa nama yang mengembalikan daftar nilai boolean yang mewakili jika bulan [Jan-Des] berakhir pada hari Senin


2

Java 7, 200 249 byte

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;}

Di Jawa, GregorianCalendaradalah campuran antara kalender Gregorian dan Julian. Karena itu, tahun 1memberikan hasil yang salah. Mengubah Calendar c=Calendar.getInstance();untuk GregorianCalendar c=new GregorianCalendar();c.setGregorianChange(new Date(1L<<63));memperbaikinya dengan memaksakan penggunaan kalender Gregorian saja. Terima kasih kepada @JonSkeet di stackoverflow.com untuk menjelaskan ini kepada saya.

Tidak digabungkan & kode uji:

Coba di sini.

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));
  }
}

Keluaran:

4 12
5 
9 
1 7 
2 10 
1 2 10 

2

C # 6 C #, 171 167 135 byte

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 byte berkat Shebang

Cetak bulan sebagai angka; dengan ruang terbatas; dengan ruang tambahan. Sekarang jawaban ini juga berfungsi untuk versi C # yang lebih lama.


Lama, 167 byte

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 byte terima kasih kepada TimmyD

Bulan keluaran adalah angka dalam string kembali, dibatasi koma

Tidak disatukan

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
        )
    )
;

@ TimmyD Ya tapi perlu pemeran eksplisit. Jawaban diperbarui
Tautan Ng

LINQ menyenangkan tapi ini 126 byte:; 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);}}}) Juga, akan lebih pendek untuk melemparkan DayOfWeekke intdaripada untuk melemparkan intkeDayOfWeek
Kade

@ Shebang, terima kasih. Saya benar-benar tidak boleh bermain golf dalam satu baris linq --- Hanya Jon Skeet yang bisa melakukannya. Lihat apakah saya punya waktu untuk memperbarui besok. Lelah sekarang.
Tautan Ng

Anda dapat mengonversikan ini menjadi sebuah Action<int>untuk menyimpan beberapa byte
TheLethalCoder

2

Ruby, 54 + 6 = 60 byte

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

6 byte untuk -rdatepada baris perintah untuk mendapatkan kelas Date dari library standar.

Penjelasan: cukup mudah berkat Datekelas hebat stdlib Ruby . Tidak hanya memiliki metode seperti monday?,, tuesday?dll, konstruktor akan mengambil angka negatif untuk bidang apa pun tahun lalu untuk berarti 'hitung bidang ini mundur dari akhir periode yang diwakili oleh bidang sebelumnya'. $*adalah singkatan ARGV, jadi $*[0]adalah cara cepat untuk mendapatkan argumen baris perintah pertama.


2

PHP, 84 byte

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

Golf Kode pertamaku. Ini adalah PHP terpendek sejauh ini untuk pertanyaan ini.

EDIT: sepertinya tidak berfungsi untuk tahun 1. Saya harus mencari tahu mengapa, tapi sekarang saya harus pergi.


1
Saya akan mengatakan "Selamat datang di PPCG!" tetapi Anda telah terdaftar di sini lebih lama dari yang saya miliki! : D Golf pertama yang bagus.
AdmBorkBork

Kesalahan Anda adalah Anda membuat 1-13-1 dan 1-14-1 untuk tahun 1 <13 sudah cukup. Jika Anda menyelesaikan ini, Anda dapat menghapus tanda kurung yang tidak sehat pada saat itu dan berpikir tentang menggunakan operator ternary
Jörg Hülsermann

Ini harus memperbaiki masalah Andafor(;$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 byte

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

Urutan hari-hari terakhir setiap bulan diberikan oleh seq(as.Date(paste0(x,-2,-1)),,'m',12)-1:

  • paste0coerces -2 dan -1 ke karakter. Jika xitu 2016 misalnya, paste0(x,-2,-1)berikan "2016-2-1"yang kemudian dikonversi ke 1 Februari 2016 oleh as.Date.

  • seqditerapkan pada POSIXct atau objek Date adalah seq(from, to , by, length.out): di sini totidak diberikan, bydiberikan sebagaimana 'm'dicocokkan dengan 'month'berkat pencocokan parsial, danlength.out tentu saja 12.

  • Urutan yang dihasilkan adalah hari pertama dari 12 bulan dimulai dengan Februari tahun yang bersangkutan. -1memberi kami pada hari terakhir 12 bulan dimulai dengan Januari tahun yang bersangkutan.

Kasus uji:

> 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

Versi lama pada 95 byte, menghasilkan nama bulan, bukan hanya angka-angkanya:

g=function(x)format(S<-seq(as.Date(sprintf("%04i-02-01",x)),,'m',12)-1,"%B")[format(S,"%u")==1]

Jawaban ini sangat brilian. Saya tidak tahu seqpunya metode untuk- Dateobjek dan ini memecahkan masalah as.Datetidak menangani tahun 10000di atas dalam jawaban saya yang dihapus.
Billywob

@ Billywob ya seq.Datedan seq.POSIXtcukup mengesankan: mereka bahkan dapat memproses perintah seperti seq(time1, time2, by="10 min")atau seq(date1, date2, by="quarter"). Sangat berguna saat merencanakan rangkaian waktu.
plannapus

2

Japt, 24 byte

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

Uji secara online! Output array angka, denganfalse menggantikan bulan yang tidak berakhir pada hari Senin.

Ada bug di interpreter yang tidak memungkinkan saya untuk digunakan Ðdi badan fungsi £. Setelah perbaikan bug dan penambahan fitur lainnya, ini adalah 18 byte di komit saat ini:

Do1@Ð400+UX e ¥2©X

1

Java, 143 129 byte

Ini menggunakan API waktu baru 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;}

Keluaran

Perhatikan bahwa setiap baris memiliki ruang ekstra di akhir.

4 12 
5 
9 
1 7 
2 10 
1 2 10 

Tidak disatukan dan diuji

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));
    }
}

Bercukur

  1. 143 hingga 129 byte: digunakan DayOfWeek::ordinaluntuk membandingkan dengan konstanta numerik alih-alih konstanta enum.
    Terima kasih @TimmyD untuk ide umum jika bukan solusi yang tepat! ;-)

@TimmyD sedih, ini enum. Itu memang memiliki getValue()metode, yang akan menghemat beberapa byte.
Celos

@Celos ordinal()menyimpan 1 byte lebih banyak dibandingkan getValue(), meskipun disarankan untuk tidak pernah menggunakannya.
Olivier Grégoire

ya, pemikiran yang bagus. Saya memposting komentar saya tanpa menyegarkan terlebih dahulu, jadi saya tidak melihat balasan dan edit Anda.
Celos

1

GNU awk, 80 byte

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

Contoh

$ gawk '{for(;m<13;a=mktime($0" "++m" 1 9 0 0")){if(strftime("%w",a-8e4)~1){print m-1}}}' <<<2016
2
10
$
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.