Страница 1 из 1

Конвертация String to TDateTime

Добавлено: 02 дек 2006, 09:35
SergeyS
у объекта DateTime из MS FrameWork есть хороший метод Parse, который из произвольной строки вытаскивает дату. Например он понимает следующие строки:
2006/01/01
2006.01.01
01.01.2006
01/01/2006
01.01.06
01.01.06 г
01 01 2006 года
1 1 2006
....
и т.д.

Есть ли подобный модуль для Delphi? Это необходимо, чтобы предоставить пользователям свободу при вводе даты и не загружать их масками ввода
Тоже самое относится и к преобразованию времени. Например:
01.01.2006 12:01
01.01.2006 12:01PM
12:01AM
...
и т.д.

Re: Конвертация String to TDateTime

Добавлено: 04 дек 2006, 13:43
Blood_Magic
нормальные люди в России вводят либо 01.01.06 либо 01.01.2006. а лучше все же маск эдит что б не гадать как ввести

Re: Конвертация String to TDateTime

Добавлено: 04 дек 2006, 15:05
Игорь Акопян
SergeyS, а как парсер поведёт себя в ситуации 01/02/03? может это 2 марта 2001 а может 1 февраля 2003 а может и нет... ;)
маску! и хинт до кучи, чтоб не оправдывались! :)

Re: Конвертация String to TDateTime

Добавлено: 05 дек 2006, 09:49
Naeel Maqsudov
Но все же если очень хочется, то можно написать свою функцию на базе StrToDateTime

Что-то типа:

Код: Выделить всё

try
  Result:=StrToDateTime(str,"YYYY/MM/DD");
except
  try 
    Result:=StrToDateTime(str,"YYYY.MM.DD");
  except
    try 
      Result:=StrToDateTime(str,"DD.MM.YYYY");
    except
       ....... // И так далее по вкусу....
    end;
  end;
end;

Re: Конвертация String to TDateTime

Добавлено: 07 дек 2006, 14:46
SergeyS
Всем спасибо, ввод даты по маске у меня и так был реализован, но хотелось расширить возможности. А вот так я реализовал совет Naeel Maqsudov:

Код: Выделить всё

function CWord(S: String; DefValue: Word): Word;
var
  C: Integer;
begin
  Val(S, Result, C);
  if C <> 0 then Result := defValue;
end;

function ParseDate(S: String; Format: String; y, m, d: Word; out ADate: TDateTime): Boolean;
var
  i: Integer;
  dd, mm, yy: String;
  b: Boolean;
begin
  Result := False;
  if Length(S) < Length(Format) then Exit;
  try
    dd := '';
    mm := '';
    yy := '';
    for i := 1 to Length(Format) do begin
      if Format[i] = 'd' then dd := dd + S[i]
      else if Format[i] = 'M' then mm := mm + S[i]
      else if Format[i] = 'y' then yy := yy + S[i]
      else if S[i] <> Format[i] then Exit;
    end;
    if d = 0 then d := CWord(dd, d);
    if m = 0 then m := CWord(mm, m);
    if y = 0 then begin
      if Length(yy) = 2 then
        y := CWord('20' + yy, y)
      else
        y := CWord(yy, y);
    end;

    Result := TryEncodeDate(y, m, d, ADate);
  except
    Result := False;
  end;
end;

// вызываемая функция. Например:
// var
//   d: TDateTime;
// begin
//   d := CDate('01/01/2003');
//   ... или
//   d := CDate('asdfasd', Date); так как ошибка то вернёт текущую дату
//   d := CDate('01/01', Date); если текущая дата 07/12/2006 вернёт '01/01/2006'
//   d := CDate('01', Date); если текущая дата 07/12/2006 вернёт '01/07/2006'
//   d := CDate('01/01/2003', Date); вернет дату 01/01/2003
//   d := CDate('01/01/2003'); аналогично
// end;
function CDate(Value: String; DefDate: TDateTime = 0): TDateTime;
const
  dd: array[0..1] of string = ('dd', 'd');
  mm: array[0..1] of string = ('MM', 'M');
  yy: array[0..1] of string = ('yyyy', 'yy');
var
  y, m, d: Word;

  function _Parse(Value: String; out ADate: TDateTime;
      Separator: String; DMY: String): Boolean;
  var
    S: String;
    i, l, _y, _m, _d: Integer;
    __y, __m, __d: Word;
  begin
    Result := True;
    S := '';
    while S <> Value do begin
      S := Value;
      Value := StringReplace(S, ' ' + Separator, Separator, [rfReplaceAll]);
    end;
    S := '';
    while S <> Value do begin
      S := Value;
      Value := StringReplace(S, Separator + ' ', Separator, [rfReplaceAll]);
    end;

    l := Length(DMY);

    for _d := 0 to 1 do
      for _m := 0 to 1 do
        for _y := 0 to 1 do begin
          S := '';
          __d := d; __m := m; __y := y;
          for i := 1 to l do begin
            if DMY[i] = 'd' then begin
              S := S + dd[_d];
              __d := 0;
            end;
            if DMY[i] = 'm' then begin
              S := S + mm[_m];
              __m := 0;
            end;
            if DMY[i] = 'y' then begin
              S := S + yy[_y];
              __y := 0;
            end;
            if i < l then S := S + Separator;
          end;
          if ParseDate(Value, S, __y, __m, __d, ADate) then Exit;
        end;
    Result := False;
  end;

var
  S: String;
begin
  if DefDate = 0 then
    DecodeDate(Date, y, m, d)
  else
    DecodeDate(DefDate, y, m, d);

  if _Parse(Value, Result, '.', 'dmy') then Exit;
  if _Parse(Value, Result, '/', 'dmy') then Exit;
  if _Parse(Value, Result, ' ', 'dmy') then Exit;
  if _Parse(Value, Result, '', 'dmy') then Exit;
  if _Parse(Value, Result, '.', 'dm') then Exit;
  if _Parse(Value, Result, '/', 'dm') then Exit;
  if _Parse(Value, Result, ' ', 'dm') then Exit;
  if _Parse(Value, Result, '', 'dm') then Exit;
  if _Parse(Value, Result, '', 'd') then Exit;
  Result := DefDate;
end;
получилось громозко, но достаточно быстро и главное работает :)
Ещё нужно добавить параметр определяющий тип даты: dmy, mdy, ymd и т.д.
но это уже не столь принципиально.