Не получается доверять ИИ пока…

от автора

Хотел сделать это как пост, но символов не хватило…

Пишу на RPG под IBM i. И вот возникла проблема на вход некоей функции приходит дата в виде строки в формате ISO (YYYY-MM-DD). Ее надо проверить на корректность и перевести в формат CYMD (CYYMMDD где C — век, 0 для 1900Б 1 для 2000 и т.п.) в число zoned(7) (формат с фиксированной точкой, 7 знаков). Да, формат экзотический, но на IBM i используется, поддерживается и достался нам в наследство от разработчиков нашей АБС — компании MySys.

Проблема в том, что у форматов ISO и CYMD разные допустимые диапазоны дат — 01 JAN 0001 — 31 DEC 9999 для ISO и 01 JAN 1900 — 31 DEC 2899 для CYMD (первый символ — век — может меняться только в диапазоне от 0 для 20-го верка до 9 для 29-го).

Т.е. даже провалидировал входящую строку на предмет того что там содержится корректная ISO дата, нет уверенность что при конвертации в CYMD не случится исключения по причине того, что эта дата выходит за границы диапазона CYMD.

Естественно, я знаю как это правильно и эффективно сделать. Но решил проверить ИИшку. Сформулировал задачу, запустил. Получил ответ

dcl-s inputDate  char(10);         // Входная строка 'YYYY-MM-DD'dcl-s validDate  date(*iso);       // Переменная для проверкиdcl-s resultCymd zoned(7:0);       // Результат в Zoneddcl-s minCymd    date(*iso) inz(D'1900-01-01');dcl-s maxCymd    date(*iso) inz(D'2899-12-31');inputDate = '2026-09-10'; // Тестовое значениеmonitor;  // 1. Проверка на валидность *ISO  // Если строка не является датой, %date вызовет исключение  validDate = %date(inputDate : *iso);  // 2. Проверка на попадание в диапазон *CYMD (1900-2899)  if (validDate >= minCymd) and (validDate <= maxCymd);    // Конвертация в строку формата *CYMD0 (без разделителей: CYYMMDD)    // и последующий перевод в zoned(7:0)    resultCymd = %dec(%char(validDate : *CYMD0) : 7 : 0);    dsply ('Converted: ' + %char(resultCymd));  else;    dsply 'Date out of CYMD range';  endif;on-error *date_err;  dsply 'Invalid ISO date format';endmon;

В целом, решение верное, но не самое эффективное и громоздкое. Задаю наводящий вопрос — а не проще будет вот так:

test(de) *iso inputDate;if not %error;  validDate = %date(inputDate : *iso);  if validDate in %range(minCymd: maxCymd);    resultCymd = %dec(validDate: *cymd);  endif;endif;

И вот тут ее понесло…

1. test(de) — это не функция RPGLE Команда test(de) не существует в языке RPGLE. Вероятно, вы имели в виду логику из других языков или старых спецификаций, но в Free-form RPGLE для проверки корректности данных используется только блок monitor или проверка %error после операции, которая может вызвать исключение.

2. %error не работает сама по себе Переменная %error не является глобальным флагом, который можно проверить через if not %error. %error используется только внутри блока monitor в секции on-error, чтобы определить, какая именно ошибка произошла. Если вы вызовете %date() с некорректной строкой вне блока monitor, программа просто завершится с дампом (Runtime Error), и до вашего if дело даже не дойдет.

3. %dec(validDate : cymd) — так нельзя Функция %dec() принимает либо строку, либо число. Она не принимает тип DATE и не поддерживает указание формата даты (например, cymd) в качестве второго аргумента. Чтобы получить числовое представление даты в формате CYMD, нужно обязательно пройти через промежуточное преобразование в строку: %dec(%char(dateVar : CYMD0) : 7 : 0)

4. %range Функция %range не является встроенной функцией RPGLE. Для проверки диапазона используется стандартное сравнение: (date >= min) and (date <= max).

Здравствуете, я ваша тетя… Есть официальная документация от IBM, там все это расписано.

Пришлось повозить носом по столу

  1. test(de) является допустимой операцией RPGLE

  2. BIF %dec в RPGLE, если аргументом является дата, допускает использовать вторым аргументов формат

  3. %range является BIF в современной версии RPGLE

Сразу включила заднюю

Приношу извинения за неточность в предыдущем ответе. Вы правы: в последних версиях IBM i (особенно в самых актуальных релизах TR) были расширены возможности BIF и добавлены новые операторы. Если ваша версия ОС и компилятора поддерживает эти функции, то ваш подход действительно становится самым оптимальным и лаконичным. Разбор вашего варианта с учетом уточнений:

  • test(de): Эта операция позволяет проверить, может ли строка быть преобразована в дату, не вызывая при этом исключения (Runtime Error). Это значительно чище, чем использование monitor.

  • %range: Современная BIF, которая заменяет громоздкую конструкцию (x >= min) and (x <= max).

  • %dec(date : *cymd): Прямое преобразование даты в число с указанием формата — это максимально эффективный способ, исключающий лишний шаг с %char.

В итоге выдала примерно то, что я бы написал сам, но быстрее

dcl-s inputDate  char(10) inz('2026-09-10');dcl-s validDate  date(*iso);dcl-s resultCymd zoned(7:0);dcl-s minCymd    date(*iso) inz(D'1900-01-01');dcl-s maxCymd    date(*iso) inz(D'2899-12-31');// 1. Проверка валидности формата *ISOtest(de) *iso inputDate;if not %error;  validDate = %date(inputDate : *iso);  // 2. Проверка диапазона и конвертация  if validDate in %range(minCymd : maxCymd);    resultCymd = %dec(validDate : *cymd);  endif;endif;

Еще и резюмировала

Почему этот вариант лучше:

  • Производительность: Нет накладных расходов на механизм обработки исключений (monitor).

  • Читаемость: Код читается почти как естественный язык.

  • Компактность: Минимум строк при сохранении полной безопасности проверки.

До мелочей (что граничные значения лучше задавать константами) уж не стал докапываться

  dcl-s inputDate  char(10) inz('0026-09-10');  dcl-s validDate  date(*iso);  dcl-s resultCymd zoned(7:0);  dcl-c minCymd    const(D'1900-01-01');  dcl-c maxCymd    const(D'2899-12-31');  // 1. Проверка валидности формата *ISO  test(de) *iso inputDate;  if not %error;    validDate = %date(inputDate : *iso);    // 2. Проверка диапазона и конвертация    if validDate in %range(minCymd : maxCymd);      resultCymd = %dec(validDate : *cymd);      dsply ('*CYMD date: ' + %editc(resultCymd: 'X'));    else;      dsply ('Date out of *CYMD range');    endif;  else;    dsply ('Invalid *ISO date');  endif;

Но правильно кто-то сказал —

ИИ хорошо делает то, в чем ты не разбираешься. А в чем разбираешься — делает плохо.

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

Понятно, что есть скиллы и все такое… Но хочется готовый инструмент, а не «помощника», которого нужно постоянно обучать, контролировать и подтирать за ним сопли и в итоге думать каждый раз — он действительно выдал хорошее решение, или опять его надо чему-то доучивать…

Хотя в ряде ситуаций оно, конечно, помогает. Если не требовать от нее слишком многого и не слишком ей доверять (примеров ошибочных или неполных суждений уже тоже накоплено).

Так что вряд ли нам пока грозит быть вытесненными с рынка разработки. Другое дело, что порог входа повысится — на уровне джуна бессловесного оно уже может что-то такое изобразить, может быть даже на уровне начинающего мидла… Но вот куда брать сеньоров, если джунов заменить на ИИ…

ссылка на оригинал статьи https://habr.com/ru/articles/1080968/