Persentase hari kerja dalam sebulan

11

Diberikan satu tahun dan satu bulan, cari tahu persentase hari kerja di bulan tersebut. Hari kerja adalah Senin hingga Jumat tanpa mempertimbangkan hari libur atau hal-hal khusus lainnya. Kalender Gregorian digunakan.

Memasukkan

Setahun dan bulan dalam format ISO 8601 (YYYY-MM). Tahun selalu memiliki empat digit, bulan selalu memiliki dua digit. Tahun yang diberikan tidak akan sebelum 1582.

Keluaran

Output adalah persentase hari kerja (sesuai dengan definisi di atas) pada bulan yang diberikan, dibulatkan menjadi bilangan bulat. Tidak ada tanda persen atau angka fraksional yang mengikuti.

Contoh 1

Input                Output

2010-05              68

Contoh 2

Input                Output

2010-06              73

Contoh 3

Input                Output

1920-10              68

Contoh 4

Input                Output

2817-12              68

Seminggu telah berlalu, jawaban telah diterima. Untuk yang penasaran, ukuran pengiriman yang kami dapatkan di kontes kami:

129 - Z shell
174 - VB.NET
222 - C
233 - C
300 - C

Serta solusi kami sendiri (tidak disimpan):

  75 - PowerShell
  93 - Ruby
112 - Shell Bourne

Joey
sumber
2
Saya seorang mahasiswa pascasarjana, jadi ...echo 100
Amory
Bahkan mahasiswa pascasarjana tidak dapat lepas dari definisi dasar dalam bidang pekerjaan mereka Dan saya mendefinisikan hari kerja secara berbeda ;-)
Joey

Jawaban:

4

64-bit Perl, 67 68

Perl 5.10 atau lebih baru, jalankan dengan perl -E 'code here'atauperl -M5.010 filename

map{$d++,/^S/||$w++if$_=`date -d@ARGV-$_`}1..31;say int.5+100*$w/$d

Konsesi ke ukuran kode:

  • sensitif-lokal: ini dianggap sebagai hari kerja hari-hari yang dateoutputnya tidak dimulai dengan huruf kapital S. Jalankan LC_ALL=Cjika ragu.
  • output murni dan diformat dengan baik, tetapi ada "sampah" di stderr pada bulan lebih pendek dari 31. 2> /dev/nulljika kesal.
  • untuk beberapa alasan, versi saya datemenganggap 2817-12 bulan tidak valid. Siapa tahu, kiamat baru GNU sudah waktunya! Membutuhkan build 64 bit dateuntuk tanggal setelah 2038. (Terima kasih Joey)
JB
sumber
1
Rupanya itu dihapuskan oleh "Siphous Hemes" selama pemerintahannya. ref "Sejarah baru Alkitab"
Martin York
1
Apakah setiap tahun setelah tahun 2038 rusak? Kemudian beralih membangun 64-bit mungkin membantu karena beberapa braindead-ness dengan penanganan tanggal ;-)
Joey
@ Joey itu persis seperti itu. Terima kasih atas tipnya!
JB
JB: Hanya dugaan dan saya sebenarnya tidak mengharapkan apapun selain C untuk tetap menggunakan bilangan bulat 32-bit yang menghitung detik sejak zaman yang aneh. Meskipun, jujur ​​saja, saya meletakkan persyaratan tentang tanggal> 2038 di sana untuk tujuan ini ;-)
Joey
3

PHP - 135

Saya membuatnya di PHP karena saya punya masalah yang sama dengan perawatan beberapa hari yang lalu.

<?php $a=array(2,3,3,3,2,1,1);$t=strtotime($argv[1]);$m=date(t,$t);echo round((20+min($m-28,$a[date(w,strtotime('28day',$t))]))/$m*100)

(Agak) Lebih jelas, dan tanpa pemberitahuan tentang konstanta yang digunakan sebagai string:

<?php
date_default_timezone_set('America/New_York');
$additionalDays = array(2, 3, 3, 3, 2, 1, 1);
$timestamp = strtotime($argv[1]);
$daysInMonth = date('t', $timestamp);
$limit = $daysInMonth - 28;
$twentyNinthDayIndex = date('w', strtotime("+28 days", $timestamp));
$add = $additionalDays[$twentyNinthDayIndex];
$numberOfWorkDays = 20 + min($limit, $add);
echo round($numberOfWorkDays / $daysInMonth * 100);
?>

Ini dimungkinkan oleh algoritma yang sangat sederhana untuk menghitung jumlah hari kerja dalam sebulan: periksa untuk hari kerja tanggal 29, 30 dan 31 (jika ada tanggal), dan tambahkan 20.

zneak
sumber
Algoritma hebat, golf buruk. Dengan menggunakan PHP 5.3.5 kontemporer dan -R, pendekatan ini dapat diturunkan hingga 86 byte (63,7%): $a="2333211";echo.5+min(-8+$m=date(t,$t=strtotime($argn)),20+$a[date(w,$t)])/$m*100|0; Lihat langkah-langkah golf.
Titus
80 byte:<?=.5+min(-8+$m=date(t,$t=strtotime($argn)),20+(5886>>date(w,$t)*2&3))/$m*100|0;
Titus
2

Python 152 Karakter

from calendar import*
y,m=map(int,raw_input().split('-'))
c=r=monthrange(y,m)[1]
for d in range(1,r+1):
 if weekday(y,m,d)>4:c-=1
print '%.f'%(c*100./r)
fR0DDY
sumber
2

Bash + coreutils, 82 byte

f()(cal -NMd$1|sed -n "s/^$2.//p"|wc -w)
dc -e`f $1 "[^S ]"`d`f $1 S`+r200*r/1+2/p
Trauma Digital
sumber
2

Windows PowerShell, 80

$x=$args;1..31|%{"$x-$_"|date -u %u -ea 0}|%{$a++
$b+=!!($_%6)}
[int]($b*100/$a)
Joey
sumber
Apakah Anda [int]benar-benar bulat? Saya cenderung percaya itu lantai.
zneak
@ zneak: PowerShell bukan bahasa C atau yang diturunkan dari C. Ia menggunakan mode pembulatan default dari .NET yang »bulat ke bilangan bulat bahkan terdekat«. Coba saja: Keduanya [int]1.5dan [int]2.5hasilkan 2. Perilaku yang tepat ini sering menyebabkan masalah dalam tugas-tugas di mana pembagian lantai diperlukan (yang kemudian membutuhkan tambahan [Math]::Floor()), tetapi dalam kasus ini tidak sakit dan »berputar sampai genap« hanya berlaku untuk angka yang berakhir di .5mana tidak dapat terjadi di sini.
Joey
Jika Anda yakin maka saya percaya Anda. Saya hanya berharap ini berfungsi seperti C #, dan saya tidak punya mesin Windows untuk diuji di rumah.
zneak
@ zneak: Tidak, pasti tidak berfungsi seperti di C #. Sesuatu seperti [int]di PowerShell biasanya lebih berupa konversi daripada pemain :-). Hal-hal seperti [int[]][char[]]'abc'juga berfungsi yang Anda tidak bisa bekerja dalam banyak bahasa lain.
Joey
Necrobump tetapi $input-> $argsmenyimpan satu byte.
Veskah
1

D: 186 Karakter

auto f(S)(S s){auto d=Date.fromISOExtendedString(s~"-28"),e=d.endOfMonth;int n=20;while(1){d+=dur!"days"(1);if(d>e)break;int w=d.dayOfWeek;if(w>0&&w<6)++n;}return rndtol(n*100.0/e.day);}

Lebih Jelas:

auto f(S)(S s)
{
    auto d = Date.fromISOExtendedString(s ~ "-28"), e = d.endOfMonth;
    int n = 20;

    while(1)
    {
        d += dur!"days"(1);

        if(d > e)
            break;

        int w = d.dayOfWeek;

        if(w > 0 && w < 6)
            ++n;
    }

    return rndtol(n * 100.0 / e.day);
}
Jonathan M Davis
sumber
1

Python - 142

from calendar import*
y,m=map(int,raw_input().split('-'))
f,r=monthrange(y,m)
print'%.f'%((r-sum(weekday(y,m,d+1)>4for d in range(r)))*100./r)

Terima kasih kepada fR0DDY untuk bit kalender.

Juan
sumber
1

Ruby, 124 119 111

require 'date'
e=Date.civil *$*[0].split(?-).map(&:to_i),-1
p ((e+1<<1..e).count{|d|d.cwday<6}*1e2/e.day).round

Memerlukan Ruby 1.9 karena melakukan splatting tahun dan bulan sebelum argumen -1 "hari" dan ?-untuk "-". Untuk Ruby 1.8, kita harus menambahkan 2 karakter:

require 'date'
e=Date.civil *$*[0].split('-').map(&:to_i)<<-1
p ((e+1<<1..e).count{|d|d.cwday<6}*1e2/e.day).round

Sunting : Cukur lima karakter berdasarkan bantuan @ Dogbert.
Sunting : Cukur delapan karakter lagi berdasarkan bantuan @ steenslag.

Phrogz
sumber
Mengapa Anda menetapkan Tanggal ke D?
Dogbert
@Dogbert Whoops! Penahanan dari waktu ketika saya memiliki dua Date.civils; Terima kasih!
Phrogz
'-'dapat ditulis ?-dalam Ruby 1.9
Dogbert
@ Patrick Bagus. Saya akan memasukkan itu juga. Saya merasa harus ada cara yang lebih singkat untuk memilih hari kerja, tetapi saya belum menemukannya.
Phrogz
e + 1 << 1 tiga lebih pendek dari ee.day + 1
steenslag
1

PHP 5.2, 88 byte

Meskipun saya sudah memasukkan solusi zneak ke 85 byte (saya hanya menemukan satu lagi), ini milik saya:
Saya ragu bahwa saya dapat memeras tiga byte lagi di sini.

$a=_4444444255555236666304777411;echo$a[date(t,$t=strtotime($argn))%28*7+date(N,$t)]+67;

mengambil input dari STDIN: Jalankan dengan echo <yyyy>-<mm> | php -nR '<code>'.

String $amemetakan hari per bulan ( date(t)) dan hari minggu pada hari pertama bulan itu ( date(N): Senin = 1, Minggu = 7) ke persentase hari kerja-67; strtotimemengonversi input ke cap waktu UNIX; sisa kode melakukan hashing.

+1 byte untuk PHP 5 yang lebih lama: Ganti Ndengan wdan $a=_...;dengan $a="...".
+3 byte lain untuk PHP 4: masukkan .-1setelah $argn.

-5 byte untuk PHP 5.5 atau lebih baru (tantangan postdates):
Hapus semuanya sebelum echodan ganti $adengan "4444444255555236666304777411".

Titus
sumber
Yah ... satu byte: %7bukan %28.
Titus
0

Rebol - 118 113

w: b: 0 o: d: do join input"-01"while[d/2 = o/2][if d/7 < 6[++ w]++ b d: o + b]print to-integer round w / b * 100

Tidak Disatukan:

w: b: 0 
o: d: do join input "-01"
while [d/2 = o/2] [
    if d/7 < 6 [++ w]
    ++ b
    d: o + b
]
print to-integer round w / b * 100
draegtun
sumber
0

C #, 158 byte

s=>{var d=DateTime.Parse(s);int i=0,t=DateTime.DaysInMonth(d.Year,d.Month),w=0;while(i<t)w-=-(int)d.AddDays(i++).DayOfWeek%6>>31;return Math.Round(1e2*w/t);};

Metode anonim yang mengembalikan persentase yang diperlukan.

Program lengkap dengan metode ungolfed, komentar dan kasus uji:

using System;

class WorkingDayPercentage
{
    static void Main()
    {
        Func <string, double> f =
        s =>
        {
            var d = DateTime.Parse(s);                      // extracts a DateTime object from the supplied string
            int i = 0,                                      // index variable
                t = DateTime.DaysInMonth(d.Year, d.Month),  // number of total number of days in the specified month
                w = 0;                                      // number of working days in the month

            while (i < t)                                   // iterates through the days of the month
                w -= -(int)d.AddDays(i++).DayOfWeek%6 >> 31;// d.AddDays(i) is the current day
                                                            // i++ increments the index variable to go to the next day
                                                            // .DayOfWeek is an enum which hold the weekdays
                                                            // (int)..DayOfWeek gets the days's index in the enum
                                                            // note that 6 is Saturday, 0 is Sunday, 1 is Monday etc.
                                                            // (int)DayOfWeek % 6 converts weekend days to 0
                                                            // while working days stay strictly positive
                                                            // - changes the sign of the positive numbers
                                                            // >> 31 extracts the signum
                                                            // which is -1 for negative numbers (working days)
                                                            // weekend days remain 0
                                                            // w -= substracts the negative numbers
                                                            // equivalent to adding their modulus

            return Math.Round(1e2 * w / t);                 // the Math.round function requires a double or a decimal
                                                            // working days and total number of days are integers
                                                            // also, a percentage must be returned
                                                            // multiplying with 100.0 converts the expression to a double
                                                            // however, 1e2 is used to shorten the code
        };

        // test cases:
        Console.WriteLine(f("2010-05")); // 68
        Console.WriteLine(f("2010-06")); // 73
        Console.WriteLine(f("1920-10")); // 68
        Console.WriteLine(f("2817-12")); // 68
    }
}

Fungsi alternatif, yang menambahkan nilai negatif ke jumlah hari kerja, mengubah tanda dalam pengembalian tanpa biaya byte tambahan:

s=>{var d=DateTime.Parse(s);int i=0,t=DateTime.DaysInMonth(d.Year,d.Month),w=0;while(i<t)w+=-(int)d.AddDays(i++).DayOfWeek%6>>31;return-Math.Round(1e2*w/t);};
adrianmp
sumber
0

Oracle SQL, 110 byte

select round(100*sum(1-trunc(to_char(x+level-1,'d')/6))/sum(1))from dual,t connect by level<=add_months(x,1)-x

Ini bekerja dengan asumsi bahwa input data disimpan dalam sebuah tabel dalam menggunakan datetipe data, misalnya

with t as (select to_date('2010-06','yyyy-mm') x from dual)
Dr Y Wit
sumber
0

APL (Dyalog Unicode) , 55 byte SBCS

Fungsi awalan diam-diam anonim.

.5+100×2÷/(2 5)2{≢⍎⍕↓⍺↓¯2' ',cal' '@5⊢⍵⊣⎕CY'dfns'}¨⊂

 lampirkan tanggal untuk memperlakukannya secara keseluruhan

(2 5)2{...  terapkan fungsi berikut untuk itu, tetapi dengan argumen kiri [2,5]dan 2:

⎕CY'dfns' salin perpustakaan "dfns"

⍵⊣ buang laporan yang mendukung tanggal tersebut

' '@5⊢ ganti karakter ke-5 ( -) dengan spasi

 jalankan itu untuk mendapatkan daftar dua elemen

cal panggil fungsi kalender itu

' ', tambahkan kolom spasi ke situ

¯2⌽ putar dua kolom terakhir (Sabtu) ke depan

⍺↓ drop-argumen jumlah baris (2, header) dan kolom (jika ditentukan; 5 = Sat + Sun)

 membagi matriks menjadi daftar garis

 format (rata dengan penyisipan spasi ganda)

 mengeksekusi (mengubah angka hari yang tersisa menjadi daftar angka datar)

 menghitung itu

2÷/ bagi setiap pasangan (hanya ada satu)

100× kalikan dengan seratus

.5+ tambahkan setengah

 lantai

Cobalah online!

Adm
sumber
0

Perl 6 , 78 byte

{round 100*@_.grep(6>*.day-of-week)/@_}o{Date.new("$_-01")...^*.month-*.month}

Cobalah online!

Jo King
sumber