【发布时间】:2018-05-29 21:32:52
【问题描述】:
我有两个 DateTime 变量,我需要计算它们之间的周数。
最快(和正确)的方法是什么?
【问题讨论】:
-
完整周数?如果是这样,一周从哪一天开始?还是相差天数/7?
-
你如何定义正确?你能举一些关于不同输入的预期结果的例子吗?
我有两个 DateTime 变量,我需要计算它们之间的周数。
最快(和正确)的方法是什么?
【问题讨论】:
使用TimeSpan:
double weeks = (date1 - date2).TotalDays / 7;
【讨论】:
TimeSpan。
更新:试试这个库:http://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET 作者已经想尽办法弄清楚所有这些细节。
我没有看到真正定义周是什么的答案。
这是一个陷阱,并非所有的星期都是平等的。有些算星期一,有些算星期四。
以这个月为例。如果我想计算 2012 年 8 月的周数,我可以这样做:
var date1 = new DateTime(2012,8,1);
var date2 = new DateTime(2012,8,31);
var weeks = (date1 - date2).TotalDays / 7;
一方面,.TotalDays 给了我们两倍: 周 == 4.2857...
我们可以四舍五入,但有时您会多算。其他时候你会功亏一篑。
计算周数通常取决于定义一周的开始和结束时间。使用 DateTime 对象,我们会发现每周都从星期一开始。
广泛使用的 ISO8601 标准定义了从星期四开始的一周。因此,两个日期之间的周数取决于有多少个星期四。
使用 GregorianCalendar 类实现类似的功能:
using System;
using System.Globalization;
using FluentAssertions;
using NUnit.Framework;
//...Namespace, test fixture class, etc ...
[Test]
public void GetMetricsTimesBetween_ReturnsCorrectRange() {
DateTime startDate = new DateTime(2012, 8, 1);
DateTime endDate = new DateTime(2012, 8, 31);
var cal = new GregorianCalendar();
int startWeekNumber = cal.GetWeekOfYear(startDate,
CalendarWeekRule.FirstDay,
DayOfWeek.Thursday);
int endWeekNumber = cal.GetWeekOfYear(endDate,
CalendarWeekRule.FirstDay,
DayOfWeek.Thursday);
int numberOfWeeksInRange = endWeekNumber - startWeekNumber;
numberOfWeeksInRange.Should().Be(5);
}
这应该会给你更可靠的结果。您必须考虑到这个例子是假设我们在同一年内计算周数。通过一些额外的工作,您可以帮助计算处理跨越不同年份的日期范围:
[Test]
public void GetCountOfWeeks() {
var startDate = new DateTime(2012, 12, 1); // 4 weeks here
var endDate = new DateTime(2014, 1, 10); // 52 in 2013 and 2 weeks in 2014
int numberOfWeeksInRange = 0;
var cal = new GregorianCalendar();
for (int year = startDate.Year; year <= endDate.Year; year++)
{
int startWeekNumber = 0;
int endWeekNumber= 0;
if(year == startDate.Year) { // start date through the end of the year
startWeekNumber = cal.GetWeekOfYear(startDate,
CalendarWeekRule.FirstDay, DayOfWeek.Thursday);
endWeekNumber = cal.GetWeekOfYear((
new DateTime(year + 1, 1, 1).AddDays(-1)),
CalendarWeekRule.FirstDay, DayOfWeek.Thursday);
} else if(year == endDate.Year) { // start of the given year through the end date
startWeekNumber = cal.GetWeekOfYear((new DateTime(year, 1, 1)),
CalendarWeekRule.FirstDay, DayOfWeek.Thursday);
endWeekNumber = cal.GetWeekOfYear(endDate,
CalendarWeekRule.FirstDay, DayOfWeek.Thursday);
} else { // calculate the number of weeks in a full year
startWeekNumber = cal.GetWeekOfYear(new DateTime(year, 1, 1),
CalendarWeekRule.FirstDay, DayOfWeek.Thursday);
endWeekNumber = cal.GetWeekOfYear((
new DateTime(year + 1, 1, 1).AddDays(-1)),
CalendarWeekRule.FirstDay, DayOfWeek.Thursday);
}
numberOfWeeksInRange += endWeekNumber - startWeekNumber;
}
numberOfWeeksInRange.Should().Be(58);
}
这仍然不完美,但更接近了。这里的重点是,如果您想获得像“周”这样的东西的真实计数,它并不像我们倾向于做的那么简单,这实际上更像是特定于语言环境的决定,而不是像 1 + 1 = 这样的标准科学表达式2. 将总天数除以 7 就像说所有“工作日”都是 9 到 5 一样模棱两可……
这是一个更好的例子。当然,仍然可以使用重构,但处理同一年份和跨多年的日期范围作为 GregorianCalendar 类的扩展:
/// <summary>
/// Returns the number of weeks between two datetimes
/// </summary>
/// <param name="cal"></param>
/// <param name="startDate"></param>
/// <param name="endDate"></param>
/// <returns></returns>
public static int GetWeeks(this GregorianCalendar cal,
CalendarWeekRule weekRule,
DayOfWeek dayofWeek,
DateTime startDate,
DateTime endDate) {
int startWeekNumber = 0;
int endWeekNumber = 0;
int numberOfWeeksInRange = 0;
if (startDate.Year == endDate.Year) {
startWeekNumber = 0;
endWeekNumber = 0;
startWeekNumber = cal.GetWeekOfYear(startDate,
weekRule,
dayofWeek);
endWeekNumber = cal.GetWeekOfYear(endDate,
weekRule,
dayofWeek);
numberOfWeeksInRange = endWeekNumber - startWeekNumber;
}
else { // calculate per year, inclusive
for (int year = startDate.Year; year <= endDate.Year; year++) {
startWeekNumber = 0;
endWeekNumber = 0;
if (year == startDate.Year) { // start date through the end of the year
startWeekNumber = cal.GetWeekOfYear(startDate, weekRule, dayofWeek);
endWeekNumber = cal.GetWeekOfYear((new DateTime(year + 1, 1, 1).AddDays(-1)),
weekRule, dayofWeek);
}
else if (year == endDate.Year) { // start of the given year through the end date
startWeekNumber = cal.GetWeekOfYear((new DateTime(year, 1, 1)),
weekRule, dayofWeek);
endWeekNumber = cal.GetWeekOfYear(endDate,
weekRule, dayofWeek);
}
else { // calculate the total number of weeks in this year
startWeekNumber = cal.GetWeekOfYear(new DateTime(year, 1, 1),
weekRule, dayofWeek);
endWeekNumber = cal.GetWeekOfYear((new DateTime(year + 1, 1, 1).AddDays(-1)),
weekRule, dayofWeek;
}
numberOfWeeksInRange += endWeekNumber - startWeekNumber;
}
}
return numberOfWeeksInRange;
}
【讨论】:
您可以尝试以下方法:
DateTime d1 = new DateTime(2006,10,1);
DateTime d2 = new DateTime(2007,10,15);
TimeSpan tt = d2 - d1;
int totalWeeks = tt.Days/7;
如果你也想要分数的精确差异,那么而不是:
int totalWeeks = tt.Days/7;
使用:
double totalWeeks = tt.TotalDays/7;
【讨论】:
(dtTo - dtFrom).TotalDays / 7
将给出周数
【讨论】:
public static int NumberOfWeeks(DateTime dateFrom, DateTime dateTo)
{
TimeSpan Span = dateTo.Subtract(dateFrom);
if (Span.Days <= 7)
{
if (dateFrom.DayOfWeek > dateTo.DayOfWeek)
{
return 2;
}
return 1;
}
int Days = Span.Days - 7 + (int)dateFrom.DayOfWeek;
int WeekCount = 1;
int DayCount = 0;
for (WeekCount = 1; DayCount < Days; WeekCount++)
{
DayCount += 7;
}
return WeekCount;
}
【讨论】:
你可以试试这样的:
var d1 = new DateTime(2011, 01, 05);
var d2 = new DateTime(2010, 01, 05);
Console.WriteLine((d1 - d2).Days / 7);
您可能需要根据您的确切要求将结果向上或向下舍入,但这应该可以解决问题。
【讨论】:
如果您尝试除以整数,它将不起作用。你必须分到两倍。
DateTime startDateTime = new DateTime(2010, 8, 1);
DateTime endDateTime = new DateTime(2010, 8, 28);
double weeks = (endDateTime - startDateTime).TotalDays / 7;
【讨论】: