C# Excel Date value is coming as numeric value - c#

An excel file is generated by a third party app. I am writing a utility to further process that Excel file. When I read a column containing date value, I am getting a numeric string like 05/02/2016 (dd/MM/yyyy) is coming as 42405.
I have tried using .Text, .Formula, .Value, .Value2 - all the approaches are returning the numeric value.
I know about FromOADateTime, but my requirement is to read the date value as a string, exactly the way it is displayed on the screen.
Thanks.
EDIT 1:
When I convert the column to Text in Excel, by using Format Cells and selecting Text, all the date values convert to numeric values even in Excel! Does that give any clue? Probably the third party app stores the data as numeric value, but Excel displays it as a date string on screen. I want to read the value displayed on screen.
EDIT 2:
This problem does not come with all the date values in that column. My first impression is that the third party app is not consistent while writing date values to Excel. But I have no control over it.
EDIT 3:
Here is the link to download file: http://wikisend.com/download/316956/Prob.xls . In this file, I need to read all date values in Column B as text starting from Row 13
And here is the link to the screenshot of how it looks in my machine: http://wikisend.com/download/443994/Screenshot1.jpg
EDIT 4:
Found the culprit in my code with the help of NineBerry's answer: a few lines before reading the Text property, I was calling ws.Columns.ClearFormats() and ws.Rows.ClearFormats();
I needed to do this as per this: How to get the range of occupied cells in excel sheet…, in order to correctly get the used range in the sheet!
The original problem is solved. Now the problem is how to use ws.UsedRange without calling ClearFormats() to correctly get the range of used cells.
My specific requirement is to get the range of used ROWS having data in any cells up to Col H. I Dont need the entire UsedRange in Excel, UsedRange within Col H is good enough for me.
Any solutions to this? Or should I post a new thread?

Using the Text property does give the string that would be displayed to a user.
private void button_Click(object sender, EventArgs e)
{
string path = #"C:\Test.xlsx";
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Workbook wb = excel.Workbooks.Open(path);
Worksheet excelSheet = wb.ActiveSheet;
//Read a specific cell
Range cell = excelSheet.Cells[1, 3] as Range;
// Show text content
MessageBox.Show(cell.Text);
wb.Close();
}
If you don't see here what you see in Excel, you have to give us more details. Maybe provide a sample Excel file where a cell does not behave as expected.
This code DOES output the content of the second column in the file provided exactly as displayed in Excel:
private void button1_Click(object sender, EventArgs e)
{
string path = #"D:\Downloads\Windows\Prob.xls";
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();
Workbook wb = excel.Workbooks.Open(path);
Worksheet excelSheet = wb.ActiveSheet;
//Read a specific cell
for (int i = 1; i <= 150; i++ )
{
Range cell = excelSheet.Cells[i + 1, 2] as Range;
textBox1.AppendText(cell.Text + Environment.NewLine);
}
wb.Close();
}
If you don't see that, you should check that you are actually reading the correct file, and that you do not modify the file yourself from code before reading.

Related

Setting cell using excel introp changes date

I'm trying to enter a date value into an excel file.
For e.g.
"05/07/19" (July 5th of 2019) and the date formate of the cell in the excel is set to "dd-MM-yy" (regional setting of the computer is also the same). But when my code enters the value into excel, value is getting changed to "07-05-19" (May 7th of 2019).
I want it to stay as "05-07-19" and also excel should consider it as a date.
I have tried different ways to set the value into an excel,
const string DATE = "05/07/19";
Application app = new Application();
Workbook workBook = app.Application.Workbooks.Open(FILE_PATH);
Worksheet sheet = workBook.Sheets[1];
Range range = sheet.get_Range("A1");
range.set_Value(XlRangeValueDataType.xlRangeValueDefault, DATE);
Range range2 = app.get_Range("A1", "A2");
range2.Cells[2, 1] = DATE;
Range range3 = app.get_Range("A3", "A3");
range3.Value = DATE;
Range range4 = app.get_Range("A4", "A4");
//Of course, It is not setting the value as a Date but text.
range4.Value = new string[] { DATE };
I want my code to behave as per the formate of the cell. If the input can be fit as a date (based on the cell formate for date), it should be considered as a date, else just a text. (The way excel behaves when the user manually input the data)
UPDATE:
So far I got to know that runtime version of excel interop (File version: 15.0.4420.1017) is v2.0 and If I run my code with target framework .Net 3.5, it is working as expected.
But the same code is having the problem if I change the target framework to .Net 4.6
Do we know, if there may any compatible interop available for .Net 4.6?
Please set the number format for the relevant cells.
As an example, do like this:
range2.NumberFormat = "DD/MM/YYYY";
Ideally excel reacts on values based on default settings and if we wish to retain our own formatting while passing values we have to prepare our destination first then put value.
I would say the code which should work as:
range2.Numberformat="dd-mm-yy";
range2.Value=DATE;

Applying formatting to a big range

I'm trying to use the Excel Interop C# libraries to copy cell formatting from one cell to a range of other cells. To do this, I'm using the following code:
var excelWrapper = new Application();
excelWrapper.DisplayAlerts = false;
var workBook = excelWrapper.Workbooks.Open(#"C:\myFile.xlsx");
Worksheet ws = workBook.Sheets[1] as Worksheet;
Range formatSource = ws.Cells[8, 1] as Range; //cell containing formatting that I want to apply
Range startCell = ws.Cells[9, 1] as Range; //first cell to format
Range endCell = ws.Cells[300, 1] as Range; //last cell to format
Range formatTarget = ws.Range[startCell, endCell];
//Copy formatting from source cell to destination range
formatSource.Copy();
formatTarget.PasteSpecial(XlPasteType.xlPasteFormats, XlPasteSpecialOperation.xlPasteSpecialOperationNone, false, false);
As you can see, I'm applying the format from cell [8,1] to the entire range [9,1] -> [300,1].
The problem I'm having is that this only applies the formatting to the first ~80 or so cells, after that the formatting is not applied. In particular, the formatting stops after row 91, so it is only applied to the first 84 of the 291 cells in the range.
I don't understand why the formatting is not applied to the entire range I selected, but only to the first 84 cells. What am I missing here? Note that the range I'm applying the style to starts empty (I write the data only after setting the formatting), so it isn't a problem derived from the data in the cells.
Well, I figured it out: the excel file looked empty, but actually it contained a table that stopped at row 91. Evidently, when you paste a format to a range that is "hybrid" (half inside table and half normal cells) the format only gets applied to the portion inside the table.

Spreadsheetgear set data flags for specific column?

I am attempting to do this:
IWorksheet worksheet = Factory.GetWorkbook().Worksheets[0];
IRange range = worksheet.Cells["A1"];
range.CopyFromDataTable(dataTable, SetDataFlags.None);
worksheet.Cells.Columns.AutoFit();
return worksheet;
This works great normally, however I've run into an issue. I have one column that has a really long number, possibly with zeroes in the front and I need it to be entered and displayed as text. If I do a lookup of that particular cell like:
var cell = range["U34"].Value;
The data has already been turned into scientific notation so no amount of formatting afterwards fixes it. I tried SetDataFlags.AllText and that works great, except it breaks the rest of the worksheet because all of the numbers are stored as text, which is unacceptable.
I'm at a loss of how to fix this.
Solution:
Since I'm just looking to change one column, if it's present and a lot of the columns are dynamic I went with the "preformatting" route. Find the column index from the datatable:
int ColumnIndex = -1;
for (int x = 0; x < dataTable.Columns.Count; x++)
{
if (dataTable.Columns[x].ColumnName.Equals("Whatever"))
{
ColumnIndex = x;
}
}
worksheet.Cells[0, ColumnIndex, 0, ColumnIndex].EntireColumn.NumberFormat = "#";
Then perform the CopyFromDataTable, with Flags set to None and everything is perfect!
The IRange.CopyFromDataTable(...) method can be passed in a SetDataFlags.InsertCells enum option, which allows you to pre-format your destination range so that the inserted DataTable data picks up the formatting you specify. This formatting includes a cell's IRange.NumberFormat, which can be set to "#" and specifies that input to that cell should be treated as Text.
So, if you know what columns will have these unusually-large numbers that trigger scientific notation, another option would be to pre-format your worksheet's destination range with IRange.NumberFormat = "#" and will preserve your values for these columns as-is.
Please see the documentation for the IRange.CopyFromDataTable(...) method, as it provides important information on what range needs this "pre-formatting." Also, assuming you've installed SpreadsheetGear on your machine, check out the Reporting > DataSet to Workbook example in the SpreadsheetGear Explorer Solutions for C#/VB (found in the "SpreadsheetGear" folder under the Start Menu) for a live demo of this SetDataFlags.InsertCells option.

C# Interop Excel format like Excel's format as table

I'm exporting a table from SQLite to Excel (2010) in C#. It works fine. I'm using the Excel.Range.set_Value() method.
How can I format an Excel.Range like Excel's format (like a table) would?
To expand upon my comment and add to D Stanley.
Range range = ws.get_Range("A1:D5");
wrksheet.ListObjects.AddEx(XlListObjectSourceType.xlSrcRange, range, missing, Microsoft.Office.Interop.Excel.XlYesNoGuess.xlNo, missing).Name = "MyTableStyle";
wrksheet.ListObjects.get_Item("MyTableStyle").TableStyle = "TableStyleMedium1";
This example selects a rectangular range of every cell in the active sheet. Also, it uses indexed parameters of Range to get the range points. Furthermore, AddEx() (and most methods in Interop.Excel) uses default parameters so you don't have to use System.Reflection.Missing.
// define points for selecting a range
// point 1 is the top, leftmost cell
Excel.Range oRng1 = oSheet.Range["A1"];
// point two is the bottom, rightmost cell
Excel.Range oRng2 = oSheet.Range["A1"].End[Excel.XlDirection.xlToRight]
.End[Excel.XlDirection.xlDown];
// define the actual range we want to select
oRng = oSheet.Range[oRng1, oRng2];
oRng.Select(); // and select it
// add the range to a formatted table
oRng.Worksheet.ListObjects.AddEx(
SourceType: Excel.XlListObjectSourceType.xlSrcRange,
Source: oRng,
XlListObjectHasHeaders: Excel.XlYesNoGuess.xlYes);
Here's the VBA that does it:
ActiveSheet.ListObjects.Add xlSrcRange, Range("$J$10:$N$12"), , xlYes
Shouldn't be too hard to translate into an automation call. You can read the documentation as well.

Edit Range NumberFormat in existing document

I can't change column format in an existing Excel document (xlsx). Columns content are numbers actually but shown as text and therefore green triangle appear telling that cells shown as text.
So I open this document in C# app and do the following thing:
sheet_.Range[sheet_.Cells[1, 2], sheet_.Cells[rowNum, 2]].EntireColumn.NumberFormat = "0";
But it doesn't change column to appear content as numbers (they remain aligned by left side)
I know this is an old post, but I've been dealing with the same problem. I receive .xlsx files that already have green triangles denoting "Number as Text" errors. I couldn't find a way to programmatically run the Excel error-checking command "Convert to Number" that you can do by clicking in Excel, and changing the NumberFormat on cells with these errors didn't work for me, but I was able to "refresh" the cell format by using the TextToColumns method.
int lastCol = sheet.UsedRange.Columns.Count;
if(lastCol > 1)
{
for (int i = 1; i <= lastCol; i++)
{
sheet.Columns[i].TextToColumns(Type.Missing, XlTextParsingType.xlDelimited, XlTextQualifier.xlTextQualifierNone);
}
And from there you can change the NumberFormat. I happened to have long integers that were getting put into scientific notation, so I used this to make them regular integers again:
sheet.Cells.NumberFormat = "#";
(PS, if anyone finds a definitive guide on the symbols to use for customized NumberFormats, I'm still trying to find one!)
Try to access to cell value over get_Range method! for example and for what number format you want, lets say that you have in your excel cell this number : 1546,65
sheet_.get_Range("P10", "Q10").NumberFormat = "0"; // returns 1546
sheet_.get_Range("P10", "Q10").NumberFormat = "0,00"; // returns 1546,65
sheet_.get_Range("P10", "Q10").NumberFormat = "#.##0,00"; // returns 1.546,65
And you can play with these number formats!
Hope it helps you
I didn't find ideal solution to this issue and ended with the following:
sheet_.get_Range("A1", "A100").NumberFormat = "0";
for(int i = 1; i <= 100; i++)
{
sheet_.Cells[1, i].Value = sheet_.Cells[1, i].Value;
}
I know this is a old post but I stumbled over this and have a solution for this. Have you tried to not assign any NumberFormat? by default excel decides based on the cell content so you wouldnt get green triangle if you have numbers which are stored as text. If you want read values based on data type then refer this post
http://www.codeproject.com/Articles/335589/Export-Multiple-Datasets-to-Multiple-Excel-sheets
For me using the Style and the NumberFormatLocal solved the problem:
sheet_.get_Range("A1", "A100").Style.NumberFormatLocal = "0";

Categories