【问题标题】:TryStrToDate Fails with format mmm/yyTryStrToDate 以 mmm/yy 格式失败
【发布时间】:2017-02-01 07:23:14
【问题描述】:

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

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

如果我将示例更改为使用 dd/mm/yyyy 并传入 01/02/2017,那么它会成功,所以我认为问题可能出在格式上。我使用以下链接作为创建格式字符串的参考

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.

我会很感激任何关于为什么失败的想法

【问题讨论】:

  • 不要使用 Delphibasics。使用官方文档。而且您的结果设置很奇怪。使用result := TryStrToDate(...)
  • 也许this post(特别是我写的答案)可以提供帮助。

标签: date delphi delphi-10-seattle


【解决方案1】:

您的格式字符串无效。这些格式字符串必须对日、月和年进行编码。您省略了不允许的日期。

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

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

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

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

最后,这是一个非常简单的格式,您可以很容易地直接解析它。

更新

正如您在 cmets 中所观察到的那样,RTL 功能是通过调用 ScanDate 来实现的,它只支持数字月份格式。因此,遗憾的是,您尝试的整个方法注定要失败。即使你解决了我发现的问题。

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

【讨论】:

  • 嗨,大卫,感谢您的帮助。实施您的更改并查看 TryStrToDate 的源代码,看起来它试图在“mmm”上调用 scannumber,所以在这种情况下,Oct 肯定会失败。这是否意味着我不能使用 mmm 格式?还是我错过了什么?
  • 呸,我没有意识到这一点。我认为你是对的,StrToDate 和朋友只支持数字月份。我认为你最好自己解析这个。检查是否有一个 / 字符,在该字符上拆分,然后解析两部分。
【解决方案2】:

根据 David l 的建议,创建了一个函数,它将月份从字符串(即 Jan)转换为 01,然后调用 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;

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

【讨论】:

  • 这没有回答所提出的问题。此外,这段代码真的很糟糕。
  • 你会如何编程?我允许传入一个日期字符串,然后是一个格式设置来说明该日期字符串的格式。然后将其转换为 trystrtodate 将接受的格式
  • 我认为这与所提出的问题无关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-30
  • 2020-10-30
  • 2018-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多