TryStrToDate失败,格式为mmm / yy

时间:2017-02-01 07:23:14

标签: date delphi delphi-10-seattle

我正在尝试使用TDateTime函数将mmm / yy格式的字符串转换为TryStrToDate。然而它似乎总是失败。

我创建了一个格式设置记录并设置了日期分隔符和短日期格式。我设置了长日期格式,以表明无论是设置短日期还是长日期格式都会出现问题。

如果我将示例更改为使用dd / mm / yyyy并在2017年1月1日通过,那么它会成功,所以我相信问题可能是格式。我使用以下链接作为参考来创建格式字符串

http://www.delphibasics.co.uk/RTL.asp?Name=formatdatetime

我已经制作了一个演示控制台应用程序,以显示我正在尝试做什么的示例

uses
   System.SysUtils;

function ValidateDate(ADate: string): boolean;
var
    fs: TFormatSettings;
    DateTime: TDateTime;
begin
    fs := TFormatSettings.Create();
    fs.DateSeparator := '/';
    fs.ShortDateFormat := 'mmm/yy';
    fs.LongDateFormat := 'mmm/yy';

    result := true;
    if not TryStrToDate(ADate, DateTime, fs) then
        result := false;
end;

begin
    try
        if not ValidateDate('Oct/16') then
            WriteLn('Failed to convert')
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
end.

我会很感激为什么会失败

2 个答案:

答案 0 :(得分:7)

您的格式字符串无效。这些格式字符串必须编码日,月和年。你省略了不允许的日子。

您为转换提供的字符串可以省略年份。在这种情况下,假设当前年份。

如果您希望将这些字符串转换为仅几个月和一年,那么请包括假日,例如1,在传递给TryStrToDate的字符串中。然后使用DecodeDate获取月份和年份的数值,忽略该日期。

因此,使用'd/mmm/yy'作为格式,并将'1/' + ADate作为要转换的字符串传递。

另请注意,它是用于从字符串转换为日期的短日期字符串格式,因此这是您需要设置的唯一格式。

最后,这是一种简单的格式,你可以很容易地直接解析它。

<强>更新

正如您所观察到的,并在评论中说明,RTL功能是通过调用ScanDate来实现的,git filter-branch仅支持数字月份格式。所以,你所尝试的整个方法,遗憾的是注定要失败。即使你解决了我发现的问题。

我的建议是简单地自己解析字符串,因为它的格式非常简单。

答案 1 :(得分:-1)

根据David的建议,l创建了一个函数,它将月份从字符串转换为Jan,然后调用TryStrToDate获取转换日期。如果格式字符串不包含一天,则默认为01

function ParseDate(ADate: string; AFormatSettings: TFormatSettings): TDateTime;
var
    DateData, FormatData: TStringList;
    Month, Day, Year: string;
    ConvertedDate: Double;
    i: integer;

    function ConvertMonth(AMonth: string; ALongMonth: boolean = false): string;
    var
        i: integer;
    begin
        Result := '-1'; // default to invalid month
        if ALongMonth then
        begin
            for i := 1 to high(AFormatSettings.LongMonthNames) do
            begin
                if AFormatSettings.LongMonthNames[i] = AMonth then
                begin
                    Result := inttostr(i); // MonthArray starts at index 1 which matches the month
                    break;
                end;
            end;
        end
        else
        begin
            for i := 1 to high(AFormatSettings.ShortMonthNames) do
            begin
                if AFormatSettings.ShortMonthNames[i] = AMonth then
                begin
                    Result := inttostr(i); // MonthArray starts at index 1 which matches the month
                    break;
                end;
            end;
        end;
    end;
begin
    DateData := TStringList.Create();
    FormatData := TStringList.Create();
    try
        DateData.Delimiter := AFormatSettings.DateSeparator;
        DateData.StrictDelimiter := true;
        DateData.DelimitedText := ADate;

        FormatData.Delimiter := AFormatSettings.DateSeparator;
        FormatData.StrictDelimiter := true;
        FormatData.DelimitedText := AFormatSettings.ShortDateFormat;

        Day := '01';
        Month := '01';
        Year := '01';

        for i := 0 to FormatData.Count - 1 do
        begin
            if FormatData[i].IndexOf('d') <> -1 then
                Day := DateData[i]
            else if FormatData[i].IndexOf('m') <> -1 then
            begin
                if FormatData[i] = 'mmm' then
                    Month := ConvertMonth(DateData[i])
                else if FormatData[i] = 'mmmm' then
                    Month := ConvertMonth(DateData[i], true)
                else
                    Month := DateData[i]
            end
            else if FormatData[i].IndexOf('y') <> -1 then
                Year := DateData[i]
        end;

        ADate := Day + AFormatSettings.DateSeparator + Month + AFormatSettings.DateSeparator + Year;

        AFormatSettings.ShortDateFormat := 'dd' + AFormatSettings.DateSeparator + 'mm' + AFormatSettings.DateSeparator + 'yyyy';
        TryStrToDate(ADate, Result, AFormatSettings);
    finally
        DateData.free();
        FormatData.free();
    end;
end;

如果有人能看到任何改进或优化,请告诉我。