Проверка реальной даты

#delphi #delphi-xe2

#delphi #delphi-xe2

Вопрос:

Есть ли какая-нибудь функция, которая может проверять дату в формате aaaa / mm / gg (ccyy / mm / dd), возвращая, True если она действительна или False иначе? Я имею в виду действительно действительную дату, а не только для выравнивания по синтаксису.

Ответ №1:

Является ли ‘aaaa’ годом и ‘gg’ днем?

 var
  MyString: string;
  MyDate: TDateTime;
  settings: TFormatSettings;
begin
  settings.ShortDateFormat := 'yyyy/mm/dd';
  settings.DateSeparator := '/';
  MyString := '2011/15/15';
  if TryStrToDateTime(MyString, MyDate, settings) then
    Label1.Caption := 'correct date'
  else
    Label1.Caption := 'incorrect';
end;
  

Комментарии:

1. Примечание: «Если S содержит только два числа, это интерпретируется как дата (m / d или d / m) в текущем году». Таким образом, можно пройти проверку с неправильно сформированной строкой. Кроме того, часть времени тоже пройдет. Кроме того, функция пропускает начальные пробелы, давая еще больше ложных срабатываний.

2. Назначение только двух полей записи настроек может быть опасным. Я бы, вероятно, попытался сначала инициализировать его из текущих активных настроек: settings := TFormatSettings. Создать(GetUserDefaultLCID);

Ответ №2:

Это очень быстро, потому что сначала обнаруживаются самые простые ошибки.

 function IsValidDate(const S: string): boolean;
var
  y, m, d: Integer;
const
  DAYS_OF_MONTH: array[1..12] of integer = (31, 29, 31, 30, 31, 30, 31, 31, 30,
  31, 30, 31);
begin
  result := false;
  if length(S) <> 10 then Exit;
  if (S[5] <> '/') or (S[8] <> '/') then Exit;
  if not TryStrToInt(Copy(S, 1, 4), y) then Exit;
  if not TryStrToInt(Copy(S, 6, 2), m) then Exit;
  if not InRange(m, 1, 12) then Exit;
  if not TryStrToInt(Copy(S, 9, 2), d) then Exit;
  if not InRange(d, 1, DAYS_OF_MONTH[m]) then Exit;
  if (not IsLeapYear(y)) and (m = 2) and (d = 29) then Exit;
  result := true;
end;
  

Комментарии:

1. Извини, Андреас. 🙂 Это работает (и поэтому нет снижения), но запрашивающий использует XE2. Лучший ответ — это ответ @Arjen, который использует TFormatSettings . Я бы разрешил исключение, а не отбрасывал его, используя TryStrToDate как это сделал Арьен.

2. @Ken, спасибо. И об исключении: зависит от обстоятельств. Андреас, и НИКАКИХ отрицательных отзывов от меня.

3. StrToDate(S, Format) подход not way специфичен для XE2, но недостаточно строг. Положительный. И я думаю, что настоящий даунвотер пытается кого-то подставить.

Ответ №3:

Используйте перегруженную версию StrToDate(), которая имеет параметр TFormatSettings. Затем вы можете передать строку нужного формата для синтаксического анализа, и она вернет TDateTime после проверки проанализированных значений.

Ответ №4:

Пытаюсь сделать то же самое и наткнулся на этот старый поток. В итоге я написал свою собственную функцию и подумал, что опубликую ее. Как насчет этого?

 function IsValidDate(const S: string): boolean;
 var TestDate : tdatetime;
begin
 Result := False;

 if (LastDelimiter('/',S) >= 4) 
 and 
 (Length(S)-LastDelimiter('/',S) >= 4) 
 then

  Result := TryStrToDate(S,TestDate);

 end;
  

Прежде всего, я проверяю, находится ли второй разделитель (/), по крайней мере, достаточно далеко, чтобы представлять как день, так и месяц (4-я позиция). Затем я ввожу в них 4-значный год в следующей строке. Измените этот второй тест на > = 2 для двухзначного числа, но я просто полагаю, что не так уж плохо ввести четырехзначный год — это всего лишь еще два штриха.

Наконец, я тестирую с помощью TryStrToDate(). Если есть только один разделитель или если это недопустимая дата, она будет обнаружена здесь.

Если вы хотите пофантазировать, вы могли бы проверить, был ли год в пределах последних 10 лет или что-то в этом роде. Просто добавьте:

 Result := Result and (Now - TestDate < 3650);
  

Дэйв