Prozentsatz der Arbeitstage in einem Monat


11

Ermitteln Sie anhand eines Jahres und eines Monats den Prozentsatz der Arbeitstage in diesem Monat. Die Arbeitstage sind Montag bis Freitag, ohne Rücksicht auf Feiertage oder andere besondere Dinge. Der Gregorianische Kalender wird verwendet.

Eingang

Ein Jahr und ein Monat im ISO 8601-Format (JJJJ-MM). Das Jahr hat immer vier Ziffern, der Monat hat immer zwei Ziffern. Das angegebene Jahr wird nicht vor 1582 liegen.

Ausgabe

Die Ausgabe ist der Prozentsatz der Arbeitstage (gemäß obiger Definition) im angegebenen Monat, gerundet auf eine ganze Zahl. Es folgen keine Prozentzeichen oder Bruchstellen.

Probe 1

Input                Output

2010-05              68

Probe 2

Input                Output

2010-06              73

Probe 3

Input                Output

1920-10              68

Probe 4

Input                Output

2817-12              68

Eine Woche ist vergangen, eine Antwort wurde angenommen. Für die Neugierigen, die Größe der Einsendungen, die wir in unserem Wettbewerb erhalten haben:

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

Sowie unsere eigenen (nicht eingestuften) Lösungen:

  75 - PowerShell
  93 - Ruby
112 - Bourne-Shell


2
Ich bin ein Doktorand, also ...echo 100
Amory

Selbst Studenten können sich den grundlegenden Definitionen in ihrer Arbeit nicht entziehen. Und ich habe Arbeitstage anders definiert ;-)
Joey

Antworten:


4

64-Bit-Perl, 67 68

Perl 5.10 oder höher mit perl -E 'code here'oder ausführenperl -M5.010 filename

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

Zugeständnisse an die Codegröße:

  • Gebietsschemasensitiv: Es werden als Arbeitstage die Tage gezählt, deren dateAusgabe nicht mit einem Großbuchstaben S beginnt. LC_ALL=CIm Zweifelsfall unterlaufen.
  • Die Ausgabe ist rein und gut formatiert, aber es gibt "Müll" auf stderr in Monaten, die kürzer als 31 2> /dev/nullsind.
  • Aus irgendeinem Grund betrachtet meine Version von date2817-12 einen ungültigen Monat. Wer wusste, GNU neue Apokalypse ist fällig! Benötigt einen 64-Bit-Build datefür Daten nach 2038. (Danke Joey)

1
Anscheinend wurde es von "Siphous Hemes" während seiner Herrschaft abgeschafft. ref "Eine neue Geschichte der Heiligen Bibel"
Martin York

1
Ist jedes Jahr nach 2038 kaputt? Dann könnte das Umschalten auf einen 64-Bit-Build aufgrund einiger Kopfschmerzen bei der Datumsverarbeitung hilfreich sein ;-)
Joey

@ Joey das ist genau das. Danke für den Tipp!
JB

JB: War nur eine Vermutung und ich hatte eigentlich nicht erwartet, dass etwas anderes als C immer noch nur 32-Bit-Ganzzahlen verwendet, die seit einer seltsamen Epoche Sekunden zählen. Um ehrlich zu sein, habe ich genau zu diesem Zweck die Anforderung über Daten> 2038 gestellt ;-)
Joey

3

PHP - 135

Ich habe es in PHP gemacht, weil ich vor ein paar Tagen ein ähnliches Problem zu behandeln hatte.

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

(Etwas) Lesbarer und ohne Hinweise darauf, dass Konstanten als Zeichenfolgen verwendet werden:

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

Dies wird durch einen sehr einfachen Algorithmus ermöglicht, mit dem die Anzahl der Arbeitstage in einem Monat berechnet werden kann: Überprüfen Sie den Wochentag des 29., 30. und 31. (falls diese Daten vorhanden sind) und addieren Sie 20.


Toller Algorithmus, schlechtes Golfen. Mit modernem PHP 5.3.5 und -Rkann dieser Ansatz auf 86 Bytes (63,7%) reduziert werden: $a="2333211";echo.5+min(-8+$m=date(t,$t=strtotime($argn)),20+$a[date(w,$t)])/$m*100|0; Siehe die
Titus

80 Bytes:<?=.5+min(-8+$m=date(t,$t=strtotime($argn)),20+(5886>>date(w,$t)*2&3))/$m*100|0;
Titus

2

Python 152 Zeichen

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)

2

Bash + Coreutils, 82 Bytes

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

2

Windows PowerShell, 80

$x=$args;1..31|%{"$x-$_"|date -u %u -ea 0}|%{$a++
$b+=!!($_%6)}
[int]($b*100/$a)

Bist du sicher, dass es [int]wirklich Runden gibt? Ich würde eher glauben, dass es Fußböden sind.
Zneak

@zneak: PowerShell ist keine C- oder C-abgeleitete Sprache. Es wird der Standardrundungsmodus von .NET verwendet, der »auf die nächste gerade ganze Zahl runden« ist. Probieren Sie es einfach aus: Beides [int]1.5und [int]2.5nachgeben 2. Dieses genaue Verhalten verursacht häufig Probleme bei Aufgaben, bei denen eine Aufteilung des Bodens erforderlich ist (was dann eine zusätzliche Aufteilung erfordert [Math]::Floor()). In diesem Fall tut es jedoch nicht weh und gilt nur für Zahlen, deren Ende .5hier nicht möglich ist.
Joey

Wenn Sie sicher sind, dann glaube ich Ihnen. Ich habe nur erwartet, dass es stattdessen wie C # funktioniert, und ich habe keinen Windows-Computer, auf dem ich zu Hause testen kann.
Zneak

@zneak: Nein, funktioniert definitiv nicht wie in C #. So etwas wie [int]in PowerShell ist normalerweise eher eine Konvertierung als eine Besetzung :-). Dinge wie [int[]][char[]]'abc'auch Arbeit, die Sie in vielen anderen Sprachen nicht arbeiten können.
Joey

Necrobump aber $input-> $argsspeichert ein Byte.
Veskah

1

D: 186 Zeichen

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

Lesbarer:

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

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)

Danke an fR0DDY für das Kalenderbit.


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

Benötigt Ruby 1.9, da das Jahr und der Monat vor dem Argument -1 "Tag" und ?-für "-". Für Ruby 1.8 müssen wir 2 Zeichen hinzufügen:

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

Bearbeiten : Rasiere fünf Zeichen basierend auf @ Dogberts Hilfe.
Bearbeiten : Rasieren Sie acht weitere Zeichen basierend auf der Hilfe von @ steenslag.


Warum weisen Sie D ein Datum zu?
Dogbert

@ Dogbert Whoops! Holdover aus einer Zeit, als ich zwei Date.civils hatte; Vielen Dank!
Phrogz

'-'könnte geschrieben werden wie ?-in Ruby 1.9
Dogbert

@ Dogbert Schön. Ich werde das auch einwerfen. Ich denke, es muss einen kürzeren Weg geben, um die Wochentage auszuwählen, aber ich habe ihn noch nicht gefunden.
Phrogz

e + 1 << 1 ist drei kürzer als ee.day + 1
steenslag

1

PHP 5.2, 88 Bytes

Obwohl ich die Lösung von zneak bereits auf 85 Bytes reduziert habe (ich habe gerade noch eine gefunden), ist hier meine eigene: Ich bezweifle, dass ich hier draußen noch drei Bytes herauspressen
kann.

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

nimmt Eingabe von STDIN entgegen: Ausführen mit echo <yyyy>-<mm> | php -nR '<code>'.

Die Zeichenfolge $aordnet Tage pro Monat ( date(t)) und Wochentag des ersten Tages des Monats ( date(N): Montag = 1, Sonntag = 7) dem Prozentsatz der Arbeitstage-67 zu. strtotimekonvertiert die Eingabe in einen UNIX-Zeitstempel; Der Rest des Codes erledigt das Hashing.

+1 Byte für älteres PHP 5: Ersetzen Ndurch wund $a=_...;durch $a="...".
weitere +3 Bytes für PHP 4: Einfügen .-1nach $argn.

-5 Bytes für PHP 5.5 oder höher (nach dem Datum der Herausforderung):
Entfernen Sie alles vorher echound ersetzen Sie es $adurch "4444444255555236666304777411".


Nun ... ein Byte: %7statt %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

Ungolfed:

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

0

C #, 158 Bytes

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

Anonyme Methode, die den erforderlichen Prozentsatz zurückgibt.

Vollständiges Programm mit ungolfed, kommentierten Methoden und Testfällen:

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

Alternative Funktion, die der Anzahl der Arbeitstage negative Werte hinzufügt und das Vorzeichen in der Rückgabe ohne zusätzliche Bytekosten ändert:

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

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

Es wird davon ausgegangen, dass Eingabedaten unter Verwendung des Datentyps in einer Tabelle gespeichert werden date, z

with t as (select to_date('2010-06','yyyy-mm') x from dual)

0

APL (Dyalog Unicode) , 55 Byte SBCS

Anonyme stillschweigende Präfixfunktion.

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

 Geben Sie das Datum an, um es als Ganzes zu behandeln

(2 5)2{ Wenden Sie die folgende Funktion an, jedoch mit den linken Argumenten [2,5]und 2:

⎕CY'dfns' Kopieren Sie die Bibliothek "dfns"

⍵⊣ Verwerfen Sie den Bericht zugunsten des Datums

' '@5⊢ Ersetzen Sie das 5. Zeichen ( -) durch ein Leerzeichen

 Führen Sie dies aus, um eine Liste mit zwei Elementen zu erhalten

cal Rufen Sie dazu die Kalenderfunktion auf

' ', Stellen Sie dem eine Spalte mit Leerzeichen voran

¯2⌽ Drehen Sie die letzten beiden Spalten (Samstag) nach vorne

⍺↓ Löschen Sie die Anzahl der Zeilen (2, Überschriften) und Spalten mit dem linken Argument (falls angegeben; 5 = Sa + So).

 Matrix in Zeilenliste aufteilen

 Format (wird durch Einfügen von Doppelabständen abgeflacht)

 Ausführen (verwandelt verbleibende Tagesnummern in eine flache numerische Liste)

 zählen diese

2÷/ Teilen Sie jedes Paar (es gibt nur eines)

100× mit hundert multiplizieren

.5+ füge eine Hälfte hinzu

 Fußboden

Probieren Sie es online aus!


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.