5

期間がある場合、たとえばDateFromDateTo日付のリストがあります。これらの日付は分割された日付になります。例えば:

DateTime dateFrom = new DateTime(2012, 1, 1);
DateTime dateTo = new DateTime(2012, 12, 31);

List<DateTime> splitDates = new List<DateTime>
    {
        new DateTime(2012,2,1),
        new DateTime(2012,5,1),
        new DateTime(2012,7,1),
        new DateTime(2012,11,1),
    };

List<Tuple<DateTime, DateTime>> periods = SplitDatePeriod(dateFrom, dateTo, splitDates);

結果を期間のリストにしたいので、前の例では結果は次のようになります。

(01/01/2012 - 01/02/2012)
(02/02/2012 - 01/05/2012)
(02/05/2012 - 01/07/2012)
(02/07/2012 - 01/11/2012)
(02/11/2012 - 31/12/2012)

私はすでにそれを行うためのメソッドを書きました:

List<Tuple<DateTime, DateTime>> SplitDatePeriod(DateTime dateFrom, DateTime dateTo, List<DateTime> splitDates)
{
    var resultDates = new List<Tuple<DateTime, DateTime>>();

    // sort split dates
    List<DateTime> _splitDates = splitDates.OrderBy(d => d.Date).ToList();

    DateTime _curDate = dateFrom.Date;
    for (int i = 0; i <= _splitDates.Count; ++i)
    {
        DateTime d = (i < _splitDates.Count) ? _splitDates[i] : dateTo;

        // skip dates out of range
        if (d.Date < dateFrom.Date || d.Date > dateTo.Date)
            continue;

        resultDates.Add(Tuple.Create(_curDate, d));

        _curDate = d.AddDays(1);
    }
    return resultDates;
}

質問
それはとても醜いように見えます、これを行うためのよりきちんとしたそしてより短い方法はありますか?おそらくLinqを使用していますか?

4

6 に答える 6

4

これは機能し、いくつかのエッジケースも処理します。

var realDates = splitDates
    .Where(d => d > dateFrom && d < dateTo)
    .Concat(new List<DateTime>() {dateFrom.AddDays(-1), dateTo})
    .Select(d => d.Date)
    .Distinct()
    .OrderBy(d => d)
    .ToList();

// now we have             (start - 1) -- split1 -- split2 -- split3 -- end
// we zip it against          split1   -- split2 -- split3 --  end
// and produce       start,split1 -- split1+1,split2 -- split2+1,split3 -- split3+1,end

realDates.Zip(realDates.Skip(1), (a, b) => Tuple.Create(a.AddDays(1), b));
于 2012-04-13T22:32:57.990 に答える
0

LBは正しく、これはおそらくCode Reviewに属していますが、私はこれにひびを入れたいと感じました。

あなたの最初のコードブロックを考えると、次のコードはあなたが求めていることを実行します:

// List of all dates in order that are valid
var dateSegments = new [] { dateFrom, dateTo }
    .Concat(splitDates.Where(x => x > dateFrom && x < dateTo))
    .OrderBy(x => x)
    .ToArray();

List<Tuple<DateTime, DateTime>> results = new List<Tuple<DateTime, DateTime>>();
for(var i = 0; i < dateSegments.Length - 1; i++)
{
    results.Add(new Tuple<DateTime, DateTime>(dateSegments[i], dateSegments[i+1]));
}
于 2012-04-13T22:28:34.857 に答える
0

あなたはこのようにそれを行うことができます:

List<DateTime> split =
  splitDates.Where(d => d >= dateFrom && d <= dateTo).ToList();

List<Tuple<DateTime, DateTime>> periods =
  Enumerable.Range(0, split.Count + 1)
  .Select(i => new Tuple<DateTime, DateTime>(
    i == 0 ? dateFrom : split[i - 1].AddDays(1),
    i == split.Count ? dateTo : split[i]
  ))
  .ToList();
于 2012-04-13T22:35:14.030 に答える
0

すべての日付を1つのリストに入れると、これは機能するはずです。

var dates = new List<DateTime>
        {
            new DateTime(2012, 1, 1),
            new DateTime(2012, 2, 1),
            new DateTime(2012, 5, 1),
            new DateTime(2012, 7, 1),
            new DateTime(2012, 11, 1),
            new DateTime(2012, 12, 31)
        };

var z = dates.Zip(dates.Skip(1), (f, s) => Tuple.Create(f.Equals(dates[0]) ? f : f.AddDays(1), s));
于 2012-04-13T22:36:48.803 に答える
0
List<DateTime> splitDates = GetSplitDates();
DateTime dateFrom = GetDateFrom();
DateTime dateTo = GetDateTo();

List<DateTime> edges = splitDates
  .Where(d => dateFrom < d && d < dateTo)
  .Concat(new List<DateTime>() {dateFrom, dateTo})
  .Distinct()
  .OrderBy(d => d)
  .ToList();

//must be at least one edge since we added at least one unique date to this.
DateTime currentEdge = edges.First();

List<Tuple<DateTime, DateTime>> resultItems = new List<Tuple<DateTime, DateTime>>();

foreach(DateTime nextEdge in edges.Skip(1))
{
  resultItems.Add(Tuple.Create(currentEdge, nextEdge));
  currentEdge = nextEdge;
}

return resultItems;
于 2012-04-14T00:25:46.797 に答える
0

提供されたDateRange間の日付を簡単に取得できるようにしました。

モデルオブジェクト

 public class DateObjectClass
{
    public DateTime startDate { get; set; }
    public DateTime endDate { get; set; }
}

アクション :

  public List<DateObjectClass> SplitDateRangeByDates(DateTime start,DateTime end)
    {
        List<DateObjectClass> datesCollection = new List<DateObjectClass>();
        DateTime startOfThisPeriod = start;
        while (startOfThisPeriod < end)
        {
            DateTime endOfThisPeriod =new DateTime(startOfThisPeriod.Year,startOfThisPeriod.Month,startOfThisPeriod.Day,23,59,59);
            endOfThisPeriod = endOfThisPeriod < end ? endOfThisPeriod : end;
            datesCollection.Add(new DateObjectClass() { startDate= startOfThisPeriod ,endDate  =endOfThisPeriod});
            startOfThisPeriod = endOfThisPeriod;
            startOfThisPeriod = startOfThisPeriod.AddSeconds(1);
        }

        return datesCollection;
    }
于 2017-04-25T10:03:46.423 に答える