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.

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

заранее определен в списке праздничных дней на целевой год с коррекцией на будний день

То есть фактически то же самое.

anonymous
()

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

Я, конечно, дико извиняюсь, но как я понял, основная проблема в том, чтобы выводить вертикально?

man cal

-v, --vertical
              Display using a vertical layout (aka ncal mode).

Это в федоре.

Im_not_a_robot ★★★★★
()

В чём проблема собрать ncal?

anonymous
()

Это надо еще базу праздников. Не каждый вторник будний день. Лучше какое-нибудь апи к «производственному календарю».

anonymous
()
Ответ на: комментарий от Harald
#!/usr/bin/pwsh

param ([int]$y, [int]$m)

(1..31 | ? {[int] (Get-Date "$($_).$m.$y").DayOfWeek -match '[06]'}).Count 2>$null
anonymous
()

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

Эталонный пример bash-говнокода. В 80% случаев применение регулярных выражений в скриптах означает говнокод. Для таких задач есть Python.

Поменяется локаль или стиль вывода календаря и всё поломается.

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

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

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

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

Непонятно, что подразумевается под «коррекцией», но попахивает тем самым «диким» переносом выходных на будние

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

чё-то как-то уныло. так что за страна-то?

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

Если любой другой вариант будет ещё хуже

Уже предложили более адекватные решения: 1, 2.

может быть костыль, но уже не говнокод

Костыль - частный случай говнокода.

X512 ★★★★★
()
Последнее исправление: X512 (всего исправлений: 1)
Ответ на: комментарий от X512
  1. Нет те решения говнокод, т.к. требуют смешения сред - зачем мне в bash сценарий ещё и руби тянуть ? Или вообще как я понял какую-то левую оболочку ?
  2. Нет говнокод пишут от малоопытности или дилетантства, а костыль может быть вынужденной мерой, если имеющийся инструментарий плохо приспособлен для задачи, а расширять инструментарий запрещено или вредно.
AKonia ★★
()
Ответ на: комментарий от AKonia

Нет те решения говнокод, т.к. требуют смешения сред - зачем мне в bash сценарий ещё и руби тянуть ?

Bash срипты предназначены для вызова последовательности программ, для более сложных задач есть полноценные языки вроде Python. Возможно есть смысл всю программу переписать на Python и выкинуть bash и тогда не будет «смешения сред».

а расширять инструментарий запрещено

Не надо ничего расширять, Python есть везде.

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

Bash срипты предназначены для вызова последовательности программ, для более сложных задач есть полноценные языки

Bash - это именно шелл и именно в этом он достаточно хорош, быть ЯП ему ни к чему.

есть смысл всю программу

Нет никакой «программы», выбросите свой воображаемый глобус, он сломался.

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

Python есть везде.

Заявление уровня «венда есть везде»:

pinkbyte@mini-router ~ $ python
-bash: python: command not found
pinkbyte@mini-router ~ $ python2
-bash: python2: command not found
pinkbyte@mini-router ~ $ python3
-bash: python3: command not found
Pinkbyte ★★★★★
()
Ответ на: комментарий от anonymous

А больше 6 бывает?

Бывает, пн - 1, вс - 7.

А там вдруг закономерности проявятся…

Ну, вот я и прошёлся, только когда считал - день пропустил. Сюда запостил, проверил, а оно не работает) Не надо сначала постить, потом проверять. Надо наоборот.

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

В ынтырпрайзе всё сложно) Уйди от сюда со своим элегантным решением.

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

Нужно таймштамп первого числа месяца преобразовать в число дней, прошедшее с 1970 (разделить нацело на 60*60*24), потом найти остаток от 7 и прибавить его к 4, а потом опять найти остаток от 7. Это и будет день недели первого месяца. Потом найти такое же число дней для первого числа следующего месяца и вычислить длину месяца.
Хотя можно даже без таких плясок.
День недели (weekDay 1 - понедельник, 7 - воскресенье) даст date +%u --date="01-01-2020 00:00:00".
Кол-во дней (monthLen) даст date +%d --date="@$(( $(date +%s --date="2020-02-01 00:00:00") - 1))"
Следующий месяц = остаток деления номера текущего месяца на 12 плюс 1.
Кол-во рабочих дней - кол-во полных недель (fullWeeks) * 5 + остаток недели в начале месяца (firstWeek) + остаток недели в конце месяца (lastWeek)
Считаем полные недели (кроме первой): fullWeeks = (monthLen - (8 - weekDay)) / 7 (нацело)
Считаем раб.дни в первой недели: firstWeek = 5 - (weekDay - 1). Считаем нулём, если получилось меньше ноля (weekDay == 1).
Тоже самое для последней недели: lastWeek = monthLen - (fullWeeks * 7) - (8 - weekDay (длинна первой недели). Если больше 5, то равна пяти.
Всё складываем.
Серьёзно не тестил, не уверен, что нужны ветвления в вычислениях раб.дней первой/последней недели, но с ними, в любом случае, будет понятнее.

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

Ппц. [n]cal, sed, tail, pyhton, веб сервис, нацпол, когда надо пошевелить мозгой, взять два таймштампа и/или немного посчитать. Типичный ЛОР.

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

date

И чем date лучше cal, лалка? Всё равно запускать внешнюю команду же. Только теперь вместо прямого результата нужно ещё что-то считать.

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

Неужели пятизвёздочнику прописные истины нужно разжёвывать?

$ LC_ALL=en_US.UTF-8 ncal
    October 2020
Su     4 11 18 25
Mo     5 12 19 26
Tu     6 13 20 27
We     7 14 21 28
Th  1  8 15 22 29
Fr  2  9 16 23 30
Sa  3 10 17 24 31
$ LC_ALL=ru_RU.UTF-8 ncal
    Октября 2020
Пн     5 12 19 26
Вт     6 13 20 27
Ср     7 14 21 28
Чт  1  8 15 22 29
Пт  2  9 16 23 30
Сб  3 10 17 24 31
Вс  4 11 18 25
$ LC_ALL=en_US.UTF-8 date +%u
2
$ LC_ALL=ru_RU.UTF-8 date +%u
2
mogwai ★★★★★
()
Ответ на: комментарий от no-such-file

И чем date лучше cal, лалка?

Тем что вывод cal предназначен для пользователя, а не для программ. Вывод зависит от локали (язык названия месяцев, дней недели), неделя может начинаться с воскресенья или понедельника, могут использоваться цвета, рамки и прочие вариации оформления, календарь не обязан быть григорианским.

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

неделя может начинаться с воскресенья или понедельника, могут использоваться цвета, рамки и прочие вариации оформления, календарь не обязан быть григорианским

ЛОЛ, а для вычислений по дню недели это всё не нужно учитывать что ли?

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

ЛОЛ, а для вычислений по дню недели это всё не нужно учитывать что ли?

Разумеется не нужно. UNIX time не зависит от локали и не имеет оформления (цвета, рамки, отступы и т.п.). Формула будет работать везде одинаково.

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

UNIX time не зависит от локали и не имеет оформления

А никто не гарантирует, как и для cal, что date вернёт что-то без учёта локали и без оформления.

no-such-file ★★★★★
()

Можно curl’ом дёргать какой-нибудь производственный календарь.

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

А никто не гарантирует, как и для cal, что date вернёт что-то без учёта локали и без оформления.

Для date +%u, date +%s гарантирует:

%u: day of week (1..7); 1 is Monday

%s: seconds since 1970-01-01 00:00:00 UTC

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

гарантирует

Про оформление ничего не сказано же.

day of week (1..7); 1 is Monday

По какому календарю? Мумба-юмба? В зависимости от локали?

И да, ТСу нужно для произвольного месяца, так что +%u пока вообще не в кассу.

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

Тебе уже @X512 разжевал подробно. Я надеялся, что ты сам это сообразишь по приведённому выводу терминала.

ЛОЛ, а для вычислений по дню недели это всё не нужно учитывать что ли?

А ты ещё раз сюда посмотри, если man date не осилил.

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

Это какой-то позор

И да, ТСу нужно для произвольного месяца, так что +%u пока вообще не в кассу.

date -d YYYYMMDD +%u

Хотя бы, что YYYYMMDD нужно заменить на требуемый год, месяц и день, ты сообразишь, или тоже явно писать надо?

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

man date

У тебя один ман, у меня другой. Как и для cal.

не осилил

Я-то осилил решить задачу, за 2 минуты. Ты уже второй день херню пишешь. Где решение Билли? Где код?

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

Алгоритм тебе дали, откуда входные данные получать дали. Или я не заметил, как топик перенесли в job?

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

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

не надо тут полит срач про страны разводить

На ЛОРе праздник, нас посетил мастер спорта международного класса по переобуванию на лету.

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

И чем date лучше cal, лалка?

Тем, что вываливает данные с которыми можно работать, а не говно.

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

А никто не гарантирует, как и для cal, что date вернёт что-то без учёта локали и без оформления.

Иди читай POSIX.

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

читай POSIX

Там как бы и cal есть, дурачина. Т.е. гарантии для cal и для date одинаковые.

no-such-file ★★★★★
()
Последнее исправление: no-such-file (всего исправлений: 1)
Ответ на: комментарий от crutch_master

таймштамп … разделить нацело на 606024

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

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

Вот именно. Поэтому поделив сегодняшний timestamp на 86400 ты можешь оказаться либо в сегодняшнем дне, либо во вчерашнем.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.