简体   繁体   English

给定的DateTime键在词典中不存在

[英]The given DateTime key was not present in the dictionary

I am a very beginner of C# and programming. 我是C#和编程的初学者。 I am trying to calculate a few DateTime variables. 我正在尝试计算一些DateTime变量。 The first one is called dDate and second dDate1 (the previous day of dDate ), third dDate2 (the second previous day of dDate , ie, the previous day of dDate1 ), the fourth dDate3 (the third previous day of dDate , ie, the second previous day of dDate1 and the previous day of dDate2 ). 第一种被称为dDate和第二dDate1 (前一天dDate ),第三dDate2 (第二前一天dDate ,即,前一天dDate1 ,第四) dDate3 (第三前一天dDate ,即dDate1的前第二天和dDate2的前一天)。 They must be not holidays or weekends! 他们一定不是假期或周末!

I've had all holidays and weekends stored in a dictionary called nd<DateTime, string> . 我已经将所有节假日和周末存储在名为nd<DateTime, string>的字典中。 The key DateTime has a series of date from 2011-01-01 to 2013-01-01 , step by one day and the value string is either TR or NT , a string variable but not boolean. 关键的DateTime具有从一系列日期2011-01-012013-01-01 ,一步一天,值string或者是TRNT ,一个字符串变量而不是布尔值。 If it is weekend or holiday, string is NT , otherwise TR . 如果是周末或假日,则字符串为NT ,否则为TR

What I am trying to do is when dDate is weekend or holiday, minus one day. 我想做的是dDate是周末或假日,减去一天。 For example, dDate is 2012-01-02 which is a holiday, change dDate to 2012-01-01 , and because it is weekend (Sunday), change it to 2011-12-31 , and it is weekend again, change dDate to 2011-12-30 . 例如, dDate是假期的2012-01-02 ,将dDate更改为2012-01-01 ,并且由于它是周末(星期日),所以将其更改为2011-12-31 ,再次是周末,则更改dDate2011-12-30 Same to dDate1 , dDate2 and dDate3 . dDate1dDate2dDate3

The problem here is my code works fine for dDate . 这里的问题是我的代码对于dDate可以正常工作。 But it gives an error: 但是它给出了一个错误:

the given key was not present in the dictionary 给定的键在字典中不存在

when I am doing the same thing for dDate1 , dDate2 or dDate3 . 当我为dDate1dDate2dDate3做同样的事情时。 The code is attached below: 该代码附在下面:

 private Dictionary<DateTime, string> noDates;
 ...
 noDates = new Dictionary<DateTime, string>();

 public void ImportNoDate()
 {
      string str;
      string[] line = new string[0];
      while ((str = reader.ReadLine()) != null) 
      {
         line = str.Split(',');
         String date = line[1];
         String flag = line[2];//flag is "NT" or "TR"
         String[] tmp = date.Split('-');
         date = Convert.ToInt32(tmp[0]) + "-" + Convert.ToInt32(tmp[1]) + "-" + Convert.ToInt32(tmp[2]);

         DateTime noDate = DateTime.Parse(date);
         noDates.Add(noDate, flag);
     }
  }

public void ImportdDate()
{
    ...
    DDates dd = new DDates(dDate, noDates); //dDate is defined similar to noDate, it is just another //series of date
}

    //DDates is an auxiliary cs file called DDates.cs
    public DDates(DateTime dd, Dictionary<DateTime, string> nd)
    {
         dDate1 = dDate.AddDays(-1);
         dDate1 = dDate.AddDays(-2);
         dDate3 = dDate.AddDays(-3);

       // dDate is imported from data file and has been Parse
      // to DateTime and it is something like
      // 2012-01-01 12:00:00 AM

     if (nd.ContainsKey(dDate))
     {
        while (nd[dDate].Contains("NT"))
       {
          dDate = dDate.AddDays(-1);
       }
    }

   //It works fine till here:
   if (nd.ContainsKey(dDate1))
   {
      //It gives "the given key was not present in the dictionary" here:
      while (nd[dDate1].Contains("NT"))
      {
        dDate1 = dDate1.AddDays(-1);
      }
   }
}

From your description it looks like what you are trying to do is for a given date find the first non holiday date. 从您的描述看来,您要针对给定的日期尝试查找第一个非假期日期。

Using a dictionary and storing every possible date is not the correct solution for this. 使用字典并存储每个可能的日期不是解决此问题的正确方法。

Personally I think a HashSet<DateTime> plus a little math would be the best solution. 我个人认为HashSet<DateTime>加上一些数学运算将是最佳解决方案。 In fact I was bored so I wrote it up 实际上我很无聊,所以我写下来

static class HolidayTester
{
    private static HashSet<DateTime> fixedHolidays = new HashSet<DateTime>(new DayOnlyComparer())
        {
            new DateTime(1900,1,1), //New Years
            new DateTime(1900,7,4), //4th of july
            new DateTime(1900,12, 25) //Christmas
        };


    /// <summary>
    /// Finds the most recent workday from a given date.
    /// </summary>
    /// <param name="date">The date to test.</param>
    /// <returns>The most recent workday.</returns>
    public static DateTime GetLastWorkday(DateTime date)
    {
        //Test for a non working day
        if (IsDayOff(date))
        {
            //We hit a non working day, recursively call this function again on yesterday.
            return GetLastWorkday(date.AddDays(-1));
        }

        //Not a holiday or a weekend, return the current date.
        return date;
    }


    /// <summary>
    /// Returns if the date is work day or not.
    /// </summary>
    /// <param name="testDate">Date to test</param>
    /// <returns>True if the date is a holiday or weekend</returns>
    public static bool IsDayOff(DateTime testDate)
    {
      return date.DayOfWeek == DayOfWeek.Saturday ||
             date.DayOfWeek == DayOfWeek.Sunday || //Test for weekend
             IsMovingHolidy(testDate) || //Test for a moving holiday
             fixedHolidays.Contains(testDate); //Test for a fixed holiday
    }


    /// <summary>
    /// Tests for each of the "dynamic" holidays that do not fall on the same date every year.
    /// </summary>
    private static bool IsMovingHolidy(DateTime testDate)
    {
        //Memoral day is the last Monday in May
        if (testDate.Month == 5 && //The month is May 
                testDate.DayOfWeek == DayOfWeek.Monday && //It is a Monday
                testDate.Day > (31 - 7)) //It lands within the last week of the month.
            return true;

        //Labor day is the first Monday in September
        if (testDate.Month == 9 && //The month is september
                testDate.DayOfWeek == DayOfWeek.Monday &&
                testDate.Day <= 7) //It lands within the first week of the month
            return true;


        //Thanksgiving is the 4th Thursday in November
        if (testDate.Month == 11 && //The month of November
            testDate.DayOfWeek == DayOfWeek.Thursday &&
            testDate.Day > (7*3) && testDate.Day <= (7*4)) //Only durning the 4th week
            return true;

        return false;
    }


    /// <summary>
    /// This comparer only tests the day and month of a date time for equality
    /// </summary>
    private class DayOnlyComparer : IEqualityComparer<DateTime>
    {
        public bool Equals(DateTime x, DateTime y)
        {
            return x.Day == y.Day && x.Month == y.Month;
        }

        public int GetHashCode(DateTime obj)
        {
            return obj.Month + (obj.Day * 12);
        }
    }
}

Now it does not follow your rules exactly, this code tests if a day is a work day and keeps walking backwards till it hits the first non work day. 现在,它不完全遵循您的规则,此代码测试一天是否为工作日,并一直向后走,直到遇到第一个非工作日为止。 It would be easy enough to modify, however I did not want to solve your problem exactly so you could learn a little (Unless I misunderstood the algorithm and I did solve the problem, in that case... your welcome) 修改起来很容易,但是我不想完全解决您的问题,因此您可以学习一些(除非我误解了算法,并且确实解决了问题,在这种情况下……不客气)

The way you would use it is simply put in a date and then use that to decide if you are going to return TR or NT 您将其使用的方式只是放在一个日期中,然后使用该日期来决定要返回TR还是NT

public static string GetDateLabel(DateTime testDate)
{
    if(HolidayTester.IsDayOff(testDate))
        return "NT";
    else
        return "TR";
}

If you want to know the last working day you can call that directly from HolidayTester.GetLastWorkday(DateTime) 如果您想知道最后一个工作日,可以直接从HolidayTester.GetLastWorkday(DateTime)致电

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM