简体   繁体   English

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

[英]Sum difference in timespans, sorted by travel days per year

So I have all these travel dates, from-date and to-date. 所以我拥有所有这些旅行日期,从最新到最新。 I want to add up all the travel days, and sort them by year. 我想把所有的旅行日加起来,然后按年份排序。 However if one travel for period which spans two years, my code will reach the wrong sum :-( 但是,如果一个旅行期限跨越两年,我的代码将达到错误的总和:-(

Given 特定

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

My code produces this. 我的代码生成了这个。 However, it makes a mistake: 但是,它犯了一个错误:

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

Code

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

Help appreciated :) 帮助赞赏:)

Assuming that var stays = List<Stay>(); 假设var stays = List<Stay>(); , you may try this: ,你可以试试这个:

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

The output of the above is: 以上的输出是:

2001 32
2002 137
2003 60
2009 334
2010 32
2013 365
2014 365
2015 33

If you write a helper method to split date ranges into several ranges partitioned by year: 如果编写辅助方法将日期范围拆分为按年划分的多个范围:

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

Then you can write some handy Linq to do your bidding: 然后你可以写一些方便的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)});

This is a more general solution that you requested because it will properly deal with sub-day TimeSpan components (ie your ranges include times of day). 这是您请求的更通用的解决方案,因为它将正确处理子日TimeSpan组件(即您的范围包括一天中的时间)。

You don't need a so big code to calculate the days between two dates; 您不需要如此大的代码来计算两个日期之间的天数; you can rely on a much simpler/more accurate approach. 你可以依靠更简单/更准确的方法。 For example: 例如:

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

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

Adapted to your specific situation: 适应您的具体情况:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM