- BrainTools - https://www.braintools.ru -

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

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

Пишу на RPG [1] под 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);       // Результат в Zoned

dcl-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. Вероятно, вы имели в виду логику [2] из других языков или старых спецификаций, но в Free-form RPGLE для проверки корректности данных используется только блок monitor или проверка %error после операции, которая может вызвать исключение.

2. %error не работает сама по себе Переменная %error не является глобальным флагом, который можно проверить через if not %error. %error используется только внутри блока monitor в секции on-error, чтобы определить, какая именно ошибка [3] произошла. Если вы вызовете %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. Проверка валидности формата *ISO
test(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;

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

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

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

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

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

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

Автор: SpiderEkb

Источник [4]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/35354

URLs in this post:

[1] RPG: https://habr.com/ru/articles/813015/

[2] логику: http://www.braintools.ru/article/7640

[3] ошибка: http://www.braintools.ru/article/4192

[4] Источник: https://habr.com/ru/articles/1080968/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1080968

www.BrainTools.ru

Rambler's Top100