Проверка корректности составляющих даты и времениЗадачаСтрока сравнивалась с образцом и оказалась похожа на дату или время, но вы хотите выполнить дополнительную проверку, чтобы убедиться в том, что строка допустима. Решение Разбейте значение на части и выполните для каждой составляющей проверку на вхождение в соответствующий диапазон. Обсуждение Сравнения с образцом может оказаться недостаточно для проверки значений дат и времени. Например, значение типа 1947-15-19 может соответствовать образцу даты, но если вставить такое значение в столбец DATE, MySQL преобразует его в 0000-00-00. Если вы хотите узнать, корректно ли значение, до того, как оно попадет в базу данных, используйте сравнение с образцом в сочетании с проверкой на принадлежность диапазону. Чтобы убедиться в правильности даты, разбейте ее на составляющие года, месяца и дня и проверьте, входят ли они в соответствующие диапазоны. Год должен быть меньше 9999 (в MySQL верхняя граница дат равна 9999-12-31), значение месяца должно быть от 1 до 12, а дни должны входить в диапазон от 1 до количества дней в данном месяце. Последнее условие несколько сложнее, так как зависит от месяца, кроме того, для февральских дат оно зависит еще и от года (високосный он или нет).Предположим, что вы проверяете входные даты в формате ISO. my $ref = is_iso_date ($val); if (defined ($ref)) { # $val соответствует образцу формата ISO; # проверять составляющие, используя $ref->[0] - $ref->[2] } else { # $val не соответствует образцу формата ISO } Функция is_iso_date() возвращает undef, если значение не совпадает с образцом формата даты ISO. В противном случае она возвращает ссылку на массив, содержащий значения года, месяца и дня.1 Чтобы выполнить дополнительную проверку составляющих даты, передайте их другой библиотечной функции, is_valid_date(): $valid = is_valid_date ($ref->[0], $ref->[1], $ref->[2]); Или, если короче: $valid = is_valid_date (@{$ref}); Функция is_valid_date() проверяет составляющие даты так: sub is_valid_date { my ($year, $month, $day) = @_; # год должен быть неотрицательным, месяц и год - положительными return (0) if $year < 0 || $month < 1 || $day < 1; # проверка допустимых границ составляющих return (0) if $year > 9999; return (0) if $month > 12; return (0) if $day > days_in_month ($year, $month); return (1); } Для is_valid_date() требуется не строка даты, а отдельные значения года, месяца и дня. Для вычисления количества дней месяца, представленного датой, функция is_valid_date() применяет вспомогательную функцию days_in_month(). Функция days_in_month() требует в качестве аргументов и год, и месяц, так как если месяц – февраль (2), то количество его дней зависит от того, високосный ли год. То есть необходимо передавать значение года в четырехзначном формате. Корректно определить високосный год в двузначном значении невозможно, как это было показано в рецепте 5.27. Функции days_in_month() и is_leap_year() базируются на приемах, взятых непосредственно оттуда: sub is_leap_year { my $year = shift; return (($year % 4 == 0) && ((($year % 100) != 0) || ($year % 400) == 0)); } sub days_in_month { my ($year, $month) = @_; my @day_tbl = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); my $days = $day_tbl[$month-1]; # добавить один день для февраля високосного года $days++ if $month == 2 && is_leap_year ($year); return ($days); } Чтобы выполнить проверку корректности значений времени, можно использовать аналогичную процедуру, изменив диапазоны для составляющих: от 0 до 24 для часов и от 0 до 59 для минут и секунд. sub is_24hr_time { my $s = shift; return undef unless $s =~ /^(\d{1,2})\D(\d{2})\D(\d{2})$/; return [ $1, $2, $3 ]; # вернуть часы, минуты, секунды } Следующая функция is_ampm_time() ищет значения времени в 12-часовом формате с необязательным суффиксом AM или PM, преобразуя время после полудня (PM) к 24-часовому формату: sub is_ampm_time { my $s = shift; return undef unless $s =~ /^(\d{1,2})\D(\d{2})\D(\d{2})(?:\s*(AM|PM))?$/i;my ($hour, $min, $sec) = ($1, $2, $3); $hour += 12 if defined ($4) && uc ($4) eq "PM"; return [ $hour, $min, $sec ]; # вернуть часы, минуты, секунды } Обе функции возвращают undef для значений, не совпадающих с образцом. В противном случае они возвращают ссылку на трехэлементный массив, содержащий часы, минуты и секунды. Статьи из раздела MySQL на эту тему: ![]() ![]() ![]() ![]() ![]() Вернуться в раздел: MySQL / 10. Импорт и экспорт данных
|