В процессе работы с Delphi иногда возникает необходимость обрабатывать строки, содержащие дату и время в нестандартном формате, например, в виде yyyymmddhhnnss. В Delphi для работы с датой и временем используется тип TDateTime, который представляет собой число, где целая часть — количество дней с 30 декабря 1899 года, а дробная часть — доля дня (от 0 до 1).
Проблема заключается в том, что стандартные функции Delphi, такие как StrToDateTime(), требуют наличия разделителей между различными компонентами даты и времени (например, -, :, ). Однако, если у вас есть строка в формате yyyymmddhhnnss без разделителей, то использование StrToDateTime() становится затруднительным.
В этой статье мы рассмотрим несколько способов решения этой проблемы, включая написание собственной функции для парсинга строки, а также использование вспомогательных функций для корректного конвертинга.
Решение 1: Написание собственной функции для парсинга строки
Наиболее надежным и универсальным способом является написание собственной функции для парсинга строки в формате yyyymmddhhnnss. Это позволяет точно контролировать процесс конвертации и убедиться, что все значения находятся в допустимых диапазонах.
Вот пример такой функции:
uses
Math, DateUtils;
function TryMyStringToDateTime(const S: string; out ADateTime: TDateTime): Boolean;
begin
if S.Length <> 14 then
Exit(False);
var LYearStr := Copy(S, 1, 4);
var LMonthStr := Copy(S, 5, 2);
var LDayStr := Copy(S, 7, 2);
var LHourStr := Copy(S, 9, 2);
var LMinuteStr := Copy(S, 11, 2);
var LSecondStr := Copy(S, 13, 2);
var LYear, LMonth, LDay, LHour, LMinute, LSecond: Integer;
if
not
(
TryStrToInt(LYearStr, LYear)
and TryStrToInt(LMonthStr, LMonth)
and TryStrToInt(LDayStr, LDay)
and TryStrToInt(LHourStr, LHour)
and TryStrToInt(LMinuteStr, LMinute)
and TryStrToInt(LSecondStr, LSecond)
)
then
Exit(False);
if not InRange(LYear, 1, 9999) then
Exit(False);
if not InRange(LMonth, 1, 12) then
Exit(False);
if not InRange(LDay, 1, DaysInAMonth(LYear, LMonth)) then
Exit(False);
if not InRange(LHour, 0, 23) then
Exit(False);
if not InRange(LMinute, 0, 59) then
Exit(False);
if not InRange(LSecond, 0, 59) then
Exit(False);
ADateTime := EncodeDateTime(LYear, LMonth, LDay, LHour, LMinute, LSecond, 0);
Result := True;
end;
function MyStringToDateTime(const S: string): TDateTime;
begin
if not TryMyStringToDateTime(S, Result) then
raise EConvertError.CreateFmt('Invalid datetime string: "%s"', [S]);
end;
function MyStringToDateTimeDef(const S: string; const ADefault: TDateTime): TDateTime;
begin
if not TryMyStringToDateTime(S, Result) then
Result := ADefault;
end;
Объяснение кода:
TryMyStringToDateTime: Эта функция пытается преобразовать строку в TDateTime. Она проверяет длину строки и разбивает её на компоненты даты и времени. Затем она проверяет, что все значения находятся в допустимых диапазонах. Если все проверки проходят успешно, она использует функцию EncodeDateTime для создания TDateTime.
MyStringToDateTime: Эта функция вызывает TryMyStringToDateTime. Если преобразование неудачно, она генерирует исключение EConvertError.
MyStringToDateTimeDef: Эта функция также вызывает TryMyStringToDateTime. Если преобразование неудачно, она возвращает значение по умолчанию.
Решение 2: Использование вспомогательных функций для добавления разделителей
Если вам не нужно полностью контролировать процесс парсинга, вы можете использовать вспомогательные функции для добавления разделителей в строке, чтобы сделать её подходящей для использования с StrToDateTime.
Вот пример такой функции:
function MyDateTimeFromString(MyString: string): TDateTime;
var
Fs: TFormatSettings;
begin
Insert('-', MyString, 5); // Добавляем разделитель между годом и месяцем
Insert('-', MyString, 8); // Добавляем разделитель между месяцем и днем
Insert(' ', MyString, 11); // Добавляем разделитель между днем и временем
Insert(':', MyString, 14); // Добавляем разделитель между часами и минутами
Insert(':', MyString, 17); // Добавляем разделитель между минутами и секундами
Fs := TFormatSettings.Create;
Fs.DateSeparator := '-';
Fs.TimeSeparator := ':';
Fs.ShortDateFormat := 'yyyy-mm-dd';
Fs.ShortTimeFormat := 'hh:nn:ss';
Result := StrToDateTime(MyString, Fs);
end;
Объяснение кода:
Insert: Эта функция добавляет разделители в строку. Мы добавляем - между годом и месяцем, - между месяцем и днем, между днем и временем, : между часами и минутами, и : между минутами и секундами.
TFormatSettings: Мы создаем экземпляр TFormatSettings и настраиваем его для использования - как разделителя даты и : как разделителя времени.
StrToDateTime: Наконец, мы используем StrToDateTime с нашими настроенными TFormatSettings для преобразования строки в TDateTime.
Вывод
Оба решения имеют свои преимущества и недостатки. Если вам нужно полный контроль над процессом парсинга и убедиться, что все значения находятся в допустимых диапазонах, то лучше использовать первое решение — написание собственной функции для парсинга строки. Если вам нужен более простой и быстрый способ, который работает в большинстве случаев, то можно использовать второе решение — добавление разделителей в строку и использование StrToDateTime.
В Delphi 11 Alexandria, как и в предыдущих версиях, нет встроенной функции для парсинга строк в формате yyyymmddhhnnss без разделителей. Поэтому использование собственных функций остаётся наиболее надежным и универсальным способом решения этой проблемы.
В статье рассматриваются способы преобразования строки в формате yyyymmddhhnnss в тип TDateTime в Delphi, когда стандартные функции не справляются из-за отсутствия разделителей.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.