【发布时间】:2009-07-07 17:09:16
【问题描述】:
我正在创建一个图书馆管理系统。
我已经使用时间戳来计算日期差异,并且在日期差异的帮助下我也在计算罚款。
现在这个日期差异包括一周中的所有天。但是对于图书馆申请,罚款应该只收取每周 6 天(周一至周六)的费用。
我做不到。
谁能帮我完成这项任务?
提前致谢!!
【问题讨论】:
标签: c#
我正在创建一个图书馆管理系统。
我已经使用时间戳来计算日期差异,并且在日期差异的帮助下我也在计算罚款。
现在这个日期差异包括一周中的所有天。但是对于图书馆申请,罚款应该只收取每周 6 天(周一至周六)的费用。
我做不到。
谁能帮我完成这项任务?
提前致谢!!
【问题讨论】:
标签: c#
本质上,您可以计算原始天数;您需要找到要从该数字中减去的星期日数。您知道每 7 天是一个星期天,因此您可以将原始天数除以 7,然后从原始天数中减去该数字。现在您需要删除一周剩余时间内存在的星期日数;原始天数的 mod 会告诉您剩余的天数。要确定该跨度是否包括星期日,您必须知道第一天是星期几;如果您将星期一定义为 0,星期二定义为 1,星期三定义为 3,等等,那么如果您将跨度开始的星期几的值添加到原始数量的 mod (7)天,如果数字是 6 或更大,则您已经跨越了一个额外的星期日,应该从您的罚款数字中删除 1 天。
在伪代码中:
int fine;
int numdays = endDay - startDay;
fine = numdays - (numdays / 7);
int dayOfWeek = startDate.DayOfWeek;
if (dayOfWeek + (numdays % 7) > 6)
{
fine = fine - 1;
}
【讨论】:
这样就可以了:
private int DaysLate(DateTime dueDate, DateTime returnDate)
{
var ts = returnDate - dueDate;
int dayCount = 0;
for (int i = 1; i <= ts.Days; i++)
{
if (dueDate.AddDays(i).DayOfWeek != DayOfWeek.Sunday)
dayCount++;
}
return dayCount;
}
【讨论】:
基于 Jacob Proffitt 的回答,但没有内存列表的开销。由于 DaysBetween 动态生成其日期,因此在生成列表时计算计数:
int c = DaysBetween(begin, end).Count(d => d.DayOfWeek != DayOfWeek.Sunday);
private IEnumerable<DateTime> DaysBetween(DateTime begin, DateTime end)
{
for(var d = begin; d <= end; d.AddDays(1)) yield return d;
}
当然,如果您不想炫耀 LINQ,您可以简化它并使用一个功能:
private int DaysBetween(DateTime begin, DateTime end)
{
int count = 0;
for(var d = begin; d <= end; d.AddDays(1))
if(d.DayOfWeek != DayOfWeek.Sunday) count++
return count;
}
恕我直言,这两者都比大家最喜欢的(乌鸦的回答)更清晰、更容易理解、调试、故障排除和修改。
当然,这是一个 O(n) 的解决方案,这意味着相隔的天数越多,计算所需的时间就越长。虽然这对于大多数现实世界的应用程序来说可能没问题,但在某些情况下,您可能更喜欢基于公式的方法,类似于以下内容:
int q = end.Subtract(begin).Days - (end.Subtract(begin).Days / 7);
【讨论】:
对此进行了快速测试,似乎可以满足您的目的:(编辑:为清晰起见添加了一些 cmets 并更正了代码错误)
private static int CalculateDaysToFine(DateTime dateDue, DateTime dateIn)
{
TimeSpan ts = dateIn - dateDue;
int daysToFine = ts.Days - (ts.Days/7); //subtract full weeks (1 Sunday each)
if (((int)dateDue.DayOfWeek + (ts.Days%7)) >6) //check to see if the remaining days contain a Sunday
daysToFine--;
return daysToFine;
}
【讨论】:
这是我的实现。我的目标是使用与 McWafflestix 类似的方法的 O(1) 执行时间。我试图保持它的可读性,最大化 OO 代码并尽可能减少“数学魔法”(并不是说我反对数学……或者魔法)。
这个想法是确定截止日期和返回日期之间完整的 7 天周数,以及一个“增量”天数来调整它以更正该数字。只要您能保证到期日和退货日期都不在星期日(我认为根据您的描述不会有问题),这将按预期工作。
static int CalculateFineDays(DateTime due, DateTime returned)
{
TimeSpan ts = returned - due;
if (ts < TimeSpan.Zero)
return 0;
int delta = returned.DayOfWeek - due.DayOfWeek;
return delta + ts.Subtract(TimeSpan.FromDays(delta)).Days * 6 / 7;
}
编辑:我之前提出了一个解决方案,并在其中发现了一个错误,并且在我处理它时,我将代码缩减为这个。
【讨论】:
我的 Linqy 方法(具有更易于阅读的优点,但在创建结构类型列表时对性能的影响很小):
private int DaysLate(DateTime dateDue, DateTime dateReturned)
{
return getDayList(dateDue, dateReturned).Where(d => d.DayOfWeek != DayOfWeek.Sunday).Count();
}
private List<DateTime> getDayList(DateTime begin, DateTime end)
{
List<DateTime> dates = new List<DateTime>();
DateTime counter = begin;
while (counter <= end)
{
dates.Add(counter);
counter = counter.AddDays(1);
}
return dates;
}
【讨论】: