Getting error string was not recognized as a valid using c# - c#

when i am try to change date format from csv file 3/1/2021-3/31/2021 to Mar-01-2021-Mar-31-2021 getting error please help me solve the issue.
foreach (DataRow dr in dtDataTable.Rows)
{
for (int i = 0; i < dtDataTable.Columns.Count; i++)
{
if (ListInputDateColumns.Contains(dtDataTable.Columns[i].ColumnName))
{
if(dtDataTable.Columns[i].ColumnName == "Period")
{
sw.Write(dr[i] = Convert.ToDateTime(dtDataTable.Rows[i][dtDataTable.Columns[i].ColumnName.ToString()]).ToString("MMM-dd-yyyy-MMM-dd-yyyy"));//Here i am getting error
}
else
{
sw.Write(dr[i] = Convert.ToDateTime(dtDataTable.Rows[i][dtDataTable.Columns[i].ColumnName.ToString()]).ToString("MMM-dd-yyyy hh:mm:ss tt"));
}
//sw.Write(dr[i].ToString());
}
else
{
sw.Write(dr[i].ToString());
}
//sw.Write(dr[i].ToString());
sw.Write(",");
}
sw.Write(sw.NewLine);
}
sw.Close();
}
}

You have to parse that string by splitting it by the delimiter and then parse each token to DateTime. Then you can convert it back to string with the desired format:
string targetFormat = "MMM-dd-yyyy";
string s = " 3/1/2021-3/31/2021";
string[] tokens = s.Split('-');
if(tokens.Length == 2)
{
bool validFrom = DateTime.TryParse(tokens[0], CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime fromDate);
bool validTo = DateTime.TryParse(tokens[1], CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime toDate);
if (validFrom && validTo)
{
string result = $"{fromDate.ToString(targetFormat, CultureInfo.InvariantCulture)}-{toDate.ToString(targetFormat, CultureInfo.InvariantCulture)}";
}
}

OK, we can do this in one line of code if you want, but it gets pretty ugly as far as readability goes. For a one liner, simply change this line:
sw.Write(dr[i] = Convert.ToDateTime(dtDataTable.Rows[i][dtDataTable.Columns[i].ColumnName.ToString()]).ToString("MMM-dd-yyyy-MMM-dd-yyyy"));//Here i am getting error
to
sw.Write(dr[i] = Convert.ToDateTime((dtDataTable.Rows[i][dtDataTable.Columns[i].ColumnName.ToString()]).Substring(0, (dtDataTable.Rows[i][dtDataTable.Columns[i].ColumnName.ToString()]).IndexOf('-'))).ToString("MMM-dd-yyyy") + "-" + Convert.ToDateTime((dtDataTable.Rows[i][dtDataTable.Columns[i].ColumnName.ToString()]).Substring((dtDataTable.Rows[i][dtDataTable.Columns[i].ColumnName.ToString()]).IndexOf('-') + 1)).ToString("MMM-dd-yyyy");
but for maintainability, I would recommend creating a quick method for parsing "Period" like this
string ParsePeriod(string period)
{
DateTime from = Convert.ToDateTime(period.Substring(0, period.IndexOf('-')));
DateTime to = Convert.ToDateTime(period.Substring(period.IndexOf('-') + 1));
return from.ToString("MMM-dd-yyyy") + "-" + to.ToString("MMM-dd-yyyy");
}
then call it like this by changing this:
sw.Write(dr[i] = Convert.ToDateTime(dtDataTable.Rows[i][dtDataTable.Columns[i].ColumnName.ToString()]).ToString("MMM-dd-yyyy-MMM-dd-yyyy"));//Here i am getting error
to this:
sw.Write(dr[i] = ParsePeriod(Convert.ToString(dtDataTable.Rows[i][dtDataTable.Columns[i].ColumnName.ToString()])));
I trust this solves your problem. ;-)

Related

C# get offset for ISO8601 date from Windows settings

I have to maximise the use of ISO8601 dates in a C# project I'm using, especially when it comes to saving dates in the database.
In the same project I am creating Outlook appointments.
List<string> Recipients = new List<string>();
Recipients.Add("person#place.com");
string AppointmentSubject = "test subject";
string AppointmentBody = "test body";
string AppointmentLocation = "test location"; // Where do I get a list of meeting rooms?
string Offset = GetISO8601OffsetForThisMachine();
DateTime AppointmentStart = DateTime.Parse("2016-10-07T08:00:00" + Offset);
DateTime AppointmentEnd = DateTime.Parse("2016-10-07T10:00:00" + Offset);
Boolean IsAtDesk = true;
CreateOutlookAppointment(Recipients, AppointmentLocation, AppointmentSubject, AppointmentBody, AppointmentStart, AppointmentEnd, IsAtDesk);
Being in UK, our offset is either +1 or +0 due to daylight saving.
Is there a way to get the offset programatically based on the Windows locale settings?
You can probably do something like :
DateTime AppointmentStart = DateTime.Parse("2016-10-07T08:00:00").ToLocalTime();
Calculate the offset with the following:
public static string GetISO8601OffsetForThisMachine()
{
string MethodResult = null;
try
{
TimeSpan OffsetTimeSpan = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now);
string Offset = (OffsetTimeSpan < TimeSpan.Zero ? "-" : "+") + OffsetTimeSpan.ToString(#"hh\:mm");
MethodResult = Offset;
}
catch //(Exception ex)
{
//ex.HandleException();
}
return MethodResult;
}

How do i only get the date from string

I have a small question.
I have to get only the Ship date "July 17, 2015" from the string. lets say this is my code:
string result = "";
foreach (HtmlElement el in webBrowser1.Document.GetElementsByTagName("div"))
if (el.GetAttribute("className") == "not-annotated hover")
{
result = el.InnerText;
textBox2.Text = result;
}
Now this is the output:
string result = "";
string date = "";
foreach (HtmlElement el in webBrowser1.Document.GetElementsByTagName("div"))
if (el.GetAttribute("className") == "not-annotated hover")
{
result = el.InnerText;
date = Regex.Match(result ,
String.Format(#"{0}\s(?<words>[\w\s]+)\s{1}", "Ship Date:", "Country:"),
RegexOptions.IgnoreCase).Groups["words"].Value;
textBox2.Text = date ;
}
It seems as if your div is an outer div, you need the one which displays the ship-date only. That would be the safest/easiest approach.
However, if all you have is that large string, you could split by new-line characters and get the date from the line which starts with Ship date:
string[] lines = result.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
string dateString = lines
.FirstOrDefault(l => l.Trim().StartsWith("Ship date", StringComparison.InvariantCultureIgnoreCase));
DateTime shipDate;
if (dateString != null)
{
string[] formats = new[] { "MMMM dd, yyyy" };
string datePart = dateString.Split(':').Last().Trim();
bool validShipDate = DateTime.TryParseExact(
datePart,
formats,
DateTimeFormatInfo.InvariantInfo,
DateTimeStyles.None,
out shipDate);
if (validShipDate)
Console.WriteLine(shipDate);
}
From the Output text that you have shared,
string result = "";
foreach (HtmlElement el in webBrowser1.Document.GetElementsByTagName("div"))
if (el.GetAttribute("className") == "not-annotated hover")
{
result = el.InnerText;
if (result.IndexOf("Ship Date") == 0) //Ship Date text is present in the string
{
//since the string format is Ship Date: July 17, 2015 -
//we can assume : as a delimiter and split the text
string[] splitText = result.Split(':');
string date = splitText[1].Trim(); //this will give the date portion alone
}
textBox2.Text = result;
}
Hope this helps.
NOTE: This logic will work only if the Ship Date string in the HTML is received in the same format as specified in your Output sample

Excel date format using EPPlus

I'm having trouble with format my cells to Date.
FileInfo info = new FileInfo(path);
using (ExcelPackage package = new ExcelPackage(info))
{
ExcelWorksheet ws = package.Workbook.Worksheets.Add(sheetName);
ws.Cells[3, 1].Style.Numberformat.Format = "yyyy-mm-dd";
ws.Cells["A3"].Formula = "=DATE(2014,10,5)";
}
Output from this in Excel: 41 917,00
Why is this not working?
I agree with Yosoyke. You're probably targeting the wrong cells. You can try:
ws.Cells["A3"].Style.Numberformat.Format = "yyyy-mm-dd";
ws.Cells["A3"].Formula = "=DATE(2014,10,5)";
worksheet.Cells["YOURDATECELL_OR_YOURDATECELLRANGE"].Style.Numberformat.Format = "mm-dd-yy";
if you use the formula mentioned by taraz. do add worksheet.Calculate() in the end.
reference
https://epplus.codeplex.com/wikipage?title=About%20Formula%20calculation
Or instead of using formula, Alternative approach
private static decimal GetExcelDecimalValueForDate(DateTime date)
{
DateTime start = new DateTime(1900, 1, 1);
TimeSpan diff = date - start;
return diff.Days + 2;
}
Reference
worksheet.Cells["A2"].Value = GetExcelDecimalValueForDate(Convert.ToDateTime('2016-04-29'));
worksheet.Cells["A2"].Style.Numberformat.Format = "mm-dd-yy";//or m/d/yy h:mm
By Default when excel saves a date field it saves it as numFormatId 14(Look at the xml files in the xls). This ensure the date formats correctly in any country when the file is opened.
In Epplus mm-dd-yy translates to numFormatId 14 for excel.
This will ensure that when the file is opened in any country the date will be formatted correctly based on the country's short date settings.
Also noticed m/d/yy h:mm formats correctly for any country.
var dateColumns = from DataColumn d in dt.Columns
where d.DataType == typeof(DateTime) || d.ColumnName.Contains("Date")
select d.Ordinal + 1;
foreach (var dc in dateColumns)
{
worksheet.Cells[2, dc, rowCount + 2, dc].Style.Numberformat.Format = "mm/dd/yyyy hh:mm:ss AM/PM";
}
it will format all the columns with header Date to specific format given/ provided
I was having the same problem with my CSV to be transformed. I was able to do this in a little different manner.
private string ConvertToExcel(string CSVpath, string EXCELPath)
{
try
{
string Filename = System.IO.Path.GetFileNameWithoutExtension(CSVpath);
string DirectoryName = System.IO.Path.GetDirectoryName(CSVpath);
EXCELPath = DirectoryName + "\\" + Filename + ".xlsx";
string worksheetsName = "Report";
bool firstRowIsHeader = false;
var format = new OfficeOpenXml.ExcelTextFormat();
format.Delimiter = '|';
format.EOL = "\n";
using (OfficeOpenXml.ExcelPackage package = new OfficeOpenXml.ExcelPackage(new System.IO.FileInfo(EXCELPath)))
{
string dateformat = "m/d/yy h:mm";
//string dateformat = System.Globalization.DateTimeFormatInfo.CurrentInfo.ShortDatePattern;
OfficeOpenXml.ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(worksheetsName);
worksheet.Cells["A1"].LoadFromText(new System.IO.FileInfo(CSVpath), format, OfficeOpenXml.Table.TableStyles.Medium2, firstRowIsHeader);
worksheet.Column(3).Style.Numberformat.Format = dateformat;
worksheet.Column(5).Style.Numberformat.Format = dateformat;
worksheet.Column(6).Style.Numberformat.Format = dateformat;
worksheet.Column(20).Style.Numberformat.Format = dateformat;
worksheet.Column(21).Style.Numberformat.Format = dateformat;
worksheet.Column(22).Style.Numberformat.Format = dateformat;
package.Save();
}
}
catch (Exception ex)
{
//DAL.Operations.Logger.LogError(ex);
Console.WriteLine(ex);
Console.Read();
}
return EXCELPath;
}
Generic solution which takes IEnumerable (data) it loops through the properties of the generic object finds which is of DateType or nullableDate Type and applies formatting:
//set the list of dateColumns which will be used to formate them
List<int> dateColumns = new List<int>();
//get the first indexer
int datecolumn = 1;
//loop through the object and get the list of datecolumns
foreach (var PropertyInfo in data.FirstOrDefault().GetType().GetProperties())
{
//check if property is of DateTime type or nullable DateTime type
if (PropertyInfo.PropertyType == typeof(DateTime) || PropertyInfo.PropertyType == typeof(DateTime?))
{
dateColumns.Add(datecolumn);
}
datecolumn++;
}
// Create the file using the FileInfo object
var file = new FileInfo(outputDir + fileName);
//create new excel package and save it
using (var package = new ExcelPackage())
{
//create new worksheet
var worksheet = package.Workbook.Worksheets.Add("Results");
// add headers
worksheet.Cells["A1"].LoadFromCollection(data, true);
//format date field
dateColumns.ForEach(item => worksheet.Column(item).Style.Numberformat.Format = "dd-mm-yyyy");
// auto size columns
worksheet.Cells.AutoFitColumns();
//save package
package.SaveAs(file);
}
You can try, If you want using AM/PM
worksheet.Cells[1].Style.Numberformat.Format = "dd/MM/yyyy HH:mm:ss AM/PM";
Following on from the very good Generic solution which takes IEnumerable.. answer we had to go a step further and display different date formatting for different properties. Fro example some columns needed to be displayed as dd/MM/yyyy and others as dd/MM/yyyy hh:mm.
So we added a DisplayFormat annotation with a DataFormatString (representing a DateTime format) to our properties like this:
using System.ComponentModel.DataAnnotations;
...
[DisplayName("Download Date")]
[DisplayFormat(DataFormatString = "dd/MM/yyyy hh:mm")]
public string DownloadDate { get; set; }
...
And then borrowing from Generic solution which takes IEnumerable.. we pulled out the date format string from the DisplayFormat annotation when iterating the properties of the data object:
public void FormatDateColumns(ExcelWorksheet worksheet, IEnumerable<IResult> data)
{
// Dictionary 'key' contains the Index of the column that contains DateTime data
// Dictionary 'value' contains the DateTime format for that column
Dictionary<int, string> dateColumns = new Dictionary<int, string>();
int dateColumnIndex = 1;
// find all the DateTime/DateTime? columns in the data object
foreach (var PropertyInfo in data.FirstOrDefault().GetType().GetProperties())
{
if (PropertyInfo.PropertyType == typeof(DateTime) || PropertyInfo.PropertyType == typeof(DateTime?))
{
string dateTimeFormat = Constants.DefaultDateTimeFormat;
// attempt to get a DataFormatString from a DisplayFormat annotation which may be decorating the Property
// looking for an annotation something like [DisplayFormat(DataFormatString = "dd-MM-yyyy hh:mm")]
if (PropertyInfo.CustomAttributes != null)
{
var dislayFormatAttribute = PropertyInfo.CustomAttributes.Where(x => x.AttributeType.Name == "DisplayFormatAttribute").FirstOrDefault();
if (dislayFormatAttribute != null && dislayFormatAttribute.NamedArguments != null && dislayFormatAttribute.NamedArguments.Count > 0)
{
var displayFormatArg = dislayFormatAttribute.NamedArguments.First();
if (displayFormatArg != null && displayFormatArg.TypedValue != null && displayFormatArg.TypedValue.Value != null)
{
// NOTE: there is probably an easier way to get at this value?
dateTimeFormat = displayFormatArg.TypedValue.Value.ToString();
}
}
}
dateColumns.Add(dateColumnIndex, dateTimeFormat);
}
dateColumnIndex++;
}
if (dateColumns.Count > 0)
{
// apply the formatting
dateColumns.ToList().ForEach(item => worksheet.Column(item.Key).Style.Numberformat.Format = item.Value);
}
}
I wanted to add that the setting of the format was the solution for me. But, I could not get it to work until I set the value property to a DateTime object and not a string. That was the key to making it all work.
I had a similar issue, and even though I was correctly setting the date and applying the proper number format to the cell containing the date, I was seeing the numeric representation of the date.
Turns out that after that, I applied a style, that effectively reset my format.
The code was something like:
ws.Cells["A3"].Style.Numberformat.Format =
System.Globalization.DateTimeFormatInfo.CurrentInfo.ShortDatePattern;
ws.Cells["A3"].Value = New DateTime(2021, 10, 15, 23, 16, 0).ToOADate();
and later, I had:
ws.Cells("A3").StyleName = colStyle //colstyle is a style created earlier
To fix that, I needed to apply the NumberFormat.Format after setting the style.
Make sure your cell width is large enough to display your date! This is the problem if the cell displays ### symbols.
A simple fix for this is to autofit the cell width in your worksheet:
ws.Cells.AutoFitColumns();
Complete example with passing a DateTime object:
ws.Cells[3, 1].Style.Numberformat.Format = "yyyy-mm-dd";
ws.Cells[3, 1].Value = new DateTime(2014,10,5);
ws.Cells.AutoFitColumns();
For advanced formatting, look at https://support.microsoft.com/en-us/office/number-format-codes-5026bbd6-04bc-48cd-bf33-80f18b4eae68.
Keep in mind NOT to localize reserved characters of the numberformat code into another language: Write yyyy for the year, not jjjj. If you want to format a number and want the decimal separator, write 0.00, not 0,00.
(Posted this as I keep stumbling over this problem and this question is the first search result.)
Some news:
ws.Cells["A3"].Style.Numberformat.Format = "[$-en-US]yyyy-mmm-dd";
ws.Cells["A3"].Formula = "=DATE(2014,10,5)";

C# String to date with CultureInfo

I have a date in the following format. It is always in this format.
yyyyMMdd -> 20130912
I need to convert it to a date. But I need to be sure that the date is converted to the correct date format of the PC. Cultureinfo.InvariantCulture. Here is what my code looks like now.
DateTime parsedDateTime;
int year = Int32.Parse(rows[row][4].ToString().Substring(0, 4));
int month = Int32.Parse(rows[row][4].ToString().Substring(4, 2));
int day = Int32.Parse(rows[row][4].ToString().Substring(6, 2));
DateTime value = new System.DateTime(year, month, day);
bool DateTimeParseFail = DateTime.TryParse(value.ToString("yyyy-MM-dd"), CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDateTime);
if (!DateTimeParseFail) {
msg = "Data Feed Convert string to DateTime: Date " + rows[row][4].ToString() + " - " + value.ToString();
ComponentMetaData.FireError(0, ComponentMetaData.Name, msg, string.Empty, 0, out pbCancel);
throw new Exception(msg);
} else {
buffer[colIndex] = parsedDateTime;
}
This just looks like overkill to me and I suspect that I'm over-thinking it. There has to be an easier way of doing this. But everything I have tried hasn't worked like I expected it.
Try this:
string dateText = rows[row][4].ToString();
DateTime date = DateTime.ParseExact(dateText, "yyyyMMdd", CultureInfo.InvariantCulture);
string result = date.ToShortDateString(CultureInfo.InvariantCulture.DateTimeFormat.ShortDatePattern);
Note that I'm assuming your assertion that the date is always in this format is correct. If it's not, you'll find that the code throws an exception.
(The code you've posted suggests that your assertion is not true, because you've got a fallback format and some failure handling there...)
Use the TryParseExact of DateTime....
var dateString = "20130912"; //rows[row][4].ToString()
DateTime parsedDateTime;
var DateTimeParseFail= DateTime.TryParseExact(dateString, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out parsedDateTime);
if (!DateTimeParseFail) {
msg = "Data Feed Convert string to DateTime: Date " + rows[row][4].ToString() + " - " + value.ToString();
ComponentMetaData.FireError(0, ComponentMetaData.Name, msg, string.Empty, 0, out pbCancel);
throw new Exception(msg);
} else {
buffer[colIndex] = parsedDateTime;
}

Checking if string is TimeSpan

I am importing data from an Excel file and i need to check if the data i am importing is a TimeSpan or a regular string. Because the data can be either 07:00:00 or D2 07:00. In the excel file some of the fields are formatted to be tt:mm but others are plain text fields.
My code look like this:
public void ReadExcelFile()
{
string filename = #"C:\Temp\Copy2.xlsx";
using (OleDbConnection connection = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + filename + ";Extended Properties=\"Excel 12.0;HDR=YES;IMEX=1\""))
{
try
{
connection.Open();
string sqlCmd1 = "SELECT * FROM [Sheet1$]";
using (OleDbCommand command = new OleDbCommand(sqlCmd1, connection))
{
command.CommandType = System.Data.CommandType.Text;
using (OleDbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
alias = "" + reader[3];
codeT = "" + reader[4];
dtTruck = "" + reader[5];
codeP = "" + reader[6];
dtPlane = "" + reader[7];
dtDealer = "" + reader[8];
TimeSpan ts;
bool TruckisValid = TimeSpan.TryParse(dtTruck, CultureInfo.InvariantCulture, out ts);
bool PlaneisValid = TimeSpan.TryParse(dtPlane, out ts);
if (TruckisValid )
{
truck = TimeSpan.FromDays(Convert.ToDouble(dtTruck));
}
else if (PlaneisValid)
{
plane = TimeSpan.FromDays(Convert.ToDouble(dtPlane));
}
else
{
}
if (dtTruck == "" && dtPlane == "")
{
dtTruck = "";
dtPlane = "";
}
else if (dtTruck != "")
{
truck = TimeSpan.FromDays(Convert.ToDouble(dtTruck));
dtPlane = "";
}
else if (dtPlane != "")
{
plane = TimeSpan.FromDays(Convert.ToDouble(dtPlane));
dtTruck = "";
}
SearchForAdrIDAndCustID(Convert.ToString(reader[0]), Convert.ToString(reader[3]));
InsertData(custID, "" + reader[3], adrID, truck, codeT, plane, codeP, dtDealer);
}
}
}
}
catch (Exception exception)
{
Console.WriteLine("ERROR in ReadExcelFile() method. Error Message : " + exception.Message);
}
}
}
As you can see i have tried to use a bool to determine if the imported field is a timespan or not. But the bool is always false.
can anyone help ?
Here's the relevant part of your question:
TimeSpan ts;
bool TruckisValid = TimeSpan.TryParse(dtTruck, CultureInfo.InvariantCulture, out ts);
bool PlaneisValid = TimeSpan.TryParse(dtPlane, out ts);
if (TruckisValid )
{
truck = TimeSpan.FromDays(Convert.ToDouble(dtTruck));
}
else if (PlaneisValid)
{
plane = TimeSpan.FromDays(Convert.ToDouble(dtPlane));
}
else
{
}
You're reusing the same TimeSpan variable ts for two different fields. I assume that you use it just to test if it can be parsed. Instead you should use the parsed TimeSpan.
You're testing for TimeSpan but you're converting it to double. It is either convertable to TimeSpan or to double not both.
So maybe this approach is better:
double d;
TimeSpan ts;
bool TruckisValidDouble = false;
bool TruckisValidTimeSpan = TimeSpan.TryParse(dtTruck, CultureInfo.InvariantCulture, out ts);
if(!TruckisValidTimeSpan)
{
TruckisValidDouble = double.TryParse(dtTruck, out d);
}
// use approapriate variables
From comments:
the reason for converting it to double is because when i import the
data from my excel file it has the percentage value of 07:00:00 witch
is 0,29166666667. So im converting the double value to a timespan.
But you cannot check for TimeSpan and parse to double or vice-versa. If you know that it's a TimeSpan via TryParse use the TimeSpan variable directly. Otherwise double.TryParse and use that variable afterwards.
For example:
if(!TruckisValidTimeSpan && TruckisValidDouble)
{
ts = TimeSpan.FromHours(d * 24);
}
You could use a regex to check if your value is a TimeSpan like so:
Regex reg = new Regex("^\d{2}:\d{2}:\d{2}$");
bool TruckIsValid = reg.IsMatch(dtTruck);

Categories