In this code item.date_time looks like "2017-10-18T04:57:39.000Z". When I put this (or any other similar string) instead of item.date_time - it works well. But despite the fact that item.date_time is equal to strings like this - it calls System.FormatException when I use it.
static void Main(string[] args)
{
eventList = new List<CsvFile>();
StreamReader sr = new StreamReader("logs.csv");
string data = sr.ReadLine();
while (data != null)
{
string[] line = data.Split(',');
ReadString(line);
data = sr.ReadLine();
}
}
class CsvFile
{
public String date_time;
public DateTime datetime;
}
static void ReadString(String[] str)
{
CsvFile item = new CsvFile();
item.date_time = str[0];
item.datetime = DateTime.ParseExact(item.date_time, "yyyy-MM-ddTHH:mm:ss.000Z", CultureInfo.InvariantCulture);
eventList.Add(item);
}
I went through dozens of questions and answers about datetime issues today, but found nothing can solve this strange thing. Any ideas what is the problem with my code?
str[0] is equal "\"2017-10-18T04:57:39.000Z\""
Your string has quotes around it (hence the \" indicators). Trim those before parsing:
item.date_time = str[0].Trim('"');
item.datetime = DateTime.ParseExact(item.date_time, "yyyy-MM-ddTHH:mm:ss.000Z", CultureInfo.InvariantCulture);
You might consider using TryParseExact so you can determine if the parse was successful and show a better error message (like which record you're on, what the input value is, etc.) rather than throwing an exception.
Another alternative is to use a CSV parsing library that can handle both the quotes around values and the date/time parsing for you.
Related
First I should mention that I know there are several questions similar to mine, but none of them could help me.
I want to compare two dates which are in two different SQL table and I'm using Lambda Expression.
My code:
var itemStartDate = new ItemsBusiness().GetList<Item>(i => Convert.ToInt64(i.StartDate.Replace("/", "")) < Convert.ToInt64(tdpStartDate.Text.Replace("/", "")));
However when I run the program, this exception shows up:
Input string was not in a correct format. When converting a string to DateTime, parse the string to take the date before putting each variable into the DateTime object.
The line which catches the exception is in another form:
try
{
int inputVal = Convert.ToInt32(value.Trim().Replace("px", ""));
myLabelWidth = inputVal.ToString();
}
p.s: My dates format is like this: "2010/06/20"
This is what I think is happening. I assume that you turn your date into a string like this:
var StartDate = DateTime.Now.Date.ToString();
var tdpStartDate = DateTime.Now.Date.ToString();
var result = Convert.ToInt64(StartDate.Replace("/", "")) < Convert.ToInt64(tdpStartDate.Replace("/", ""));
This will fail with the error you got because the Date is in a format with letters when representing the month.
What you can do is simply to format the Date to include nothing but digits:
var StartDate = DateTime.Now.Date.ToString("ddMMyyyy");
var tdpStartDate = DateTime.Now.Date.ToString("ddMMyyyy");
var result = Convert.ToInt64(StartDate) < Convert.ToInt64(tdpStartDate);
This does not throw the exception like before
I am trying to format Datetime string using
date.ToString(format)
If user feeds in wrong format, e.g. "YYYY MM DDr" I would like to know whether I can convert datetime using that format, rather than returning
2015 04 DDr
since
DateTime.ToString(format)
always returns a valid String.
For example, is there any method that perhaps throw an exception on failed conversion so that I can catch and decide not display my output string instead of displaying something like
2015 04 DDr
If you assume that all the letters inserted in your format are either separators or letters that should be converted to a DatePart, you can check if after converting the date you still have non separator chars that were not converted, as follows:
public static class DateTimeExtension
{
public static string ToStringExt(this DateTime p_Date, String format)
{
char[] separators = { ' ', '/', '-' };
String stringDate = p_Date.ToString(format);
foreach (char dateChar in format)
{
if (stringDate.Contains(dateChar) && !separators.Contains(dateChar))
{
throw new FormatException("Format Error");
}
}
return stringDate;
}
}
Edited after #Vladimir Mezentsev observation:
This code assumes that you are converting only to Numbers, if you are doing something that will convert to Day strings like Tuesday, the logic may fail. To address this scenario the code would get a little more complicated but can also be achieved with something like this:
public static string ToStringExt(this DateTime p_Date, String format)
{
foreach (string dateFormatPart in getFormatStrings(format))
{
if (p_Date.ToString(dateFormatPart) == dateFormatPart)
{
throw new FormatException("Format Error");
}
}
return p_Date.ToString(format);
}
private static IEnumerable<string> getFormatStrings(String format)
{
char[] separators = { ' ', '/', '-' };
StringBuilder builder = new StringBuilder();
char previous = format[0];
foreach (char c in format)
{
if (separators.Contains(c) || c != previous)
{
string formatPart = builder.ToString();
if (!String.IsNullOrEmpty(formatPart))
{
yield return formatPart;
builder.Clear();
}
}
if(!separators.Contains(c))
{
builder.Append(c);
}
previous = c;
}
if (builder.Length > 0)
yield return builder.ToString();
}
Have a look at https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx. Particularly this part...
If you're wanting to validate the string used to format the DateTime object, then you'll probably have to write your own using the link provided to know what formats are acceptable, and treat any other characters as errors.
There is no invalid format, because you can parse formatted string with exact same format. Even if after parsing you have not loss in any part of date, that could not form the final decision - valid or invalid format.
You should carefully consider what can be appropriate for user, even give him an opportunity to construct format from some predefined blocks. Maybe show sample conversion with confirmation.
For specific formats you can create some extension method where you can apply your business rules and throw exceptions when you need it.
I am working on a simple windows forms application that the user enters a string with delimiters and I parse the string and only get the variables out of the string.
So for example if the user enters:
2X + 5Y + z^3
I extract the values 2,5 and 3 from the "equation" and simply add them together.
This is how I get the integer values from a string.
int thirdValue
string temp;
temp = Regex.Match(variables[3], #"\d+").Value
thirdValue = int.Parse(temp);
variables is just an array of strings I use to store strings after parsing.
However, I get the following error when I run the application:
Input string was not in a correct format
Why i everyone moaning about this question and marking it down? it's incredibly easy to explain what is happening and the questioner was right to say it as he did. There is nothing wrong whatsoever.
Regex.Match(variables[3], #"\d+").Value
throws a Input string was not in a correct format.. FormatException if the string (here it's variables[3]) doesn't contain any numbers. It also does it if it can't access variables[3] within the memory stack of an Array when running as a service. I SUSPECT THIS IS A BUG The error is that the .Value is empty and the .Match failed.
Now quite honestly this is a feature masquerading as a bug if you ask me, but it's meant to be a design feature. The right way (IMHO) to have done this method would be to return a blank string. But they don't they throw a FormatException. Go figure. It is for this reason you were advised by astef to not even bother with Regex because it throws exceptions and is confusing. But he got marked down too!
The way round it is to use this simple additional method they also made
if (Regex.IsMatch(variables[3], #"\d+")){
temp = Regex.Match(variables[3], #"\d+").Value
}
If this still doesn't work for you you cannot use Regex for this. I have seen in a c# service that this doesn't work and throws incorrect errors. So I had to stop using Regex
I prefer simple and lightweight solutions without Regex:
static class Program
{
static void Main()
{
Console.WriteLine("2X + 65Y + z^3".GetNumbersFromString().Sum());
Console.ReadLine();
}
static IEnumerable<int> GetNumbersFromString(this string input)
{
StringBuilder number = new StringBuilder();
foreach (char ch in input)
{
if (char.IsDigit(ch))
number.Append(ch);
else if (number.Length > 0)
{
yield return int.Parse(number.ToString());
number.Clear();
}
}
yield return int.Parse(number.ToString());
}
}
you can change the string to char array and check if its a digit and count them up.
string temp = textBox1.Text;
char[] arra = temp.ToCharArray();
int total = 0;
foreach (char t in arra)
{
if (char.IsDigit(t))
{
total += int.Parse(t + "");
}
}
textBox1.Text = total.ToString();
This should solve your problem:
string temp;
temp = Regex.Matches(textBox1.Text, #"\d+", RegexOptions.IgnoreCase)[2].Value;
int thirdValue = int.Parse(temp);
Im still learning in C#, and there is one thing i cant really seem to find the answer to.
If i have a string that looks like this "abcdefg012345", and i want to make it look like "ab-cde-fg-012345"
i tought of something like this:
string S1 = "abcdefg012345";
string S2 = S1.Insert(2, "-");
string S3 = S2.Insert(6, "-");
string S4 = S3.Insert.....
...
..
Now i was looking if it would be possible to get this al into 1 line somehow, without having to make all those strings.
I assume this would be possible somehow ?
Whether or not you can make this a one-liner (you can), it will always cause multiple strings to be created, due to the immutability of the String in .NET
If you want to do this somewhat efficiently, without creating multiple strings, you could use a StringBuilder. An extension method could also be useful to make it easier to use.
public static class StringExtensions
{
public static string MultiInsert(this string str, string insertChar, params int[] positions)
{
StringBuilder sb = new StringBuilder(str.Length + (positions.Length*insertChar.Length));
var posLookup = new HashSet<int>(positions);
for(int i=0;i<str.Length;i++)
{
sb.Append(str[i]);
if(posLookup.Contains(i))
sb.Append(insertChar);
}
return sb.ToString();
}
}
Note that this example initialises StringBuilder to the correct length up-front, therefore avoiding the need to grow the StringBuilder.
Usage: "abcdefg012345".MultiInsert("-",2,5); // yields "abc-def-g012345"
Live example: http://rextester.com/EZPQ89741
string S1 = "abcdefg012345".Insert(2, "-").Insert(6, "-")..... ;
If the positions for the inserted strings are constant you could consider using string.Format() method. For example:
string strTarget = String.Format("abc{0}def{0}g012345","-");
string s = "abcdefg012345";
foreach (var index in [2, 6, ...]
{
s = s.Insert(index, "-");
}
I like this
StringBuilder sb = new StringBuilder("abcdefg012345");
sb.Insert(6, '-').Insert(2, '-').ToString();
String s1 = "abcdefg012345";
String seperator = "-";
s1 = s1.Insert(2, seperator).Insert(6, seperator).Insert(9, seperator);
Chaining them like that keeps your line count down. This works because the Insert method returns the string value of s1 with the parameters supplied, then the Insert function is being called on that returned string and so on.
Also it's worth noting that String is a special immutable class so each time you set a value to it, it is being recreated. Also worth noting that String is a special type that allows you to set it to a new instance with calling the constructor on it, the first line above will be under the hood calling the constructor with the text in the speech marks.
Just for the sake of completion and to show the use of the lesser known Aggregate function, here's another one-liner:
string result = new[] { 2, 5, 8, 15 }.Aggregate("abcdefg012345", (s, i) => s.Insert(i, "-"));
result is ab-cd-ef-g01234-5. I wouldn't recommend this variant, though. It's way too hard to grasp on first sight.
Edit: this solution is not valid, anyway, as the "-" will be inserted at the index of the already modified string, not at the positions wrt to the original string. But then again, most of the answers here suffer from the same problem.
You should use a StringBuilder in this case as Strings objects are immutable and your code would essentially create a completely new string for each one of those operations.
http://msdn.microsoft.com/en-us/library/2839d5h5(v=vs.71).aspx
Some more information available here:
http://www.dotnetperls.com/stringbuilder
Example:
namespace ConsoleApplication10
{
class Program
{
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder("abcdefg012345");
sb.Insert(2, '-');
sb.Insert(6, '-');
Console.WriteLine(sb);
Console.Read();
}
}
}
If you really want it on a single line you could simply do something like this:
StringBuilder sb = new StringBuilder("abcdefg012345").Insert(2, '-').Insert(6, '-');
I'm trying to load some XY-coordinates from a asc-file. It looks like this:
-55.988544 9382
-53.395804 9403
-50.804601 9433
Then I am converting the coordinates to floats. But somehow f.e. for the first value I get "-55988544.0" instead of "-55.988544".
Here is the code:
private void btngettext_Click(object sender, EventArgs e)
{
StreamReader objStream = new StreamReader("C:\\...\\.asc");
firstLine = objStream.ReadLine();
int i = 0;
/*Split String on Tab,
* will separate words*/
string[] words = firstLine.Split('\t');
richTextBox1.Text = words[0];
foreach(string word in words)
{
if(word != "")
{
Console.WriteLine(word); //the value of the string is "-55.988544" here
//value = float.Parse(word); tried both
value = Convert.ToSingle(word); //here the float value is "-55988544.0"
Console.WriteLine(value.ToString());// "-5,598854E+07"
xyArray[0,i] = value;
i++;
}
}
}
Besides, if I would use objStream.ReadToEnd() or .Read(), how could iterate through lines. Read the values in the first line, save them and proceed to the next line.
Thanks in advance,
BC++
It sounds like your application is running under a culture where "." is a thousands separator rather than a decimal separator. If the source file always uses a ".", then it is better to parse with:
float.Parse(word, System.Globalization.CultureInfo.InvariantCulture);
That will ensure that the parse uses a "." no matter what the machine culture is.
It probably is an issue with the culture settings. Try the following:
var culture = System.Globalization.CultureInfo.InvariantCulture;
value = float.Parse(word, culture);
If your data uses a known, fixed notation for decimal separator etc you should not rely on the defaults of the reading PC. Use
value = float.Parse(word, CultureInfo.InvariantCulture);