Бухгалтер попросила поправить разрядность количества месяцев срока полезного использования объектов основных средств (не изучал я законодательства, а бухгалтер уверяет, что у нее есть объект со сроком 109.2 месяца).
Полез я в типовую бухгалтерию от МиСофт, поправил, где только возможно, тестирую и получаю ошибку в непредвиденном месте: есть оказывается функция, которая возвращает вместо 13 месяцев строку «1 год 1 месяц». А у меня дробное число, вот и нарвался я на ошибку.
Скажу честно, мне не понравилась функция, которая вообще не использует возможности 1С по использованию т.н. «Предмета исчисления», вот и решил переписать.
Маленькое пояснение.
В одном из мест кода «день» представлен как «#$ень». Чтобы представить число дней в виде именно числа дальше по коду ищется этот самый «день» и удаляется все, что до него. Когда я искал просто букву «д», то получал результат в виде «12 дцать дней», «20 дцать дней», а усложнять код для поиска «день, дня, дней» не захотел.
Советую и «год, года, лет» в «Предмете исчисления» представить как «@@год, @@года, @@лет» для исключения из кода двойного поиска по словам «год, лет».
В коде оставлена функция из типовой конфигурации. Весь ее код можно просто удалить (область выделена фиолетовым), т.к. до этого кода, по идее, никогда не должен доходить компилятор.
Собственно функция:
Функция РасшифровкаСрокаПолезногоИспользования(СрокПолезногоИспользования) Экспорт
РасшифровкаСрокаПолезногоИспользования = "";
Если ЗначениеЗаполнено(СрокПолезногоИспользования) Тогда
ЧастьМесяца = СрокПолезногоИспользования - Цел(СрокПолезногоИспользования);
ЧислоДней = Цел(30 * ЧастьМесяца);
Суффикс = "";
Если НЕ ЧислоДней = 0 Тогда
Суффикс = ЧислоПрописью(ЧислоДней, "НД = Ложь", "#$ень, #$ня, #$ней, м,,,,,0");
ПозицияПослеПрописи = Найти(Суффикс, "#$");
Суффикс = Сред(Суффикс, ПозицияПослеПрописи);
Суффикс = " " + СокрЛП(ЧислоДней) + " " + Суффикс;
КонецЕсли;
ЧислоЛет = Цел(СрокПолезногоИспользования / 12);
ЧислоМесяцев = Цел((СрокПолезногоИспользования % 12));
ЧислоЛетМесяцев = ЧислоЛет + ЧислоМесяцев/100;
Если ЧислоЛет = 0 Тогда
СтрокаЧислоЛетМесяцев = ЧислоПрописью(ЧислоМесяцев, "НД = Ложь", "месяц, месяца, месяцев, м,,,,,0");
СтрокаПоиска = "месяц";
Иначе
СтрокаЧислоЛетМесяцев = ЧислоПрописью(ЧислоЛетМесяцев, ?(ЧислоМесяцев = 0, "НД = Ложь", "НД = Истина"), "год, года, лет, м" + ?(ЧислоМесяцев = 0, ",,,,,0" ,", месяц, месяца, месяцев, м, 2"));
СтрокаПоиска = "год";
КонецЕсли;
ПозицияПослеЛет = Найти(СтрокаЧислоЛетМесяцев, СтрокаПоиска);
Если ПозицияПослеЛет = 0 Тогда
ПозицияПослеЛет = Найти(СтрокаЧислоЛетМесяцев, "лет");
Если ПозицияПослеЛет = 0 Тогда
//Фигня какая-то, оставим алгоритм МиСофт
От сих старый код типовой конфигурации
**************************************
Если НЕ (ЧислоЛет = 0) Тогда
// Построим строку с числом лет
Если (СтрДлина(ЧислоЛет) > 1) И (Число(Сред(ЧислоЛет, СтрДлина(ЧислоЛет) - 1, 1)) = 1) Тогда
СтрокаГод = " лет";
ИначеЕсли Число(Прав(ЧислоЛет, 1)) = 1 Тогда
СтрокаГод = " год";
ИначеЕсли (Число(Прав(ЧислоЛет, 1)) > 1) И (Число(Прав(ЧислоЛет, 1)) < 5) Тогда
СтрокаГод = " года";
Иначе
СтрокаГод = " лет";
КонецЕсли;
РасшифровкаСрокаПолезногоИспользования = РасшифровкаСрокаПолезногоИспользования + Строка(ЧислоЛет) + СтрокаГод;
КонецЕсли;
Если НЕ (ЧислоМесяцев = 0) Тогда
// Построим строку с числом месяцев
Если (СтрДлина(Цел(ЧислоМесяцев)) > 1) И (Число(Сред(Цел(ЧислоМесяцев), СтрДлина(Цел(ЧислоМесяцев)) - 1, 1)) = 1) Тогда
СтрокаМесяц = " месяцев";
ИначеЕсли Число(Прав(Цел(ЧислоМесяцев), 1)) = 1 Тогда
СтрокаМесяц = " месяц";
ИначеЕсли (Число(Прав(Цел(ЧислоМесяцев), 1)) > 1) И (Число(Прав(Цел(ЧислоМесяцев), 1)) < 5) Тогда
СтрокаМесяц = " месяца";
Иначе
СтрокаМесяц = " месяцев";
КонецЕсли;
РасшифровкаСрокаПолезногоИспользования = РасшифровкаСрокаПолезногоИспользования + ?(НЕ ЗначениеЗаполнено(РасшифровкаСрокаПолезногоИспользования), "", " ") + Строка(ЧислоМесяцев) + СтрокаМесяц;
КонецЕсли;
РасшифровкаСрокаПолезногоИспользования = "(" + РасшифровкаСрокаПолезногоИспользования + ")";
**************************************
До сих старый код типовой конфигурации
КонецЕсли;
КонецЕсли;
Если РасшифровкаСрокаПолезногоИспользования = "" Тогда
РасшифровкаСрокаПолезногоИспользования = СокрЛП(?(ЧислоЛет = 0, ЧислоМесяцев, ЧислоЛет)) + " " + Сред(СтрокаЧислоЛетМесяцев, ПозицияПослеЛет);
//Уберем обязательное двузначное число месяцев, если оно получилось:
РасшифровкаСрокаПолезногоИспользования = СтрЗаменить(РасшифровкаСрокаПолезногоИспользования, " 0", " ") + СтрЗаменить(Суффикс, "#$", "д");
КонецЕсли;
КонецЕсли;
Возврат РасшифровкаСрокаПолезногоИспользования;
КонецФункции// РасшифровкаСрокаПолезногоИспользования()
Здесь же оставил часть кода МиСофта на непредвиденные мною ситуации.
Функция, безусловно, хорошая.
Но вы слышали, что вместо того, чтобы использовать вот такие конструкции:
(Число(Прав(Цел(ЧислоМесяцев), 1)) < 5)
Можно использовать операцию остатка целочисленного деления?
ЧислоМесяцев % 10 < 5?
(1) Это код МиСофт, который я оставил для сравнения или на случай моего тупизма.
На входе: 1.2
На выходе: 1 месяц 6 #$ней
Ожидал: 1 месяц 6 дней
(3) Поправил и саму функцию и вставил пояснение про эти самые «#$ни». В 11:20 (GMT+3) публикация обновлена (проверил).
Товарищи программисты! Представленная в публикации функция, если ее вставить в код 1С не заработает!
Удалите из кода строчки, разукрашенные фиолетовым.
Если решил использовать ЧислоПрописью(), то можно проще:
Показать
Тест на правильность:
Показать
По замерам, Вариант1/Вариант2 = 9/11 сек. (на 301*31 итераций), зато Вариант2 читабельней.
Если требуется оптимизированный вариант, то лучше делать без тяжёлой ЧислоПрописью().
(5) Намного читабельнее, спасибо за наводку про «Периоды», которые «все в одном». В «Периоды», если использовать Структуру вместо текста, можно получить повышение производительности?
Пожалуйста. 🙂
Давай замерим (для упрощения выбираю одинаковый номер — 1):
Показать
Итог: прироста производительности нет.
В сроках полезного использования могут быть только целые месяца и никаких дней там не должно быть.