Pourcentage de jours de travail dans un mois

11

Étant donné un an et un mois, découvrez le pourcentage de jours de travail au cours dudit mois. Les jours ouvrables sont du lundi au vendredi, sans égard aux jours fériés ou autres choses spéciales. Le calendrier grégorien est utilisé.

Contribution

Une année et un mois au format ISO 8601 (AAAA-MM). L'année a toujours quatre chiffres, le mois a toujours deux chiffres. L'année donnée ne sera pas antérieure à 1582.

Production

La sortie est le pourcentage de jours de travail (selon la définition ci-dessus) dans le mois donné, arrondi à un nombre entier. Aucun signe de pourcentage ou chiffre fractionnaire ne suit.

Échantillon 1

Input                Output

2010-05              68

Échantillon 2

Input                Output

2010-06              73

Échantillon 3

Input                Output

1920-10              68

Échantillon 4

Input                Output

2817-12              68

Une semaine s'est écoulée, une réponse a été acceptée. Pour les curieux, la taille des soumissions reçues lors de notre concours:

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

Ainsi que nos propres solutions (non classées):

  75 - PowerShell
  93 - Ruby
112 - Coque Bourne

Joey
la source
2
Je suis un étudiant diplômé, alors ...echo 100
Amory
Même les étudiants diplômés ne peuvent échapper aux définitions fondamentales de leur métier. Et j'ai défini les jours de travail différemment ;-)
Joey

Réponses:

4

Perl 64 bits, 67 68

Perl 5.10 ou version ultérieure, exécutez avec perl -E 'code here'ouperl -M5.010 filename

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

Concessions sur la taille du code:

  • sensible aux paramètres régionaux: il compte comme jours de travail les jours dont la datesortie ne commence pas par un S. majuscule LC_ALL=C.
  • la sortie est pure et bien formatée, mais il y a des "ordures" sur stderr les mois plus courts que 31. 2> /dev/nullsi bouleversé.
  • pour une raison quelconque, ma version de dateconsidère 2817-12 un mois invalide. Qui savait, la nouvelle apocalypse GNU est attendue! Nécessite une version 64 bits de datepour les dates après 2038. (Merci Joey)
JB
la source
1
Apparemment, il a été aboli par "Siphous Hemes" pendant son règne. ref "Une nouvelle histoire de la Sainte Bible"
Martin York
1
Est-ce que chaque année après 2038 est interrompue? Ensuite, passer à une version 64 bits pourrait aider en raison d'une certaine cervelle avec la gestion des dates ;-)
Joey
@Joey c'est exactement ça. Merci pour le conseil!
JB
JB: C'était juste une supposition et je ne m'attendais pas à ce que quoi que ce soit au-delà de C utilise toujours uniquement des entiers 32 bits qui comptent des secondes depuis une époque étrange. Cependant, pour être honnête, j'ai mis l'exigence concernant les dates> 2038 là-dedans exactement à cette fin ;-)
Joey
3

PHP - 135

Je l'ai fait en PHP car j'avais un problème similaire à traiter il y a quelques jours.

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

(Un peu) De manière plus lisible, et sans avis sur les constantes utilisées comme chaînes:

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

Ceci est rendu possible par un algorithme très simple pour calculer le nombre de jours de travail dans un mois: vérifiez la semaine du 29, 30 et 31 (si ces dates existent), et ajoutez 20.

zneak
la source
Excellent algorithme, mauvais golf. En utilisant PHP 5.3.5 contemporain et -R, cette approche peut être golfée jusqu'à 86 octets (63,7%): $a="2333211";echo.5+min(-8+$m=date(t,$t=strtotime($argn)),20+$a[date(w,$t)])/$m*100|0; Voir les étapes de golf.
Titus
80 octets:<?=.5+min(-8+$m=date(t,$t=strtotime($argn)),20+(5886>>date(w,$t)*2&3))/$m*100|0;
Titus
2

Python 152 caractères

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
la source
2

Bash + coreutils, 82 octets

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
Traumatisme numérique
la source
2

Windows PowerShell, 80

$x=$args;1..31|%{"$x-$_"|date -u %u -ea 0}|%{$a++
$b+=!!($_%6)}
[int]($b*100/$a)
Joey
la source
Êtes-vous [int]vraiment sûrs ? J'aurais tendance à croire que c'est des planchers.
zneak
@zneak: PowerShell n'est pas un langage C ou dérivé de C. Il utilise le mode d'arrondi par défaut de .NET qui est «arrondi à l'entier pair le plus proche». Essayez-le: les deux [int]1.5et le [int]2.5rendement 2. Ce comportement exact provoque souvent des problèmes dans les tâches où une division au sol est nécessaire (ce qui nécessite alors un supplément [Math]::Floor()), mais dans ce cas, cela ne fait pas de mal et «arrondir à même» s'applique uniquement aux nombres dont la fin .5ne peut pas se produire ici.
Joey
Si vous êtes sûr, je vous crois. Je m'attendais juste à ce qu'il fonctionne comme C # à la place, et je n'ai pas de machine Windows sur laquelle tester à la maison.
zneak
@zneak: Non, ça ne marche vraiment pas comme en C #. Quelque chose comme [int]dans PowerShell est généralement plus une conversion qu'un cast :-). Des choses comme le [int[]][char[]]'abc'travail aussi que vous ne pouvez pas travailler dans de nombreuses autres langues.
Joey
Necrobump mais $input-> $argsenregistre un octet.
Veskah
1

D: 186 caractères

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

Plus lisiblement:

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

Merci à fR0DDY pour le bit de calendrier.

Juan
la source
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

Requiert Ruby 1.9 en raison de l'éclatement de l'année et du mois avant l'argument "jour" -1 et ?-pour "-". Pour Ruby 1.8, nous devons ajouter 2 caractères:

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

Edit : Rasez cinq personnages sur la base de l'aide de @ Dogbert.
Edit : Rasez huit autres personnages sur la base de l'aide de @ steenslag.

Phrogz
la source
Pourquoi attribuez-vous la date à D?
Dogbert
@Dogbert Whoops! Holdover d'une époque où j'avais deux Date.civils; Merci!
Phrogz
'-'pourrait être écrit comme ?-dans Ruby 1.9
Dogbert
@Dogbert Nice. Je vais jeter ça aussi. Je pense qu'il doit y avoir un moyen plus court de choisir les jours de la semaine, mais je ne l'ai pas encore trouvé.
Phrogz
e + 1 << 1 est trois de moins que ee.day + 1
steenslag
1

PHP 5.2, 88 octets

Bien que j'aie déjà joué à la solution de zneak jusqu'à 85 octets (je viens d'en trouver un de plus), voici la mienne:
je doute que je puisse presser encore trois octets ici.

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

prend l'entrée de STDIN: Exécuter avec echo <yyyy>-<mm> | php -nR '<code>'.

La chaîne $amappe les jours par mois ( date(t)) et le jour de la semaine du premier jour du mois ( date(N): lundi = 1, dimanche = 7) au pourcentage de jours de travail-67; strtotimeconvertit l'entrée en horodatage UNIX; le reste du code fait le hachage.

+1 octet pour les anciens PHP 5: remplacez Npar wet $a=_...;par $a="...".
un autre +3 octets pour PHP 4: insérer .-1après $argn.

-5 octets pour PHP 5.5 ou version ultérieure (postdate le défi):
supprimez tout avant echoet remplacez $apar "4444444255555236666304777411".

Titus
la source
Eh bien ... un octet: %7au lieu de %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

Non golfé:

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
la source
0

C #, 158 octets

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

Méthode anonyme qui renvoie le pourcentage requis.

Programme complet avec méthode non testée et commentée et cas de test:

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

Fonction alternative, qui ajoute des valeurs négatives au nombre de jours ouvrables, en changeant le signe dans le retour sans coût supplémentaire en octets:

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
la source
0

Oracle SQL, 110 octets

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

Il fonctionne avec l'hypothèse que les données d'entrée sont stockées dans une table en utilisant datele type de données, par exemple

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

APL (Dyalog Unicode) , 55 octets SBCS

Fonction de préfixe tacite anonyme.

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

 joindre une date pour le traiter dans son ensemble

(2 5)2{ Appliquez la fonction suivante là-dessus, mais avec les arguments de gauche [2,5]et 2:

⎕CY'dfns' copier la bibliothèque "dfns"

⍵⊣ jeter le rapport en faveur de la date

' '@5⊢ remplacer le 5ème caractère ( -) par un espace

 exécutez cela pour obtenir la liste à deux éléments

cal appeler la fonction de calendrier sur ce

' ', ajouter une colonne d'espaces à celle

¯2⌽ faire pivoter les deux dernières colonnes (samedi) vers l'avant

⍺↓ supprimer l'argument de gauche nombre de lignes (2, en-têtes) et de colonnes (si spécifié; 5 = sam + dim)

 diviser la matrice en liste de lignes

 format (aplatit avec insertion de double interligne)

 exécuter (transforme les nombres de jours restants en une liste numérique plate)

 compter ceux

2÷/ divisez chaque paire (il n'y en a qu'une)

100× multiplier par cent

.5+ ajouter un demi

 sol

Essayez-le en ligne!

Adam
la source
0

Perl 6 , 78 octets

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

Essayez-le en ligne!

Jo King
la source