BASH: Как найти нет. дней (считая только «Сеть / Рабочие дни») между двумя датами (т.е. исключая выходные суббота / воскресенье) - PullRequest
0 голосов
/ 14 февраля 2020

RHEL 7,5

BASH GNU bash, версия 4.2.46 (2) -релиз (x86_64-redhat- linux -gnu) )

В MS Excel я могу использовать Сетевые дни, чтобы найти номер. дней между двумя датами. Интересно, можно ли использовать bash в качестве первого предпочтения (- или любой другой предустановленный язык в Linux, поддерживающий решение этой проблемы, возможно, с использованием одной строки - мое второе предпочтение). Я не уверен, существует ли какая-либо библиотека или пользовательский инструмент / утилита в Linux, которая вычисляет это значение.

  • Чтобы рассчитать количество рабочих дней между двумя датами, вы можете использовать Функция NETWORKDAYS. NETWORKDAYS автоматически исключает выходные дни, а также может по желанию исключать пользовательский список праздников. Обратите внимание, что NETWORKDAYS включает даты начала и окончания в расчет, если они являются рабочими днями.

У меня есть файл file.txt, содержащий 2 поля столбца в ГГГГ-мм-дд * Формат 1020 * для Разрешено и Начало даты ( Вы можете игнорировать строку заголовка на данный момент ):

Resolved,StartOfWork
2020-01-16,2020-01-10
2020-01-13,2020-01-13
2020-01-20,2020-01-15
2020-01-20,2020-01-14
2020-01-14,2020-01-09
2020-01-09,2020-01-08
2020-01-16,2020-01-14
2020-01-09,2020-01-07
2020-01-14,2020-01-12

Для каждой строки я хочу посчитать нет. NETWORK, т.е. только ДНЕЙ НЕДЕЛИ между этими двумя датами ( не имеет значения, если даты Resolved / StartOfWork были в выходные дни: суббота / воскресенье ).

  • Расчет из № дней НЕ СЛЕДУЕТ включать выходных дней, т. е. субботу / воскресенье .

PS : для целей настоящего пост, мой вопрос очень отличается от того, о чем просит этот пост: Как найти разницу в днях между двумя датами?

Ответы [ 2 ]

2 голосов
/ 14 февраля 2020

Я бы позвонил переводчику Python для этого. Принятие принятого ответа от Использование Python для подсчета количества рабочих дней в месяце? -

countBusinessDaysPy=$(cat <<'EOF'
import datetime, sys

businessdays = 0
startDate = datetime.date.fromisoformat(sys.argv[1])
endDate = datetime.date.fromisoformat(sys.argv[2])
if endDate < startDate:
    (startDate, endDate) = (endDate, startDate)

while startDate <= endDate:      # change from <= to < to not count both start and end days
    if startDate.weekday() < 5:
        businessdays += 1
    startDate += datetime.timedelta(days=1)

print(businessdays)
EOF
)

countBusinessDays() { python3 -c "$countBusinessDaysPy" "$@"; }

... дает вам функцию оболочки, которая вызывает Python переводчик для выполнения необходимой математики (обратите внимание, что это диапазон включительно ). После этого:

$ countBusinessDays 2019-01-01 2020-01-01
262
$ countBusinessDays 2019-01-01 2019-01-07
5

Вызов этого цикла для вашего файла (обратите внимание, что в реальном мире цикл в Python, а не bash) может выглядеть следующим образом:

{
  read -r header; printf '%s\n' "$header,TotalDates"
  while IFS=, read -r resolved startOfWork rest; do
    printf '%s\n' "${resolved},${startOfWork}${rest:+,$rest},$(countBusinessDays "$startOfWork" "$resolved")"
  done
} <yourInputFile

... который выдает в качестве вывода:

Resolved,StartOfWork,TotalDates
2020-01-16,2020-01-10,5
2020-01-13,2020-01-13,1
2020-01-20,2020-01-15,4
2020-01-20,2020-01-14,5
2020-01-14,2020-01-09,4
2020-01-09,2020-01-08,2
2020-01-16,2020-01-14,3
2020-01-09,2020-01-07,3
2020-01-14,2020-01-12,2
1 голос
/ 14 февраля 2020

Это может быть переосмысление колеса , но вот решение bash (если интересно).
Обратите внимание, что для команды date требуется опция -d.

while IFS="," read -r endday startday; do
    if (( lineno++ == 0 )); then                # handle header line
        echo "Resolved,StartOfWork,TotalDates"
        continue
    fi
    startsec=$(date -d "$startday" +%s)
    startdayofweek=$(date -d "$startday" +%w)   # 0 for Sun, ... 6 for Sat
    endsec=$(date -d "$endday" +%s)
    days=$(( (endsec - startsec) / 86400 + 1 )) # calendar days
    weeks=$(( days / 7 ))                       # number of weeks
    frac=$(( days % 7 ))                        # fraction mod 7
    if (( startdayofweek == 0 )); then          # case of starting on Sunday
        if (( frac > 0 )); then
            add=1                               # additional number of holidays
        else
            add=0
        fi
    else
        magic=$(( frac + (startdayofweek + 6) % 7 ))
                                                # calculate number of holidays
                                                # in the fraction period
        if (( magic < 6 )); then
            add=0
        elif (( magic == 6 )); then
            add=1
        else
            add=2
        fi
    fi
    holidays=$(( weeks * 2 + add ))             # total number of holidays
    workdays=$(( days - holidays ))             # subtract the holidays
    echo "$endday,$startday,$workdays"
done < inputfile
...