简体   繁体   English

在C#中,找到DateTime数组中的间隙的最佳方法是什么?

[英]In C#, what is the best way to find gaps in a DateTime array?

I have a list of dates that are apart by a month in the sense that all dates are the "First Monday of the month". 我有一个相隔一个月的日期列表,因为所有日期都是“本月的第一个星期一”。 In some cases months are missing so I need to write a function to determine if all dates are consecutive 在某些情况下,几个月都会丢失,所以我需要编写一个函数来确定所有日期是否都是连续的

So for example if this was the list of dates, the function would return true as all items are the "First Friday of the month" and there are no gaps. 因此,例如,如果这是日期列表,则函数将返回true,因为所有项目都是“本月的第一个星期五”,并且没有间隙。 This example below would return true. 以下示例将返回true。

 var date = new DateTime(2013, 1, 4);
 var date1 = new DateTime(2013, 2, 1);
 var date2 = new DateTime(2013, 3, 1);
 var date3 = new DateTime(2013, 4, 5);

 var dateArray = new DateTime[]{date, date1, date2, date3};
 bool isConsecutive = IsThisListConsecutive(dateArray);

where this example below would return false because, even though they are also all "First Friday of the month", its missing the March 2013 item. 以下示例将返回false,因为即使它们也都是“本月的第一个星期五”,它也错过了2013年3月的项目。

 var date = new DateTime(2013, 1, 4);
 var date1 = new DateTime(2013, 2, 1);
 var date3 = new DateTime(2013, 4, 5);

 var dateArray = new DateTime[]{date, date1, date3};
 bool isConsecutive = IsThisListConsecutive(dateArray);

so i am trying to figure out the right logic for the IsThisListConsecutive() method: 所以我试图找出IsThisListConsecutive()方法的正确逻辑:

Here was my first try: (Note I already know upfront that all dates are same day of week and same week of month so the only thing i am looking for is a missing slot) 这是我的第一次尝试:(注意我已经预先知道所有日期都是一周的同一天和同月的一周,所以我唯一需要的是缺少的插槽)

  private bool IsThisListConsecutive(IEnumerable<DateTime> orderedSlots)
    {
        DateTime firstDate = orderedSlots.First();
        int count = 0;
        foreach (var slot in orderedSlots)
        {
            if (slot.Month != firstDate.AddMonths(count).Month)
            {
                return false;
            }
            count++;
        }
        return true;
    }

This code above works exept if the list crosses over from one year to another. 如果列表从一年跨越到另一年,则上面的代码将起作用。 I wanted to get any advice on a better way to create this function and how that line could be rewritten to deal with dates that cross over years. 我希望得到关于创建此函数的更好方法的任何建议,以及如何重写该行以处理跨越多年的日期。

So to implement this we'll start with a simple helper method that takes a sequence and returns a sequence of pairs that make up each item with it's previous item. 因此,为了实现这一点,我们将从一个简单的辅助方法开始,该方法接受一个序列并返回一系列对,这些对组成了每个项目的前一个项目。

public static IEnumerable<Tuple<T, T>> Pair<T>(this IEnumerable<T> source)
{
    T previous;
    using (var iterator = source.GetEnumerator())
    {
        if (iterator.MoveNext())
            previous = iterator.Current;
        else
            yield break;

        while(iterator.MoveNext())
        {
            yield return Tuple.Create(previous, iterator.Current);
            previous = iterator.Current;
        }
    }
}

We'll also use this simple method to determine if two dates are in the same month: 我们还将使用这种简单的方法来确定两个日期是否在同一个月中:

public static bool AreSameMonth(DateTime first, DateTime second)
{
    return first.Year == second.Year 
        && first.Month == second.Month;
}

Using that, we can easily grab the month of each date and see if it's the month after the previous month. 使用它,我们可以轻松获取每个日期的月份,看看它是否是上个月之后的月份。 If it's true for all of the pairs, then we have consecutive months. 如果所有对都是如此,那么我们连续几个月。

private static bool IsThisListConsecutive(IEnumerable<DateTime> orderedSlots)
{
    return orderedSlots.Pair()
        .All(pair => AreSameMonth(pair.Item1.AddMonths(1), pair.Item2));
}

I would recommend looking at the TimeSpan structure. 我建议看一下TimeSpan结构。 Thanks to operator overload you can get a TimeSpan by substracting two dates and then receive a TimeSpan that expresses the difference between the two dates. 由于运算符过载,您可以通过减去两个日期来获取TimeSpan ,然后接收表示两个日期之间差异的TimeSpan

http://msdn.microsoft.com/en-us/library/system.timespan.aspx http://msdn.microsoft.com/en-us/library/system.timespan.aspx

Note: This is completely untested, and the date checks are probably pretty bad or somewhat redundant, but that's the best I could come up with right now ^^ 注意:这是完全未经测试的,日期检查可能非常糟糕或有些多余,但这是我现在能想到的最好的^^

public bool AreSameWeekdayEveryMonth(IEnumerable<DateTime> dates)
{
    var en = dates.GetEnumerator();
    if (en.MoveNext())
    {
        DayOfWeek weekday = en.Current.DayOfWeek;
        DateTime previous = en.Current;
        while (en.MoveNext())
        {
            DateTime d = en.Current;
            if (d.DayOfWeek != weekday || d.Day > 7)
                return false;
            if (d.Month != previous.Month && ((d - previous).Days == 28 || (d - previous).Days == 35))
                return false;
            previous = d;
        }
    }
    return true;
}

okay, your code doesnt work when the years cross over becuase jan 1st may be a monday on one year and a tuesday on the next. 好吧,你的代码在岁月交叉时不起作用因为jan 1st可能是一年的星期一和下一个的星期二。 If I was doing this, I would first check that 如果我这样做,我会先检查一下

a) they are the same day of the week in each month (use DateTime.DayOfWeek) a)它们是每个月的一周中的同一天(使用DateTime.DayOfWeek)

b) they are the same week of the month in each month* use extension method DayOfMonth (see link) * Calculate week of month in .NET * b)它们是每个月的同一周*使用扩展方法DayOfMonth(参见链接)* 计算.NET *中的星期几 *

(you said you already know a & b to be true so lets go on to the third condition) (你说你已经知道a&b是真的所以让我们继续第三个条件)

c) we have to determine if they are in consecutive months c)我们必须确定它们是否连续几个月

//order the list of dates & place it into an array for ease of looping
DateTime[] orderedSlots = slots.OrderBy( t => t).ToArray<DateTime>();


//create a variable to hold the date from the previous month
DateTime temp = orderedSlots[0];


for(i= 1; index < orderedSlots.Length; index++)
{
    if((orderedSlots[index].Month != temp.AddMonths(1).Month |
        orderedSlots[index].Year  != temp.AddMonths(1).Year)){
        return false;
    }

    previousDate =  orderedSlots[index];
}

return true;

if you need to check conditions a & b as well add change the if statement as follows 如果您需要检查条件a和b以及添加更改if语句,如下所示

    if( orderedSlots[index].Month != temp.AddMonths(1).Month |
        orderedSlots[index].Year  != temp.AddMonths(1).Year) |
        orderedSlots[index].DayOfWeek != temp.DayOfWeek      |
        orderedSlots[index].GetWeekOfMonth != temp.AddMonths(1).GetWeekOfMonth){
        return false;
    }

remember that to use the get week of month extension method you have to include the code in Calculate week of month in .NET I'm sure there are typos as I did this in a text editor. 记住要使用get week of month扩展方法,你必须在.NET中包含计算星期几中的代码我确信在文本编辑器中有这样的拼写错误。

Well, here is my initial thought on how I would approach this problem. 好吧,这是最初想到如何解决这个问题。

First, is to define a function that will turn the dates into the ordinal values corresponding to the order in which they should appear. 首先,定义一个函数,它将日期转换为与它们应该出现的顺序相对应的序数值。

int ToOrdinal(DateTime d, DateTime baseline) {
   if (d.Day <= 7
       && d.DayInWeek == baseline.DayInWeek) {
      // Since there is only one "First Friday" a month, and there are
      // 12 months in year we can easily compose the ordinal.
      // (As per default.kramer's comment, months normalized to [0,11].)
      return d.Year * 12 + (d.Month - 1);
   } else {
      // Was not correct "kind" of day -
      // Maybe baseline is Tuesday, but d represents Wednesday or
      // maybe d wasn't in the first week ..
      return 0;
   }
}

var dates = ..;
var baseline = dates.FirstOrDefault();
var ordinals = dates.Select(d => ToOrdinal(d, baseline));

Then, for the dates provided, we end up with ordinal sequences like: 然后,对于提供的日期,我们最终得到序数序列,如:

[24156 + 0, 24156 + 1, 24156 + 2, 24156 + 3]

And

[24156 + 0, 24156 + 1, /* !!!! */ 24156 + 3]

From here it is just a trivial matter of iterating the list and ensuring that the integers occur in sequence without gaps or stalls - that is, each item/integer is exactly one more than the previous. 从这里开始迭代列表并确保整数按顺序出现而没有间隙或停顿只是一个小问题 - 也就是说,每个项目/整数正好比前一个更多。

I could be misinterpreting what you are trying to do, but I think this will work, assuming you don't have to handle ancient dates. 我可能会误解你想要做什么,但我认为这会有效,假设你不必处理古代日期。 See if there are any gaps in the dates converted to "total months" 查看转换为“总月数”的日期是否存在任何差距

int totalMonths = date.Year * 12 + (date.Month - 1);

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

相关问题 在C#中创建午夜DateTime的最佳方法 - Best way to create a Midnight DateTime in C# 在 C# 中创建只读数组的最佳方法是什么? - What's the best way of creating a readonly array in C#? 在C#中将short []数组写入文件的最佳方法是什么? - What's the best way to write a short[] array to a file in C#? 在C#中比较2个整数列表/数组的最佳方法是什么? - What is the best way to compare 2 integer lists / array in C# 将项目添加到C#数组的最佳方法是什么? - What's the best way to add an item to a C# array? 在C#中,将一个DateTime集合聚合和转换为另一个DateTime集合的最佳方法是什么? - In C#, What is the best way to aggregate and transform one DateTime collection into another? 测试ac#DateTime是分钟,小时,月等的最佳方法是什么 - What is the best way to test that a c# DateTime is a minute, hour, month, etc 在 C# 中比较两个 DateTime 的相等性的最佳方法是什么……但只能达到一定的精度? - What's the best way to compare the equality of two DateTime's in C#… but only to a certain precision? 在C#中,按DateTime排序的最佳方法是什么? 并在末尾有空的? - In C#, what is the best way to sort by DateTime? and have the empty ones at the end? 是否有将 DateTime 插入数组 C# 的最佳方法 - Is there an optimal way to insert a DateTime into an array C#
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM