Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Как преобразовать строку в дату?

01.01.2007

Код распознаёт и русский и английский языки. Кстати вполне корректно обрабатывает и падежи типа:

2 мая 2002

май месяц 1999 года, 3е число

3е мая 1999 года

Солнечный апрельский день в 1998м году, 20е число

Корректно распознаёт что-нибудь типа

July 3, 99

но естественно не способен распознать

01-jan-03

т.е. год если двузначный, то должен быть больше 31. Иначе необоходим дополнительный параметер, указывающий годом считать первую или вторую найденную цифру в строке

 
Function StringToDate(Temp:String):TDateTime;

  type
TDateItem=(diYear, diMonth, diDay, diUnknown);
       
TCharId=(ciAlpha, ciNumber, ciSpace);
 
 
//языковые настройки. Для включения нового языка добавляем раскладку сюда, дополняем тип alpha и меняем
 
//единственную строку где используется эта константа
 
const
    eng_monthes
:array[1..12] of string=('jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec');
    rus_monthes
:array[1..12] of string=('янв', 'фев', 'мар', 'апр', 'ма', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дес');
    alpha
:set of char=['a'..'z','а'..'я'];
 
 
//временные переменные
 
var month, day, year:string;
      temp1
:string;
      i
, j:integer;
      ci1
, ci2:TCharId;
 
 
Function GetWord(var temp:string):string;
 
begin
   
//возвращаем следующее слово из строки и вырезаем это слово из исходной строки
   
if pos(' ', temp)>0 then
     
begin //берём слово до пробела
        result
:=trim(copy(temp, 1, pos(' ', temp)));
        temp
:=copy(temp, pos(' ', temp)+1, length(temp));
     
end
   
else //это последнее слово в строке
     
begin
        result
:=trim(temp);
        temp
:='';
     
end;
 
end;
 
 
Function GetDateItemType(temp:string):TDateItem;
   
var i, j:integer;
 
begin
   
//распознаём тип слова
    i
:=StrToIntDef(temp,0); //попытка преобразовать слово в цифру
   
Case i of
     
0: Result:=diMonth; //не число, значит или месяц или мусор
     
1..31:Result:=diDay;//числа от 1 до 31 считаем днём
     
else Result:=diYear;//любые другие числа считаем годами
   
End;
 
end;
 
 
Function GetCharId(ch:char):TCharId;
 
begin
   
//узнаём тип символа, нужно для распознавания "склееных" дней или лет с месяцем
   
Case ch of
     
' ':Result:=ciSpace;
     
'0'..'9':Result:=ciNumber;
     
else Result:=ciAlpha;
   
End;
 
end;
 
 
 
begin
  temp
:=trim(ansilowercase(temp));
  month
:='';
  day
:='';
  year
:='';
//замена любого мусора на пробелы
 
For i:=1 to length(temp) do
   
if not (temp[i] in alpha+['0'..'9']) then temp[i]:=' ';
 
//удаление лишних пробелов
 
while pos('  ', temp)>0 do
   
Temp:=StringReplace(temp, '  ',' ',[rfReplaceAll]);
 
//вставка пробелов если месяц слеплен с днём или годом
  ci1
:=GetCharId(temp[1]);
  i
:=1;
 
Repeat
    inc
(i);
    ci2
:=GetCharId(temp[i]);
   
if ((ci1=ciAlpha) and (ci2=ciNumber)) or ((ci1=ciNumber) and (ci2=ciAlpha)) then
      insert
(' ', temp, i);
    ci1
:=ci2;
 
Until i>=length(temp);
 
//собственно парсинг
 
while temp>'' do
   
begin
      temp1
:=GetWord(temp);
     
Case GetDateItemType(temp1) of
        diMonth
: if month='' then  //только если месяц ещё не определён, уменьшает вероятность ошибочного результата
                   
for i:=12 downto 1 do  // обязателен отсчёт в обратную сторону чтоб не путать май и март
                     
if (pos(eng_monthes[i],temp1)=1) or (pos(rus_monthes[i],temp1)=1) then  //сюда добавляем ещё язык если надо
                       month
:=inttostr(i);
        diDay
:   Day:=temp1;
        diYear
:  Year:=temp1;
     
End;
   
end;
 
 
//проверка - все ли элементы определены
 
if (month='') or (Day='') or (Year='') then raise Exception.Create('Could not be converted!');
 
//поправка на двузначный год
 
if length(year)<3 then year:='19'+year;
 
//кодирование результата
 
Result:=EncodeDate(Strtoint(Year), Strtoint(month), Strtoint(Day));
end;

Автор: Vit


Функция StrToDate преобразует только числа, поэтому, если у Вас месяцы в виде имён, то прийдётся использовать VarToDateTime.

var
  D1
, D2, D3 : TDateTime;
begin
D1
:= VarToDateTime('December 6, 1969');
D2
:= VarToDateTime('6-Apr-1998');
D3
:= VarToDateTime('1998-Apr-6');
ShowMessage(DateToStr(D1)+' '+DateToStr(D2)+' '+
DateToStr(D3));
end;

Взято из https://forum.sources.ru


When extracting data from text or other operating systems the format of date strings can vary dramatically. Borland function StrToDateTime() converts a string to a TDateTime value, but it is limited to the fact that the string parameter must be in the format of the current locale's date/time format. eg. "MM/DD/YY HH:MM:SS"

Answer:

This is of little use when extracting dates such as ..

       1) "Friday 18 October 2002 08:34am (45 secs)"  or "Wednesday 15 May 2002 06:12 (22 secs)"

       2) "20020431"

       3) "12.Nov.03"

       4) "14 Hour 31 Minute 25 Second 321 MSecs"

This function will evaluate a DateTime string in accordance to the DateTime specifier format string supplied. The following specifiers are supported ...

dd                        the day as a number with a leading zero or space (01-31).  

ddd                        the day as an abbreviation (Sun-Sat)

dddd                        the day as a full name (Sunday-Saturday)

mm                        the month as a number with a leading zero or space (01-12).

mmm                the month as an abbreviation (Jan-Dec)

mmmm                the month as a full name (January-December)

yy                        the year as a two-digit number (00-99).

yyyy                        the year as a four-digit number (0000-9999).

hh                        the hour with a leading zero or space (00-23)

nn                        the minute with a leading zero or space (00-59).

ss                        the second with a leading zero or space (00-59).

zzz                        the millisecond with a leading zero (000-999).

ampm                Specifies am or pm flag hours (0..12)

ap                        Specifies a or p flag hours (0..12)

(Any other character corresponds to a literal or delimiter.)

NOTE : One assumption I have to make is that DAYS, MONTHS, HOURS and MINUTES have a leading                       ZERO or SPACE (ie. are 2 chars long) and MILLISECONDS are 3 chars long (ZERO or SPACE                        padded)

Using function

DateTimeStrEval(const DateTimeFormat : string; const DateTimeStr : string) : TDateTime; 

The above Examples (1..4) can be evaluated as ... (Assume DT1 to DT4 equals example strings 1..4)

        MyDate := DateTimeStrEval('dddd dd mmmm yyyy hh:nnampm (ss xxxx)', DT1);
       
MyDate := DateTimeStrEval('yyyymmdd', DT2);
       
MyDate := DateTimeStrEval('dd-mmm-yy', DT3);
       
MyDate := DateTimeStrEval('hh xxxx nn xxxxxx ss xxxxxx zzz xxxxx', DT4);
uses SysUtils, DateUtils
 
 
// =============================================================================
 
// Evaluate a date time string into a TDateTime obeying the
 
// rules of the specified DateTimeFormat string
 
// eg. DateTimeStrEval('dd-MMM-yyyy hh:nn','23-May-2002 12:34)
 
//
 
// Delphi 6 Specific in DateUtils can be translated to ....
 
//
 
// YearOf()
 
//
 
// function YearOf(const AValue: TDateTime): Word;
 
// var LMonth, LDay : word;
 
// begin
 
//   DecodeDate(AValue,Result,LMonth,LDay);
 
// end;
 
//
 
// TryEncodeDateTime()
 
//
 
// function TryEncodeDateTime(const AYear,AMonth,ADay,AHour,AMinute,ASecond,
 
//                            AMilliSecond : word;
 
//                            out AValue : TDateTime): Boolean;
 
// var LTime : TDateTime;
 
// begin
 
//   Result := TryEncodeDate(AYear, AMonth, ADay, AValue);
 
//   if Result then begin
 
//     Result := TryEncodeTime(AHour, AMinute, ASecond, AMilliSecond, LTime);
 
//     if Result then
 
//        AValue := AValue + LTime;
 
//   end;
 
// end;
 
//
 
// (TryEncodeDate() and TryEncodeTime() is the same as EncodeDate() and
 
//  EncodeTime() with error checking and boolean return value)
 
//
 
// =============================================================================
 
function DateTimeStrEval(const DateTimeFormat: string;
 
const DateTimeStr: string): TDateTime;
var
  i
, ii, iii: integer;
 
Retvar: TDateTime;
 
Tmp,
   
Fmt, Data, Mask, Spec: string;
 
Year, Month, Day, Hour,
   
Minute, Second, MSec: word;
 
AmPm: integer;
begin
 
Year := 1;
 
Month := 1;
 
Day := 1;
 
Hour := 0;
 
Minute := 0;
 
Second := 0;
 
MSec := 0;
 
Fmt := UpperCase(DateTimeFormat);
 
Data := UpperCase(DateTimeStr);
  i
:= 1;
 
Mask := '';
 
AmPm := 0;
 
 
while i < length(Fmt) do
 
begin
   
if Fmt[i] in ['A', 'P', 'D', 'M', 'Y', 'H', 'N', 'S', 'Z'] then
   
begin
     
// Start of a date specifier
     
Mask := Fmt[i];
      ii
:= i + 1;
 
     
// Keep going till not valid specifier
     
while true do
     
begin
       
if ii > length(Fmt) then
         
Break; // End of specifier string
       
Spec := Mask + Fmt[ii];
 
       
if (Spec = 'DD') or (Spec = 'DDD') or (Spec = 'DDDD') or
         
(Spec = 'MM') or (Spec = 'MMM') or (Spec = 'MMMM') or
         
(Spec = 'YY') or (Spec = 'YYY') or (Spec = 'YYYY') or
         
(Spec = 'HH') or (Spec = 'NN') or (Spec = 'SS') or
         
(Spec = 'ZZ') or (Spec = 'ZZZ') or
         
(Spec = 'AP') or (Spec = 'AM') or (Spec = 'AMP') or
         
(Spec = 'AMPM') then
       
begin
         
Mask := Spec;
          inc
(ii);
       
end
       
else
       
begin
         
// End of or Invalid specifier
         
Break;
       
end;
     
end;
 
     
// Got a valid specifier ? - evaluate it from data string
     
if (Mask <> '') and (length(Data) > 0) then
     
begin
       
// Day 1..31
       
if (Mask = 'DD') then
       
begin
         
Day := StrToIntDef(trim(copy(Data, 1, 2)), 0);
         
delete(Data, 1, 2);
       
end;
 
       
// Day Sun..Sat (Just remove from data string)
       
if Mask = 'DDD' then
         
delete(Data, 1, 3);
 
       
// Day Sunday..Saturday (Just remove from data string LEN)
       
if Mask = 'DDDD' then
       
begin
         
Tmp := copy(Data, 1, 3);
         
for iii := 1 to 7 do
         
begin
           
if Tmp = Uppercase(copy(LongDayNames[iii], 1, 3)) then
           
begin
             
delete(Data, 1, length(LongDayNames[iii]));
             
Break;
           
end;
         
end;
       
end;
 
       
// Month 1..12
       
if (Mask = 'MM') then
       
begin
         
Month := StrToIntDef(trim(copy(Data, 1, 2)), 0);
         
delete(Data, 1, 2);
       
end;
 
       
// Month Jan..Dec
       
if Mask = 'MMM' then
       
begin
         
Tmp := copy(Data, 1, 3);
         
for iii := 1 to 12 do
         
begin
           
if Tmp = Uppercase(copy(LongMonthNames[iii], 1, 3)) then
           
begin
             
Month := iii;
             
delete(Data, 1, 3);
             
Break;
           
end;
         
end;
       
end;
 
       
// Month January..December
       
if Mask = 'MMMM' then
       
begin
         
Tmp := copy(Data, 1, 3);
         
for iii := 1 to 12 do
         
begin
           
if Tmp = Uppercase(copy(LongMonthNames[iii], 1, 3)) then
           
begin
             
Month := iii;
             
delete(Data, 1, length(LongMonthNames[iii]));
             
Break;
           
end;
         
end;
       
end;
 
       
// Year 2 Digit
       
if Mask = 'YY' then
       
begin
         
Year := StrToIntDef(copy(Data, 1, 2), 0);
         
delete(Data, 1, 2);
         
if Year < TwoDigitYearCenturyWindow then
           
Year := (YearOf(Date) div 100) * 100 + Year
         
else
           
Year := (YearOf(Date) div 100 - 1) * 100 + Year;
       
end;
 
       
// Year 4 Digit
       
if Mask = 'YYYY' then
       
begin
         
Year := StrToIntDef(copy(Data, 1, 4), 0);
         
delete(Data, 1, 4);
       
end;
 
       
// Hours
       
if Mask = 'HH' then
       
begin
         
Hour := StrToIntDef(trim(copy(Data, 1, 2)), 0);
         
delete(Data, 1, 2);
       
end;
 
       
// Minutes
       
if Mask = 'NN' then
       
begin
         
Minute := StrToIntDef(trim(copy(Data, 1, 2)), 0);
         
delete(Data, 1, 2);
       
end;
 
       
// Seconds
       
if Mask = 'SS' then
       
begin
         
Second := StrToIntDef(trim(copy(Data, 1, 2)), 0);
         
delete(Data, 1, 2);
       
end;
 
       
// Milliseconds
       
if (Mask = 'ZZ') or (Mask = 'ZZZ') then
       
begin
         
MSec := StrToIntDef(trim(copy(Data, 1, 3)), 0);
         
delete(Data, 1, 3);
       
end;
 
       
// AmPm A or P flag
       
if (Mask = 'AP') then
       
begin
         
if Data[1] = 'A' then
           
AmPm := -1
         
else
           
AmPm := 1;
         
delete(Data, 1, 1);
       
end;
 
       
// AmPm AM or PM flag
       
if (Mask = 'AM') or (Mask = 'AMP') or (Mask = 'AMPM') then
       
begin
         
if copy(Data, 1, 2) = 'AM' then
           
AmPm := -1
         
else
           
AmPm := 1;
         
delete(Data, 1, 2);
       
end;
 
       
Mask := '';
        i
:= ii;
     
end;
   
end
   
else
   
begin
     
// Remove delimiter from data string
     
if length(Data) > 1 then
       
delete(Data, 1, 1);
      inc
(i);
   
end;
 
end;
 
 
if AmPm = 1 then
   
Hour := Hour + 12;
 
if not TryEncodeDateTime(Year, Month, Day, Hour, Minute, Second, MSec, Retvar) then
   
Retvar := 0.0;
 
Result := Retvar;
end;

Взято с Delphi Knowledge Base: https://www.baltsoft.com/