时间差的总和差异,按每年的旅行天数排序

时间:2013-08-14 13:11:59

标签: c# .net datetime timespan

所以我拥有所有这些旅行日期,从日期到目前为止。我想把所有的旅行日加起来,然后按年份排序。但是,如果一次旅行超过两年,我的代码将达到错误的总和:-(

鉴于

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;
}

帮助赞赏:)

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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)});

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

答案 2 :(得分: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);
}