Инструменты пользователя

Инструменты сайта


mikrotik:rb3011uias:routeros:system:scripts:functions:day_of_the_week

Это старая версия документа!


Функция вычисления дня недели по дате для MikroTik

Мой вариант1) функции, которая возвращает текущий день недели основываясь на дате. Использует модифицированный алгоритм Зеллера для программного обеспечения2).

:!: Добавлена модифицированная функция, которая возвращает массив из дня недели и текущего часа.

Комментарии к коду

Создаем глобальную функцию3) и получаем текущую дату.

:global dayOfWeek do={
  :local date [ /system clock get date ];

Для тестирования и диагностики закомментировать предыдущее и раскомментировать это. Дату указывать, как в примере.

  #:local date "mar/01/2009";
  #:put $date;

Инициализируем необходимые переменные.

  :local result;
  :local day;
  :local year;

<BOOKMARK:days-array>Вводим массивы с данными. Обратите внимание в каком порядке следуют дни недели и какая нумерация у месяцев. Так должно быть согласно алгоритму.

  :local days {"sat";"sun";"mon";"tue";"wed";"thu";"fri";};
  :local months {mar="3";apr="4";may="5";jun="6";jul="7";aug="8";sep="9";oct="10";nov="11";dec="12";jan="13";feb="14";};

Отбираем месяц и «век».

  :local month ( $months -> [ :pick $date 0 3 ] );
  :local century [ :pick $date 7 9 ];

Проверяем день и год – если они начинаются с нуля, используем только вторую цифру.

  :if ( [ :pick $date 4 5 ] = 0 ) do={ :set day [ :pick $date 5 6 ]; } else={ :set day [ :pick $date 4 6 ]; }
  :if ( [ :pick $date 9 10 ] = 0 ) do={ :set year [ :pick $date 10 11 ]; } else={ :set year [ :pick $date 9 11 ]; }

Корректируем номер года для Января и Февраля, т.к., согласно алгоритму, они имеют номера 13 и 14 соответственно.

  :if ( $month = 13 || $month = 14 ) do={ :set year ( $year - 1 ); }

Сам модифицированный алгоритм Зеллера.

  :set result ( $day + ( 13 * ( $month + 1 ) / 5 ) + ( $century / 4 ) + $year + ( $year / 4 ) + ( 5 * $century ) );
  :set result ( $days -> ( $result % 7 ) );

Возвращаем результат.

  :return $result;
}

Код для импорта

day-of-week.rsc
/system script
add comment="\D4\F3\ED\EA\F6\E8\FF \E2\FB\F7\E8\F1\EB\E5\ED\E8\FF \E4\ED\FF \
    \ED\E5\E4\E5\EB\E8" dont-require-permissions=no name=day-of-week owner=\
    vasya policy=read,write,policy,test source="# Written by Nikolay Soloshin \
    (nikolay@soloshin.su) for RouterOS v6.47.8 on hAP (mipsbe) @ 2020.12\r\
    \n\r\
    \n:global dayOfWeek do={\r\
    \n  :local date [ /system clock get date ];\r\
    \n\r\
    \n  # For test\r\
    \n  #:local date \"mar/01/2009\";\r\
    \n  #:put \$date;\r\
    \n\r\
    \n  :local result;\r\
    \n  :local day;\r\
    \n  :local year;\r\
    \n\r\
    \n  :local days {\"sat\";\"sun\";\"mon\";\"tue\";\"wed\";\"thu\";\"fri\";}\
    ;\r\
    \n  :local months {mar=\"3\";apr=\"4\";may=\"5\";jun=\"6\";jul=\"7\";aug=\
    \"8\";sep=\"9\";oct=\"10\";nov=\"11\";dec=\"12\";jan=\"13\";feb=\"14\";};\
    \r\
    \n\r\
    \n  :local month ( \$months -> [ :pick \$date 0 3 ] );\r\
    \n  :local century [ :pick \$date 7 9 ];\r\
    \n\r\
    \n  # If the first char is a 0 (zero) only read last char, else script fai\
    ls\r\
    \n  :if ( [ :pick \$date 4 5 ] = 0 ) do={ :set day [ :pick \$date 5 6 ]; }\
    \_else={ :set day [ :pick \$date 4 6 ]; }\r\
    \n  :if ( [ :pick \$date 9 10 ] = 0 ) do={ :set year [ :pick \$date 10 11 \
    ]; } else={ :set year [ :pick \$date 9 11 ]; }\r\
    \n  \r\
    \n  # Adjusting the year value for January and February\r\
    \n  :if ( \$month = 13 || \$month = 14 ) do={ :set year ( \$year - 1 ); }\
    \r\
    \n\r\
    \n  # Modified Zeller's congruence for software\r\
    \n  :set result ( \$day + ( 13 * ( \$month + 1 ) / 5 ) + ( \$century / 4 )\
    \_+ \$year + ( \$year / 4 ) + ( 5 * \$century ) );\r\
    \n  :set result ( \$days -> ( \$result % 7 ) );\r\
    \n\r\
    \n  :return \$result;\r\
    \n}\r\
    \n\r\
    \n# With love from Vladivostok."

Модификация функции

Модифицированная функция, которая возвращает массив из цифры дня недели и цифры часа. НАПИСАТЬ, ГДЕ ВВОДИТСЯ И ГДЕ ИСПОЛЬЗУЕТСЯ,

Комментарии к коду

Этот код содержит такие изменения:

Добавлено

Получение часа из текущего времени и преобразование строки в число.

  :local time [ :tonum [ :pick [ /system clock get time ] 0 2 ] ];

Строка для тестирования.

  #:local time [ :tonum 14 ];

Удаление нуля в первой позиции из времени.

  :if ( [ :pick $time 0 1 ] = 0 ) do={ :set time [ :pick $time 0 1 ]; }

Сборка массива.

  :set ( $result -> "day" ) $day;
  :set ( $result -> "time" ) $time;

Изменено

Добавлено преобразование в массив.

  :local result [ :toarray "" ];

Убрана трансформация в буквенный код дня недели.

  :set day ( $day % 7 );

Убрано

Этот массив больше не нужен, т.к. отдаем в виде цифры.

  :local days {"sat";"sun";"mon";"tue";"wed";"thu";"fri";};

Код для импорта

day-of-week-and-time.rsc
/system script
add comment="\CC\EE\E4\E8\F4\E8\EA\E0\F6\E8\FF, \E2\EE\E7\E2\F0\E0\F9\E0\FE\F9\
    \E0\FF \E4\E5\ED\FC \ED\E5\E4\E5\EB\E8 \E8 \E2\F0\E5\EC\FF" \
    dont-require-permissions=no name=day-of-week-and-time owner=vasya policy=\
    ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source=":\
    global dayAndTime do={\r\
    \n  :local date [ /system clock get date ];\r\
    \n  :local time [ :tonum [ :pick [ /system clock get time ] 0 2 ] ];\r\
    \n\r\
    \n  # For test\r\
    \n  #:local time [ :tonum 14 ];\r\
    \n  #:local date \"mar/01/2009\";\r\
    \n\r\
    \n  :local day;\r\
    \n  :local year;\r\
    \n  :local result [ :toarray \"\" ];\r\
    \n\r\
    \n  :local months {mar=\"3\";apr=\"4\";may=\"5\";jun=\"6\";jul=\"7\";aug=\
    \"8\";sep=\"9\";oct=\"10\";nov=\"11\";dec=\"12\";jan=\"13\";feb=\"14\";};\
    \r\
    \n\r\
    \n  :local month ( \$months -> [ :pick \$date 0 3 ] );\r\
    \n  :local century [ :pick \$date 7 9 ];\r\
    \n\r\
    \n  # If the first char is a 0 (zero) only read last char, else script fai\
    ls\r\
    \n  :if ( [ :pick \$date 4 5 ] = 0 ) do={ :set day [ :pick \$date 5 6 ]; }\
    \_else={ :set day [ :pick \$date 4 6 ]; }\r\
    \n  :if ( [ :pick \$date 9 10 ] = 0 ) do={ :set year [ :pick \$date 10 11 \
    ]; } else={ :set year [ :pick \$date 9 11 ]; }\r\
    \n  :if ( [ :pick \$time 0 1 ] = 0 ) do={ :set time [ :pick \$time 0 1 ]; \
    }\r\
    \n  \r\
    \n  # Adjusting the year value for January and February\r\
    \n  :if ( \$month = 13 || \$month = 14 ) do={ :set year ( \$year - 1 ); }\
    \r\
    \n\r\
    \n  # Modified Zeller's congruence for software\r\
    \n  :set day ( \$day + ( 13 * ( \$month + 1 ) / 5 ) + ( \$century / 4 ) + \
    \$year + ( \$year / 4 ) + ( 5 * \$century ) );\r\
    \n  :set day ( \$day % 7 );\r\
    \n\r\
    \n  :set ( \$result -> \"day\" ) \$day;\r\
    \n  :set ( \$result -> \"time\" ) \$time;\r\
    \n\r\
    \n  :return \$result;\r\
    \n}"

Пример использования

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

Вывод оригинальной функции:

[vasya@Gateos] > :put [ $dayOfWeek ]
dec/08/2020
tue

Вывод модифицированной функции:

[vasya@Gateos] > :put [ $dayAndTime ]
dec/08/2020
18:29:37
day=3;time=18

Порядок следования дней недели смотрите выше.

Политики запуска

Это минимально необходимый набор для работы функции.

  • read,
  • write,
  • policy,
  • test.
1)
В Интернете есть несколько других кейсов, но все они показались мне несколько громоздкими и, по разным сообщениям, не всегда корректно работающим. Вот ссылки на них – раз, два и три. Поэтому я разобрался в работе алгоритма – Excel с примером – и собрал свой велосипед. LOL
2)
Подробнее смотрите по ссылке.
3)
При необходимости можно сделать функцию локальной, заменив :global на :local или вообще превратить в обычный фрагмент кода, убрав конструкцию :global dayOfWeek do={... :return $result; }.

Обсуждение

Ваш комментарий:
D S​ I Y U E A T U Z P H A D F​ J
 
Последнее изменение: 2022/02/12 11:40 (внешнее изменение)