range.set_Value formatting for dates in Excel VSTO - c#

The following code puts date values into excel, but for some reason they are not automatically formatted as date. If I enter these dates manually – they get formatted automatically. Excel is running on Windows with European locale setting. How do I make Excel format the dates automatically? I can't explicitly apply formatting as the range I'm putting into excel may contain columns of different data types and the whole range has to be inserted in one shot for performance reasons.
string[,] arr = new string [2, 2];
arr[0, 0] = "Date";
arr[0, 1] = "DateTime";
arr[1, 0] = "21/12/2018";
arr[1, 1] = "26/12/2019";
Range rng = Globals.ThisAddIn.Application.ActiveSheet.Range["A1:B2"];
rng.set_Value(XlRangeValueDataType.xlRangeValueDefault, arr);
UPDATE:
I've actually narrowed it down to the following:
string dt = DateTime.Now.ToString(System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat);
worksheet.Range["A1"].Value = dt;
It's bizarre, the string is formatted according to the user's locale setting, but when I insert it into excel in the second line – Excel for some reason converts it to US format. So with european date format setup in Windows, if the string is "11/03/2019", what I see in Excel after I run the code is "03/11/2019".

Related

C# DateTime from Excel turns into float number

I have an excel file in the first column which contains dates in the format dd.MM.yyyy hh:mm:ss. I'm trying to display data from an excel table in datagridview, but the date is displayed as a float number.
I tried to convert the date to the desired format in this way, but it does not work:
worksheet.Cells[2, 1, endCell.Row, 1].Style.Numberformat.Format = "dd.MM.yyyy hh:mm:ss";
The full code of my method:
public static DataTable readTableFromExcel(FileInfo file)
{
DataTable table = new DataTable();
Console.WriteLine(file.Exists);
using (ExcelPackage package= new ExcelPackage(file))
{
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
ExcelWorksheet worksheet = package.Workbook.Worksheets[0];
ExcelCellAddress startCell = worksheet.Dimension.Start;
ExcelCellAddress endCell = worksheet.Dimension.End;
ExcelRange range = worksheet.Cells[startCell.Row, startCell.Column, endCell.Row, endCell.Column];
ExcelTable excelTable = worksheet.Tables.Add(range, "table");
Console.WriteLine(worksheet.Cells[2, 1].Value.ToString());
table = excelTable.ToDataTable();
}
return table;
}
String with Console.Writeline outputs 44912,0912268519 instead of 17.12.2022 2:11:22.
Then I output the data to datagridview: tableView.DataSource = table;
And it looks like: https://i.stack.imgur.com/aXx6V.png
File used: https://drive.google.com/drive/folders/1hXKmKs_F7EyO5GdVU3HVATxDLlFWO4jk?usp=share_link
How can I display the datetime correctly?
In Excel, dates and times are stored as a floating point number representing the number of days since the epoch date of January 1, 1970. This means that when you read a date or time value from an Excel file into a C# DateTime object, you will need to convert the floating point value to a DateTime object.
// Assume that the Excel date value is stored in a variable called "excelDate"
// Convert the Excel date value to a DateTime object
DateTime dateTime = DateTime.FromOADate(excelDate);
system.datetime.fromoadate

How to make format mask in DataGridView cell?

I need to make a format/mask in a cell that prevents the user from entering data that isn't relevant.
The column cell contains date values like "MM/YYYY" without a day value.
I tried the following to make this definition but without success:
dataGridView1.Columns[0].DefaultCellStyle.Format = "##/####" // || dd/yyyy
Also, I tried to go to the properties of DataGridView and define Format from there.
The method you're using for formatting is a valid approach. There are a few issues that may be happening here. Please ensure:
The underlying data is of type DateTime and not type string. Type string will not apply the format as expected. (See columns 1 and 2 in example below.)
The individual DataGridViewTextBoxCell.Style.Format isn't being set to something different than your desired format. This would override the column formatting. (See column 3 in example below.)
EXAMPLE
this.dataGridView1.ColumnCount = 4;
this.dataGridView1.RowCount = 1;
this.dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
DateTime date = DateTime.Now;
this.dataGridView1[0, 0].Value = date;
this.dataGridView1[1, 0].Value = date.ToString();
this.dataGridView1[2, 0].Value = date.ToString("MM/yyyy");
this.dataGridView1[3, 0].Value = date;
this.dataGridView1[3, 0].Style.Format = "MM/yyyy";
this.dataGridView1.Columns[0].DefaultCellStyle.Format = "dd/yyyy";
this.dataGridView1.Columns[1].DefaultCellStyle.Format = "dd/yyyy";
this.dataGridView1.Columns[2].DefaultCellStyle.Format = "dd/yyyy";
this.dataGridView1.Columns[3].DefaultCellStyle.Format = "dd/yyyy";
As you can see from the output:
Columns[0] contains a DateTime and correctly formats as "dd/yyyy".
Columns[1] contains a string and cannot be reformatted to "dd/yyyy".
Columns[2] contains a formatted string and cannot be reformatted to "dd/yyyy".
Columns[3] contains a DateTime and formatting is overridden by the cell format "MM/yyyy".
To correct these issues, just set your cell value using the DateTime object and not any string representation.
In the case where you are getting this data from some outside source and it's already of type string, you can Parse it, but note that the missing portions of the DateTime object will be defaulted and there's really nothing you can do about that without having the original full data:
DateTime date = DateTime.Parse("10/2016");
Console.WriteLine("Output: {0}", date.ToString());
// Output: 10/1/2016 12:00:00 AM
Validation
If validating user input (and losing formatting on edits) is your main concern, consider the following method for validation to cancel an invalid edit:
private void DataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
DateTime parsed;
if (!DateTime.TryParse(e.FormattedValue.ToString(), out parsed))
{
this.dataGridView1.CancelEdit();
}
}
Coupled with this answer for reapplying your format using the DataGridView.CellFormatting event handler. (Note that this also negates the need to ensure your data types are not string, but is more costly due to the event being triggered often.)

C# Excel Interop Charts with multi series - X axis as DateTime

I have an excel addin implemented in C#. This connects to a server and obtains <key, value1, value2, value3..> pairs, where key is DateTime.
After data is fetched, this is populated in Excel worksheet. This data is used to plot multi-series line graph.
I am using ChartWizard and on the Chart object I add multiple series using .NewSeries option.
What is the best way to specify that my X axis is DateTime. I see the behaviour differs when I use ScatterLines or XLLines. I am unable to find an approach where I can say to the chart that my X axis is DateTime and specify a dateformat to same
Any help will be appreciated.
Vikron
Microsoft.Office.Tools.Excel.Chart chart = worksheet.Controls.AddChart(0, 0, xx, yy, "Trend");
chart.ChartWizard(Type.Missing,
Microsoft.Office.Interop.Excel.XlChartType.xlXYScatterLines,
Type.Missing,
XlRowCol.xlColumns,
Type.Missing,
Type.Missing,
true,
"Trend",
"Time stamp",
Type.Missing,
Type.Missing);
chart.AutoScaling = false;
chart.ChartStyle = 34;
chart.Legend.Position = XlLegendPosition.xlLegendPositionBottom;
chart.HasTitle = true;
chart.ChartType = XlChartType.xlXYScatterLines;
chart.ChartTitle.Text = "Trend";
foreach (series)
{
Excel.Series xlSeries = (Excel.Series)((Excel.SeriesCollection)chart.SeriesCollection()).NewSeries();
Microsoft.Office.Interop.Excel.Range seriesRange = worksheet.get_Range(series.seriesBeginRange,
worksheet.get_Range(series.seriesBeginRange).get_End(XlDirection.xlDown));
xlSeries.Name = series.seriesName;
xlSeries.XValues = timeSeriesRange; //This has datetime
xlSeries.ChartType = Microsoft.Office.Interop.Excel.XlChartType.xlXYScatterLines;
xlSeries.Values = seriesRange;
}
cell.NumberFormat = "MM/dd/yy HH:mm";
cell.Value = ts;
Found, if not best, something that works for me. When I was populating with DateTime formatted to the desired date time display pattern, the Cell type was getting set to "General" and of-course the value was treated as "String", with this xlLines did worked perfectly. Then the problem with this is that user will not be able to modify the DateTime format into a different display pattern as the cells were updated as "String".
Now, I populate the Excel cell with C# DateTime object. I set the format as
cell.NumberFormat = "m/d/yy h:mm;#";
To obtain the exact NumberFormat to Format Axis=>Number=>Category=>Format Code properties in Excel. This will let Excel treat the Type as Time and user can modify the date time format. Then, I modified to xlXLScatterLines, modified Tickspaces as below:
Axis xAxis = (Excel.Axis)chart.Axes(Excel.XlAxisType.xlCategory);
TickLabels ticks = xAxis.TickLabels;
xAxis.MinimumScale = timeSeriesRange.Value2[1, 1];
xAxis.MaximumScale = timeSeriesRange.Value2[timeSeriesRange.Count, 1];
xAxis.MajorTickMark = XlTickMark.xlTickMarkCross;
xAxis.MinorTickMark = XlTickMark.xlTickMarkInside;
xAxis.MajorUnit = 0.005;
xAxis.HasMinorGridlines = true;
xAxis.HasMajorGridlines = true;
ticks.Orientation = XlTickLabelOrientation.xlTickLabelOrientationUpward;
chart.PlotArea.Select();
chart.PlotArea.Height = 300;

Custom date format in Excel for zero

I am new to excel and C#. I am fetching data from database and showing in excel. In a array when ever there is a null record I am replacing it with '0'. My issue is after I format the column to a date format '0' is replaced by default value '1/0/1900'. I need a custom format which will format only date records and but not zeros.
Note:In below Code Data= contains array of records. CreateDataArray will check for null records and will replace by 0.
object[,] updateValues = CreateDataArray(data, 1, direction);
IRange dataRange = _rangeHelper.GetRangeBeside(startCell, data.Length - 1, direction);
dataRange.Value2 = updateValues;
// Apply format
dataRange.NumberFormat = "m/d/yyyy";
dataRange.NumberFormatLocal = "m/d/yyyy";
Try this:
dataRange.NumberFormat = "m/d/yyyy;;#0";

Convert time-formatted column in excel to C# DateTime

I am currently using the Excel C# libraries (Microsoft.Office.Interop.Excel) to read an excel spreadsheet into my C# application.
I initially tried to read all the cells as their raw data, but found that Date-formatted cells were giving me a 5-digit integer, and time-formatted cells were returning a decimal. So I then found out that you can use a date-conversion method built into Excel's C# library, like so:
DateTime excelDate = (DateTime)ExcelCalcValue.ExcelDateToDateTime(workbook, Double.Parse(cell.Value.ToString()));
output = excelDate.ToString("yyyy-MM-dd HH:mm");
Through debugging my application with various test sheets, I have been able to record the various format strings that cells return when they are formatted in different ways. These are below:
(WorksheetCell.CellFormat.FormatString)
Times
[$-F400]h:mm:ss\\ AM/PM
hh:mm:ss;#
h:mm:ss;#
[$-409]hh:mm:ss\\ AM/PM;#
[$-409]h:mm:ss\\ AM/PM;#
Dates
m/d/yy
[$-F800]dddd\\,\\ mmmm\\ dd\\,\\ yyyy
dd/mm/yyyy;#
dd/mm/yy;#
d/m/yy;#
d\\.m\\.yy;#
yyyy\\-mm\\-dd;#
[$-809]dd\\ mmmm\\ yyyy;#
[$-809]d\\ mmmm\\ yyyy;#
Using these, I can now reliably determine the formatting style of a cell in excel. Using the earlier code, I can detect a date-formatted cell and return the proper data in DateTime format. However, I cannot see an equivalent function for converting time-formatted cells.
I get a result of 0.58368055555555554 when I read a cell time-formatted as [$-F400]h:mm:ss\\ AM/PM. I have absolutely no idea how to convert this into a DateTime, or indeed what this float represents.
Can anyone suggest a method of converting time-formatted excel cells (which are stored as a strange float) into the correct DateTime variable?
As FrankPI said, use DateTime.FromOADate(). You would use this function with the raw data from an Excel cell - there is no need to parse the format.
Excel encodes its dates and times in a double. The integral portion represents the days after January 1, 1900. The fraction part represents the time since midnight of the day referenced. For example:
1.5 is January 1, 1900 # Noon
and
41507.25 = August 21, 2013 # 6:00 am
Refer to the MSDN docs on this function for more information:
http://msdn.microsoft.com/en-us/library/system.datetime.fromoadate.aspx
The "strange float" can probably be converted too a DateTime via the DateTime.FromOADate() method. Actually, it is the number of days since January, 1, 1900 with the time as fractions, e. g. 0.04236 = 1/24 + 1/(24 * 60) for 1:01 am.
I wrote this function to handle a date input from Excel into C#. It handles a number of data type possibilities for a date cell:
/// <summary>
/// Returns DateTime?
/// Excel dates are double values, and sometimes, they're typical dd/mm/yyyy dates.
/// This function handles both possibilities, and the possibility of a blank date input.
/// ///
/// </summary>
/// <param name="inputDate"></param>
/// <returns></returns>
private static DateTime? ResolveExcelDateInput(string inputDate)
{
double incomingDate = 0;
DateTime incomingDateDate = new DateTime();
// If the incoming date is a double type, parse it into DateTime
if (Double.TryParse(inputDate, out incomingDate))
{
return DateTime.FromOADate(incomingDate);
}
// IF the incoming date value is a date type, parse it.
var parseDateResult = DateTime.TryParse(inputDate, out incomingDateDate);
if(parseDateResult)
{
// If the parse is successful return the date
return incomingDateDate;
}
else
{
// If the parse isn't successful; check if this a blank value and set to a default value.
if(string.IsNullOrWhiteSpace(inputDate))
{
return new DateTime(1901, 1, 1);
}
else
{
// Otherwise return null value so that is then handled by the validation logic.
// log a validation result because inputDate is likely an invalid string value that has nothing to do with dates.
return null;
}
}
}
If you want that either date value is in double format or in date format it converts it to date format then try to use following code. datestringvalue should be your input value.
DateTime dateNow = DateTime.Now;
DateTime formatedDate = DateTime.TryParse("datestringvalue", out dateNow) ? Convert.ToDateTime("datestringvalue") : DateTime.FromOADate(Convert.ToDouble("datestringvalue"));

Categories

Resources