LINUX.ORG.RU

Посчитать количество будних дней в месяце

 ,


0

1

Есть отличный способ используя команду ncal:

https://linuxconfig.org/how-to-list-only-work-days-using-shell-command-line-on-linux

Передавая в качестве параметра номер месяца и год можно узнать число будних дней для любого месяца.

ncal -hM 9 2020 | grep -vE "^S|^ |^$" | sed "s/[[:alpha:]]//g" | fmt -w 1 | sort -n | wc -l
22

Это все прекрасно работает до попытки использования в рэдхэт или центос. Там ncal нет, а есть только cal и основное отличие в том, что ncal выводит дни строками, а cal - колонками. Соответственно в ncal строки с выходными можно легко срезать кучей способов:

ncal -hM 9 2020 
    September 2020
Mo     7 14 21 28
Tu  1  8 15 22 29
We  2  9 16 23 30
Th  3 10 17 24
Fr  4 11 18 25
Sa  5 12 19 26
Su  6 13 20 27

А в cal какого-то надежного способа придумать не получилось:

cal -m $(date +%m -d 'last month') 2020    
   September 2020   
Mo Tu We Th Fr Sa Su
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 

нужно для Centos8.

★★

01.01.1970 - четверг. Это всё, что тебе нужно знать для того, чтобы решить свою задачу. (Про то, что такое Григорианский календарь, надеюсь, ты знаешь)

crutch_master ★★★★★
()

что ncal выводит дни строками, а cal - колонками А в cal какого-то надежного способа придумать не получилось

-N Switch to ncal mode.

ukr_unix_user ★★★★
()

А в cal какого-то надежного способа придумать не получилось:

cal -N -m $(date +%m -d 'last month') 2020
    Сентябрь 2020     
Вс     6 13 20 27   
Пн     7 14 21 28   
Вт  1  8 15 22 29   
Ср  2  9 16 23 30   
Чт  3 10 17 24      
Пт  4 11 18 25      
Сб  5 12 19 26      
anonymous
()
Ответ на: комментарий от ukr_unix_user
cat /etc/redhat-release 
CentOS Linux release 8.2.2004 (Core)

cal --help

Usage:
 cal [options] [[[day] month] year]
 cal [options] <timestamp|monthname>

Display a calendar, or some part of it.
Without any arguments, display the current month.

Options:
 -1, --one             show only a single month (default)
 -3, --three           show three months spanning the date
 -n, --months <num>    show num months starting with date's month
 -S, --span            span the date when displaying multiple months
 -s, --sunday          Sunday as first day of week
 -m, --monday          Monday as first day of week
 -j, --julian          use day-of-year for all calendars
     --reform <val>    Gregorian reform date (1752|gregorian|iso|julian)
     --iso             alias for --reform=iso
 -y, --year            show the whole year
 -Y, --twelve          show the next twelve months
 -w, --week[=<num>]    show US or ISO-8601 week numbers
     --color[=<when>]  colorize messages (auto, always or never)
                         colors are enabled by default

 -h, --help            display this help
 -V, --version         display version
nerve ★★
() автор топика
Последнее исправление: nerve (всего исправлений: 1)
Ответ на: комментарий от grem

там в первой строке с днями для разных месяцев разное количество пробелов вначале и во второй строке тоже разное количество пробелов пока не появились даты 10 и больше. надежно вывести первые пять колонок из-за этого не получается.

nerve ★★
() автор топика
Ответ на: комментарий от anonymous
ncal -hM 10 2020 | grep -vE "^S|^ |^$" | sed "s/[[:alpha:]]//g" | fmt -w 1 | sort -n | wc -l
22
ncal -hM 9 2020 | grep -vE "^S|^ |^$" | sed "s/[[:alpha:]]//g" | fmt -w 1 | sort -n | wc -l
22
ncal -hM 8 2020 | grep -vE "^S|^ |^$" | sed "s/[[:alpha:]]//g" | fmt -w 1 | sort -n | wc -l
21


cal -m 10 2020 | awk '{print substr($0,4,14)}' | tail -n 6 | fmt -w 1 | sort -n | wc -l
24
cal -m 9 2020 | awk '{print substr($0,4,14)}' | tail -n 6 | fmt -w 1 | sort -n | wc -l
23
cal -m 8 2020 | awk '{print substr($0,4,14)}' | tail -n 6 | fmt -w 1 | sort -n | wc -l
22

nerve ★★
() автор топика
Ответ на: комментарий от anonymous
cal -m 10 2020 | awk '{print substr($0,4,14)}' | head -n 7 | tail -n 5 | fmt -w 1 | wc -l
23
nerve ★★
() автор топика
Ответ на: комментарий от no-such-file

похоже работает с другим tail. благодарю!

cal -m 10 2020 | tail -6 | cut -c1-14 | wc -w
22
cal -m 9 2020 | tail -6 | cut -c1-14 | wc -w
22
cal -m 8 2020 | tail -6 | cut -c1-14 | wc -w
21
nerve ★★
() автор топика
Ответ на: комментарий от grem

да, точно, посимвольно работает.

nerve ★★
() автор топика
Ответ на: комментарий от nerve

tail -6

Так ненадёжно, может оказаться меньше строк в месяце (например в феврале). Нужно именно дропнуть первые 2. Попробуй tail -n+3

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 2)

cal -m $(date +%m -d 'last month') 2020 | tail -n+3 | cut -d\ -f1-5 | wc -w

anonymous
()
Ответ на: комментарий от no-such-file

согласен, имеет смысл. спасибо.

nerve ★★
() автор топика
Ответ на: комментарий от anonymous

cal 9 2020 | sed «s/[[:alpha:]]//g» | tail -n +3 | cut -c1-14 | wc -w

sed - бесполезная трата времени на поиск и замену всех букв! Если следующая команда tail отсекает строки с буквами.

sigurd ★★★★★
()
Последнее исправление: sigurd (всего исправлений: 1)

RE: Посчитать количество будних дней в месяце

Есть отличный способ используя команду ncal:

Парсить вывод гуйни там, где задача решается в 2-3 операции? Дай угадаю, суровый ынтырпрайз?

если ДеньНеделиНа1оеЧисло >= 6
	ДеньНеделиНа1оеЧисло = 6;

ВыходныхДней = 8;

если Месяц = Февраль и Год != Високосный
	ВыходныхДней--;

РабочихДней = ВсегоДнейВМесяце - ВыходныхДней - ДеньНеделиНа1оеЧисло;
mogwai ★★★★★
()
Последнее исправление: mogwai (всего исправлений: 1)
Ответ на: комментарий от anonymous

Во нареоманы же

Ну не знаю, у меня на bash и то короче вышло:

#!/usr/bin/env bash

wd=0
{
        read my;
        read wn;
        while IFS= read l; do
                ds=(${l//   / 0})
                for d in "${ds[@]:0:5}"; do ((wd+=d!=0)); done
        done
} < <(cal -m)
echo wd=$wd

vodz ★★★★★
()

Какой-то поток сознания, собери свой нкал и обмазывайся, тоже мне проблему нашел, даже голову включать не надо будет как и раньше.

anonymous
()

кол-во рабочих дней в феврале невисокосного года всегда 20
а по твоей формуле получается какая-то хрень, зависящая от дня недели первого числа

лучше парсь гуйню )))

Egor_
()
Ответ на: комментарий от Egor_

Да уже попробовал посчитать и понял, ага. Не гуйню парсить ваще не вариант. Ща, надо подумать больше минуты)

mogwai ★★★★★
()
Ответ на: комментарий от Egor_

UPD

Выходных = 8

Если Месяц = Февраль и Год = Високосный и ПервыйДень >= Сб
	Выходных++;
	
Если ВсегоДней = 30 
	Если ПервыйДеньМесяца >= Пт
		Выходных++;
	Если ПервыйДеньМесяца = Сб
		Выходных++;

Если ВсегоДней = 31
	Если ПервыйДень >= Чт
		Выходных++;
	Если ПервыйДень = Пт или ПервыйДень = Сб
		Выходных++;

РабочихДней = ВсегоДней - Выходных;
mogwai ★★★★★
()
Последнее исправление: mogwai (всего исправлений: 1)
Ответ на: комментарий от mogwai

Во первых не бывает

А больше 6 бывает? Чем магическое число 0 отличается от магического 6?

Твой код - типичный ынтырпрайз: на входе в функцию проверяют непонятно откуда взятые условия и количество этих условий растет с возрастом этого ынтырпрайза

во вторых - оно не работает

Подход в общем правильный. Надо знать количество дней в месяце и день недели первого (или какого либо другого) дня, и тупо посчитать: пройтись - по всем дням месяца (30 - это немного). А там вдруг закономерности проявятся…

anonymous
()
bash: ncal: команда не найдена

0
> 22
bash: 22: команда не найдена
> cal -m $(date +%m -d 'last month') 2020    
    Сентябрь 2020   
Пн Вт Ср Чт Пт Сб Вс
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30

boss@linux-boss:~> 
ZenitharChampion ★★★★★
()
Последнее исправление: ZenitharChampion (всего исправлений: 1)

Раз уж тут все равно все уже обсудили, то, думаю, теперь можно выкладывать любой код.

ruby -e "require 'date';i = 0;((Date.today - Date.today.mday + 1)...(Date.today - Date.today.mday + 1).next_month).each{|d| i+=1 if (1..5).include?(d.wday)};puts i"

Для текущего месяца. Для других придеться менять параметры.

Leupold_cat ★★★★★
()
Последнее исправление: Leupold_cat (всего исправлений: 2)
Ответ на: UPD от mogwai

чо-та сложно у тебя

можно проще:

D - день недели первого числа запрошенного месяца (1=пн, 7=вс)
D2 - день недели первого числа следующего месяца (1=пн, 7=вс)
вспомогательная функция f(x) = min(5, x-1)
кол-во рабочих дней = (f(D2)-f(D)+5)%5+20
Egor_
()
Ответ на: комментарий от mogwai

Не гуйню парсить ваще не вариант

cal -m $Month $Year | tail -n +3 | cut -c1-14 | wc -w

если это быстро и надежно работает и не покидает пределов локалхоста, то в чем проблема с этим однострочником?

nerve ★★
() автор топика
Ответ на: комментарий от nerve

Просто хорошая привычка писать сразу переносимо/надёжно(в разумных пределах)

chkalov
()
Ответ на: комментарий от anonymous

к счастью в рф я не проживаю и такой дикости, как перенос выходных на будние дни никогда не видел.

а так на каждый год формируется список официальных праздничных дней, выпадающих на будние дни и в дальнейшем это учитывается, как и другие условия, влияющие на количество дней в месяце, которые должны быть Реально отработаны.

nerve ★★
() автор топика
Ответ на: комментарий от anonymous

с каких пор ruby нельзя вызывать как те же awk или sed?

anonymous
()
Ответ на: комментарий от nerve

дикости, как перенос выходных на будние дни никогда не видел.

ведь это так прогрессивно работать лишний день бесплатно

в какой стране вам так мозги промывают, если не секрет?

next_time ★★★★★
()

cal -v и усё, возможно криво, но я бы сделал так

expr $(cal -v | grep -v Вс | grep -v Сб | wc -w) - 7
# или так нечувствительно к языку
cal -vm | head -n 6 | sed -e 's/[[:alpha:]]//g;s/[[:digit:]]\{4\}//' | wc -w
AKonia ★★
()
Последнее исправление: AKonia (всего исправлений: 3)
Ответ на: комментарий от nerve

каждый год формируется список

Ну и чем это отличается, кроме того, что в РФ праздничные дни закреплены в ТК?

anonymous
()

Гугл сказал, что ncal пришёл к нам из яббла. Ты можешь взять сырец и канпельнуть на целевой тачке.

anonymous
()
Ответ на: комментарий от sigurd

sed - бесполезная трата времени на поиск и замену всех букв

Это если «подсветки» нет. А у меня есть. Как предлагаешь от неё избавиться по-другому?

anonymous
()
Ответ на: комментарий от anonymous

На сайтах правовых систем (типа консультанта) обычно уже в html выложен в готовом виде производственный календарь. Его проще парить будет.

kss ★★★★★
()

Это так не работает, кроме субботы и воскресенья есть ещё и праздники и они локальны. Вон в этом году 31 декабря выходным сделали. Разумеется касается только РФ.

peregrine ★★★★★
()
Последнее исправление: peregrine (всего исправлений: 1)
Ответ на: комментарий от anonymous

постановляет:Перенести в 2021 году следующие выходные дни:с субботы 2 января на пятницу 5 ноября;с воскресенья 3 января на пятницу 31 декабря;с субботы 20 февраля на понедельник 22 февраля.

отличается, кроме того, что в РФ праздничные дни закреплены в ТК?

ничем, кроме того что у нас нет никаких переносов с выходных на будни. выходные дни (СБ-ВС) - всегда выходные и есть только праздничные дни, которые могут выпадать на будни. А если они выпадают на выходные (и соответственно следующий будний день должен быть выходной), то этот случай опять же заранее определен в списке праздничных дней на целевой год с коррекцией на будний день.

nerve ★★
() автор топика
Ответ на: комментарий от next_time

прогрессивно

не понял про лишний день бесплатно. если что - прочти мой предыдущий комментарий.

в какой стране

у меня 24 календарных дня оплачиваемого отпуска где выходные не считаются если берешь 2 недели или больше подряд. плюс 1-2 недели оплачиваемых больничных. плюс офиц праздничные дни. и не надо тут полит срач про страны разводить. имхо находясь в рф заикаться про промывку мозгов по меньшей мере странно.

nerve ★★
() автор топика
Последнее исправление: nerve (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.