Oracle Регулярное выражение для даты - PullRequest
0 голосов
/ 28 мая 2020

У меня следующий анонимный блок. Я написал небольшое регулярное выражение, чтобы принять дату. Он может проверять день, месяц и год. Теперь я хочу рассмотреть единственный вековой год, и регулярное выражение также должно разрешать год в формате RR (вековой год). Также я хочу принять день без нуля в префиксе; в настоящее время он принимает это только на месяц. См. Сценарий ios ниже:

> 01/12/2154 (Do not accept, It's not a century year)
> 11/12/1996 (Do not accept, It's not a century year)
> 11/2/24 (Accept, and a plsql logic in IF condition could change it to 2024; Add 20 to it)
> 1/9/2020 (Accept)
> 01/02/2020 (Accept)
> 1/29/20 (Accept)
> 01/11/25 (Accept)
> 1/09/2021 (Accept)

**

declare
date_v varchar2(40):= '01/01/2025';
date_n date;
begin
if regexp_like (date_v, '([0-9]|1[0-2])/([0-2][0-9]|3[0-1])/[0-9]{4}') then
-- logic
date_n:= TO_DATE(date_v,'MM/DD/YYYY');
dbms_output.put_line(date_n);
end if;
end;

Ответы [ 4 ]

3 голосов
/ 28 мая 2020

Вы можете использовать регулярное выражение для даты, но это не хороший способ проверить правильность даты, он просто проверяет правильность формата. Например, 30-FEB-2020 передаст ваше регулярное выражение, но это недействительная дата. Вместо этого база данных может сделать эту работу за вас. Я обычно использую что-то вроде этого:

FUNCTION is_valid_date (date_str_i VARCHAR2, format_i VARCHAR2) RETURN VARCHAR2
/* check if date is valid */
AS
  l_dummy_dt DATE;
  date_not_valid_for_m EXCEPTION;
  PRAGMA EXCEPTION_INIT(date_not_valid_for_m, -01839);  
BEGIN
  l_dummy_dt := TO_DATE(date_str_i,format_i);
  RETURN 'Y';
EXCEPTION WHEN date_not_valid_for_m THEN
  RETURN 'N';
END; 

Обратите внимание, что он не работает только в том случае, если TO_DATE возвращает ora-01839: дата недействительна для указанного месяца, вы можете легко добавить другие возможные ошибки или просто использовать WHEN OTHERS ТОГДА ВОЗВРАЩАЙТЕ 'N';

2 голосов
/ 28 мая 2020

Oracle достаточно умен, чтобы распознать строку с 0 или без него в формате даты.

Таким образом, вы можете напрямую преобразовать эту строку в TO_DATE('11/2/24', 'mm/dd/rrrr'), а для распознавания текущего века вы можете использовать TRUNC в век с использованием 'CC' следующим образом:

SQL> SELECT
  2      TO_DATE('11/2/24', 'mm/dd/rrrr') YOUR_DATE,
  3      CASE
  4          WHEN TRUNC(TO_DATE('11/2/24', 'mm/dd/rrrr'), 'CC') = TRUNC(SYSDATE, 'CC') THEN
  5              'ACCEPT'
  6          ELSE
  7              'REJECT'
  8      END RESULT
  9  FROM
 10      DUAL;

YOUR_DATE   RESULT
----------- ------
02-NOV-2024 ACCEPT

SQL>

Результат запроса с другой датой прошлого века:

SQL> SELECT
  2      TO_DATE('11/12/1996', 'mm/dd/rrrr') YOUR_DATE,
  3      CASE
  4          WHEN TRUNC(TO_DATE('11/12/1996', 'mm/dd/rrrr'), 'CC') = TRUNC(SYSDATE, 'CC') THEN
  5              'ACCEPT'
  6          ELSE
  7              'REJECT'
  8      END RESULT
  9  FROM
 10      DUAL;

YOUR_DATE   RESULT
----------- ------
12-NOV-1996 REJECT

SQL>

Примечание : Я использовал 'rrrr' для года, поскольку он преобразует любые два-di git лет в год, приходящийся на 1950-2049 гг.

1 голос
/ 31 мая 2020

Проверка даты с помощью регулярного выражения сложна, очень сложна. Проблема в том, что в месяцах разное количество дней, а 29 февраля действительно только в определенные годы. Ваша просьба состоит в том, чтобы иметь несколько допустимых форматов, которые сильно усложняют. Следующая функция проверяет даты в формате ISO-8601 (ГГГГ-ММ-ДД) и только в этом формате, но при этом проверяет правильное количество дней в каждом месяце для дат с 0001-01-01 по 9999-12-31. , включая високосные дни (29 февраля), если они действительны. но опять же всего 1 формат. Рекомендация не пытайтесь проверять даты с помощью регулярных выражений, особенно в нескольких форматах.

create or replace function valid_iso_date (iso_date_string varchar2)
   return date
is
   iso_date_pattern constant varchar2(256) := 
       '^((0[0-9]{2}[1-9]|[1-9][0-9]{3})-((0[13578]|10|12)-(0[1-9]|[12][0-9]|3[01])|02-(0[1-9]|1[0-9]|2[0-8])|(0[469]|11)-(0[1-9]|[12][0-9]|30))$)|^(\d\d(0[48]|[2468][048]|[13579][26])-02-29$)';

   result_date date := null;
begin 
   if regexp_like(iso_date_string, iso_data_pattern)
   then 
      result_date := to_date(iso_date_string,'yyyy-mm-dd');
   end if; 
   return result_date;
end valid_iso_date; 
1 голос
/ 28 мая 2020

Попробуйте это:

with t(date_col) as (
select '01/01/2014' from dual
union all
select '1/2/2014' from dual
union all
select '01/3/2014' from dual
union all
select '1/04/2014' from dual
union all
select '11/1/14' from dual)
select date_col,
       case
         when regexp_instr(date_col, '^\d/\d/\d{4}$') = 1 then
          'd/m/yyyy'
         when regexp_instr(date_col, '^\d{2}/\d/\d{4}$') = 1 then
          'dd/m/yyyy'
         when regexp_instr(date_col, '^\d/\d{2}/\d{4}$') = 1 then
          'd/mm/yyyy'
         when regexp_instr(date_col, '^\d{2}/\d{2}/\d{4}$') = 1 then
          'dd/mm/yyyy'
         else
          'Unknown format'
       end date_format
  from t;

DATE_COL   DATE_FORMAT
---------- --------------
01/01/2014 dd/mm/yyyy
1/2/2014   d/m/yyyy
01/3/2014  dd/m/yyyy
1/04/2014  d/mm/yyyy
11/1/14    Unknown format

Обратитесь к этой ссылке:

Регулярное выражение для дат в Oracle

...