4

所以我有所有这些旅行日期,从日期到现在。我想把所有的旅行天数加起来,然后按年份排序。但是,如果一次旅行跨越两年,我的代码将达到错误的总和:-(

给定

From date   To date      Number of days
01.01.2001  01.02.2001   32
01.01.2002  01.02.2002   32
01.05.2002  01.08.2002   93
20.12.2002  01.03.2003   72
01.02.2009  01.02.2010   366
01.01.2013  02.02.2015   763

                   Sum   1358

我的代码产生了这个。然而,它犯了一个错误:

Year    Total days
2001    32
2002    137
2003    60
2009    334
2010    32
2013    365
2014    398        <---- here is a case where my code is wrong

Sum     1358

代码

var dates = new Dictionary<int, int>();
var stays = GetStays();
var returnString = "Year, Total days<br><br>";
foreach (var stay in stays)
{
    var totalTravelDays = stay.ToDate.Value.AddDays(1) - stay.FromDate;

    var currentYear = stay.FromDate.Value.Year;
    var nextYear = stay.FromDate.Value.AddYears(1).Year;
    var nextYearDate = new DateTime(stay.FromDate.Value.Year, 1, 1).AddYears(1);

    var daysInThisYear = new TimeSpan?();
    var daysInNextYear = new TimeSpan?();

    if (stay.FromDate.Value.Year != stay.ToDate.Value.Year)
    {
        daysInThisYear = nextYearDate - stay.FromDate;
        daysInNextYear = totalTravelDays - daysInThisYear;
    }
    else
    {
        daysInThisYear = totalTravelDays;
        daysInNextYear = new TimeSpan(0);
    }

    if (dates.ContainsKey(currentYear))
        dates[currentYear] += daysInThisYear.Value.Days;
    else
        dates[currentYear] = daysInThisYear.Value.Days;

    if (dates.ContainsKey(nextYear))
        dates[nextYear] += daysInNextYear.Value.Days;
    else
        dates[nextYear] = daysInNextYear.Value.Days;
}

帮助表示赞赏:)

4

3 回答 3

4

假设var stays = List<Stay>();,你可以试试这个:

var days = stays.SelectMany(s =>
        Enumerable
            .Range(0, (s.ToDate - s.FromDate).Days + 1)
            .Select(d => s.FromDate.AddDays(d)))
    .GroupBy(d => d.Year)
    .Select(s => new { Year = s.Key, TotalDays = s.Count() })
    .ToList();

days.ForEach(d =>
{
    Console.WriteLine("{0} {1}", d.Year, d.TotalDays);
});

上面的输出是:

2001 32
2002 137
2003 60
2009 334
2010 32
2013 365
2014 365
2015 33
于 2013-08-14T13:46:15.933 回答
3

如果您编写一个辅助方法将日期范围拆分为按年份划分的多个范围:

IEnumerable<Tuple<DateTime,DateTime>> 
    SplitDateRangeByYear(DateTime fromDate, DateTime toDate)
{
    var start = fromDate;
    for(var y = fromDate.Year; y < toDate.Year; ++y)
    {
        var nextYear = y + 1;
        var nextYearStartDate = new DateTime(nextYear, 1, 1);
        yield return Tuple.Create(start, nextYearStartDate);
        start = nextYearStartDate;
    }
    yield return Tuple.Create(start, toDate);
}

然后你可以写一些方便的 Linq 来做你的竞标:

    var yearlyTotals = stays
        .SelectMany(s => SplitDateRangeByYear(s.FromDate, s.ToDate))
        .GroupBy(x => x.Item1.Year)
        .Select(g => new{
                Year = g.Key, 
                NumDays= g.Sum(x => (x.Item2 - x.Item1).TotalDays)});

这是您要求的更通用的解决方案,因为它将正确处理亚日时间跨度组件(即您的范围包括一天中的时间)。

于 2013-08-14T13:41:57.790 回答
2

您不需要这么大的代码来计算两个日期之间的天数;您可以依靠更简单/更准确的方法。例如:

DateTime date1 = new DateTime(2013, 1, 1);
DateTime date2 = new DateTime(2015, 2, 2);

int totDays = Math.Abs(date1.Subtract(date2).Days);

适应您的具体情况:

int[] days = new int[Math.Abs(date1.Year - date2.Year) + 1];
int curYear = 0;
if (date1.Year != date2.Year)
{
    if(date1.Year > date2.Year)
    {
        DateTime temp = date1;
        date1 = date2;
        date2 = temp;
    }
    int curYearNo = date1.Year - 1;
    curYear = -1;
    do
    {
        curYearNo = curYearNo + 1;
        curYear = curYear + 1;
        if (curYearNo < date2.Year)
        {
            days[curYear] = Math.Abs(new DateTime(curYearNo, 1, 1).Subtract(new DateTime(curYearNo, 12, 31)).Days) + 1; //Without +1 it would output 364/365 (because of not including both 1st January and 31st December)
        }
        else
        {
            days[curYear] = Math.Abs(new DateTime(curYearNo, 1, 1).Subtract(date2).Days);
        }
    } while (curYearNo < date2.Year);
}
else
{
    days[curYear] = Math.Abs(date1.Subtract(date2).Days);
}
于 2013-08-14T13:26:43.517 回答