Вот еще один способ сделать это, основное отличие здесь в том, что я использую цикл for
, чтобы постоянно обновлять «первый день» до первого дня в периоде или до первого дня текущего месяца,и от «последнего дня» до последнего дня текущего месяца или до последнего дня периода, в зависимости от того, что меньше.
Я также добавил это как статический метод в класс AmountPerMonth
, который принимает AmountPerPeriod
и возвращает List<AmountPerMonth>
.Кроме того, я переопределил метод ToString
, чтобы вывести строку, аналогичную приведенной в вашем вопросе, поэтому вывод выглядит так же:
public class AmountPerMonth
{
public int Id { get; set; }
public int Year { get; set; }
public int Month { get; set; }
public decimal Amount { get; set; }
public static List<AmountPerMonth> FromPeriod(AmountPerPeriod period)
{
if (period == null) return null;
var amtPerDay = period.Amount / ((period.EndDate - period.StartDate).Days + 1);
var result = new List<AmountPerMonth>();
for (var date = period.StartDate; date <= period.EndDate;
date = date.AddMonths(1).ToFirstDateOfMonth())
{
var lastDayOfMonth = date.ToLastDateOfMonth();
var lastDay = period.EndDate < lastDayOfMonth
? period.EndDate
: lastDayOfMonth;
var amount = ((lastDay - date).Days + 1) * amtPerDay;
result.Add(new AmountPerMonth
{
Id = period.Id,
Year = date.Year,
Month = date.Month,
Amount = amount
});
}
return result;
}
public override string ToString()
{
return $"{Id,-3} |{Month,-6}| {Year,-6}| {Amount:0.00}";
}
}
Мы можем использовать этот метод в качестве аргумента для SelectMany
изВаши образцы данных для создания нашего списка и вывода результатов:
static void Main(string[] args)
{
var lstAmmountPerPeriod = new List<AmountPerPeriod>()
{
new AmountPerPeriod
{
Id = 1,
StartDate = new DateTime(2019, 03, 21),
EndDate = new DateTime(2019, 05, 09),
Amount = 10000
},
new AmountPerPeriod
{
Id = 2,
StartDate = new DateTime(2019, 04, 02),
EndDate = new DateTime(2019, 04, 10),
Amount = 30000
},
new AmountPerPeriod
{
Id = 3,
StartDate = new DateTime(2018, 11, 01),
EndDate = new DateTime(2019, 01, 08),
Amount = 20000
}
};
var amountsPerMonth = lstAmmountPerPeriod.SelectMany(AmountPerMonth.FromPeriod);
Console.WriteLine("ID |month |year |amount");
Console.WriteLine("---|------|-------|--------");
Console.WriteLine(string.Join(Environment.NewLine, amountsPerMonth));
GetKeyFromUser("\n\nDone! Press any key to exit...");
}
Вывод
Примечание: Эти методы расширения были использованы в коде выше:
public static class Extensions
{
public static DateTime ToFirstDateOfMonth(this DateTime input)
{
return new DateTime(input.Year, input.Month, 1, input.Hour,
input.Minute, input.Second, input.Millisecond, input.Kind);
}
public static DateTime ToLastDateOfMonth(this DateTime input)
{
return new DateTime(input.Year, input.Month,
DateTime.DaysInMonth(input.Year, input.Month), input.Hour,
input.Minute, input.Second, input.Millisecond, input.Kind);
}
}