1

私は良い質問だと思ったものを思いつきました: 指定された日付形式の 2 つの DateTime 間のすべてのラベルを取得するにはどうすればよいですか? 私が思いついたものよりもエレガントなソリューションを誰かが持っているかどうか疑問に思いました。(コンパイル時にフォーマットを知る以外に)またはこれを最適化する方法。

これを使用して、すべての時間セグメントに値があるわけではないグラフを生成しています (そのため、 .GroupBy(date => date.ToString(dateFormat))要素がゼロの期間はスキップされます)

例: 2011/01/01 から 2011/03/21 までのすべてのラベルを日付形式 "yyyyMM" で出力します。 GetTimeSegmentLables(new DateTime(2011,1,1), new DateTime(2011,3,21), "yyyyMM").Dump(); これは、次のような形式もサポートする必要があります。"yyyy MM 'Month' dddd\\'\\s"

これは私が思いついたものです:

public static List<string> GetTimeSegmentLabels(DateTime startDate, DateTime endDate, string dateFormat)
{
    DateTime incrementedDate = startDate;
    TimeSpan increment = GetSmallestUnitInDateFormat(dateFormat);

    int estimatedCount = (int)((endDate - startDate).TotalMilliseconds / increment.TotalMilliseconds + 1);
    List<string> Formats = new List<string>(estimatedCount);

    string LastFormat = "";
    while (incrementedDate < endDate)
    {
        string next = incrementedDate.ToString(dateFormat);
        if (next != LastFormat)
        {
            Formats.Add(next);
            LastFormat = next;
        }
        incrementedDate = incrementedDate.Add(increment);
    }
    if (LastFormat != endDate.ToString(dateFormat))
        Formats.Add(endDate.ToString(dateFormat));

    return Formats;
}

public static TimeSpan GetSmallestUnitInDateFormat(string dateFormat)
{
    //Remove escaped characters
    string stripped = Regex.Replace(dateFormat, "(\\\\.|'[^']+'|\"[^\"]+\")", "");

    //Check for format strings in increasing order
    if (stripped.Contains("F") || stripped.Contains("F"))
    {
        //TODO find longest [fF]+ string
    }
    if (stripped.Contains("s"))
    {
        return new TimeSpan(0, 0, 1);
    }
    if (stripped.Contains("m"))
    {
        return new TimeSpan(0, 1, 0);
    }
    if (stripped.Contains("h") || stripped.Contains("H"))
    {
        return new TimeSpan(1, 0, 0);
    }
    if (stripped.Contains("d"))
    {
        return new TimeSpan(1, 0, 0, 0);
    }
    if (stripped.Contains("M"))
    {
        //30 is the average month (365.25/12) but there is a chance it would skip Feburary...
        //So 28 should hit every month for each year, hitting one twice
        return new TimeSpan(28, 0, 0, 0);
    }
    if (stripped.Contains("y"))
    {
        return new TimeSpan(365, 0, 0, 0);
    }

    throw new ArgumentOutOfRangeException("Unable to find any supported Format Specifier");
}
4

0 に答える 0