简体   繁体   中英

C# - Excel date not passing date serial in Value2

I have an Excel sheet with a list of people's birthdays that reads like this:

Mary  08/17/1993
John  01/23/1991
Ann   12/07/1989

Where the left column has a 'GENERAL' format, and the right column has a 'DATE' format. The intent is to have a windows service that will be reading this list of birthdays every day and send out any "Happy Birthday!" emails that apply.

This is the code I'm using for reading the excel data:

public static List<Tuple<string, DateTime>> getBirthdays()
{
    List<Tuple<string, DateTime>> birthdays = new List<Tuple<string, DateTime>>();

    Excel.Application xlApp = new Excel.Application();
    Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(@"C:\Users\AGuaja\Desktop\birthdays.xlsx");
    Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
    Excel.Range xlRange = xlWorksheet.UsedRange;

    int rowCount = xlRange.Rows.Count;
    int colCount = xlRange.Columns.Count;

    string user = String.Empty;
    DateTime bday = DateTime.Now;

    for (int i = 1; i <= rowCount; i++)
    {
        for (int j = 1; j <= colCount; j++)
        {
            if (xlRange.Cells[i, j] != null && xlRange.Cells[i, j].Value2 != null) 
            {
                if (j == 1)
                    user = xlRange.Cells[i, j].Value2.ToString();
                else
                    bday = DateTime.FromOADate(double.Parse(xlRange.Cells[i, j].Value2));
            }
        }
        birthdays.Add(new Tuple<string, DateTime>(user, bday));
    }

    GC.Collect();
    GC.WaitForPendingFinalizers();

    Marshal.ReleaseComObject(xlRange);
    Marshal.ReleaseComObject(xlWorksheet);

    xlWorkbook.Close();
    Marshal.ReleaseComObject(xlWorkbook);

    xlApp.Quit();
    Marshal.ReleaseComObject(xlApp);

    return birthdays;
}

After searching around for a bit I learned that the correct way to get a date from Excel was to use the FromOADate method, which expects a double value in the form of 40599, for instance, to represent a date. The thing is however, that my Value2 is not returning that date serial, but instead the value in the format seen above, 12/07/1989, and as such I'm not able to use the 'proper way' of converting Excel dates.

I mean, sure, I can just use Value2 's string and parse that as a Date, but why is the value not being passed on properly in the first place?

I think you may be making this more complicated than it has to be. If you are simply looking for a date from the cell… use a DateTime.TryParse(…) . You will have to do this any way as in Excel even if the column is set as a Date the user can pretty much type whatever they want. The point being that you cannot depend on excel to return a VALID date, so simply check to see if it is valid and react appropriately. The code below will do this.

DateTime cellDate;
if (DateTime.TryParse(xlRange.Cells[i, j].Value, out cellDate)) {
  Console.WriteLine("Valid Date: " + cellDate.ToLongDateString());
}
else {
  Console.WriteLine("Date Is Invalid: " + xlRange.Cells[i, j].Value);
}

Hope this helps!

Edit for OP Answer

I am glad you found the problem you were having. I must say however that I think you are still missing my point. You cannot depend on an Excel Cell having a proper value. In most cases, if you get values from excel cells and you want to use those values in your program for something other than strings, you MUST validate this value simply to prevent your code from crashing. In your fix… you are simply making sure the value in the excel cell is formatted properly. In the future, if you inadvertently type in the wrong format your program will crash. This would be undesirable in any environment.

Using your example of sending out a birthday email or eCard is trivial and not that important unless someone really wants their birthday eCard. In this “birthday” case ignoring the invalid data is acceptable; however it may be nice to know why it didn't get sent. In your current code you will be made aware of this situation by crashing. So you have to go and look for the invalid date if it's important enough and fix it in excel.

Given your description let's assume it WAS important enough to try and fix the invalid date. There are several issues that arise here. As you said in your answer you had the MM/dd/YYYY(US) dates that were defaulting to the dd/MM/YYYY format ... In this case only “YOU” would know this. If someone else typed in the date you could not possibly know if 03/10/1997 was correct or 10/03/1997 was correct as BOTH are valid dates. In this case it would simply be the wrong birthday date, either typed in by you or another user. There is absolutely zero you can do to prevent this from happening as both dates are valid. If a large company makes this mistake, it may never be known until the customer complains that they are getting their birthday eCard on the wrong date.

Lastly, as I started, your current code has a bug and will crash if the date is in an invalid format. The problem here is that YOU know this, and do not address this situation in your code. This is the wrong approach; fix your code so it doesn't crash.

So after some debugging I realized what the problem was. I had entered MM/dd/YYYY (US) dates that were defaulting to the dd/MM/YYYY format instead. And though the string was technically correct, the date itself was invalid of course, which is why no date serial was being passed.

Changing the date to match the correct format (or alternatively specifying the US convention for them) solved the problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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