Can't get DateTime.TryParseExact to work - c#

I have the following code:
string[] format = { "yyyy/MM/dd", "MM/dd/yyyy" };
DateTime valueDate;
value = value.Replace("-", "/");
if (DateTime.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out valueDate))
{
value = "TO_DATE(" + valueDate + ", 'yyyy-mm-dd')";
}
else
{
throw new Exception("Could not parse incoming date: " + valueDate);
}
So now I have a test case.
And value = '2013/01/21' after the replace statement replacing "-" with "/".
This should match the first format in the format string array.
But TryParseExact is not working and always goes to the else path.
Can anyone see any errors in this code?

It's not TryParseExact that's the problem, it's the value of your string. I say that because this little scriptcs script:
using System.Globalization;
string[] format = { "yyyy/MM/dd", "MM/dd/yyyy" };
DateTime valueDate;
var value = "2013/01/21";
if (DateTime.TryParseExact(value, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out valueDate))
{
Console.WriteLine("Success!");
}
else
{
Console.WriteLine("Failure!");
}
prints Success!. So, in other words, this statement:
And value = '2013/01/21' after the replace statement replacing "-" with "/".
literally cannot be correct.
As stated by James, it's very possible there is whitespace in the actual string value. There are a couple solutions: remove the whitespace or allow whitespace. To allow whitespace you could use DateTimeStyles.AllowWhiteSpaces rather than DateTimeStyles.None.

Don't know if it's your issue, but make sure you always escape out your forward-slashes when using date formats. A / character is not a literal slash, but rather your local system's date separator (which is usually the forward-slash, but not always).
When using a format string, you escape a forward-slash with a real backslash, like:
DateTime.ParseExact("2012/12/31", "yyyy\\/MM\\/dd", null);
// or
DateTime.ParseExact("2012/12/31", #"yyyy\/MM\/dd", null);

Related

Parsing horrible timestamp C#

I have a timestamp from a server of the form 20220505 17:36:29 - it has 2 whitespaces, and I do not trust the sender to always send the same number of whitespaces in future revisions - ideally would like to handle any number of whitespaces the same.
I tried this with DateTime.ParseExact but failed:
var horribleTimestamp = "20220505 17:36:29";
var timestamp = DateTime.ParseExact(horribleTimestamp, "yyyyMMdd hh:mm:ss", CultureInfo.InvariantCulture)
// throws `System.FormatException: String '20220505 17:36:29' was not recognized as a valid DateTime.`
To save my headaches with timezones later how can I achieve this with Nodatime as i think makes sense to switch to that already.
The time is local from my PC and I would like to convert this to a global timestamp (which I believe should be Instant?) for a given local timezone?
If you want to handle any amount of whitespace, there are two options:
Use a regular expression (or similar) to get it into a canonical format with a single space
Split on spaces and then parse the first and last parts separately. (Or split on spaces, recombine the first and last parts and parse...)
In Noda Time, the value you've got represents a LocalDateTime, so that's what you should parse it to. Here's a complete example using the regex approach:
using NodaTime;
using NodaTime.Text;
using System.Text.RegularExpressions;
// Lots of spaces just to check the canonicalization
string text = "20220505 17:36:29";
// Replace multiple spaces with a single space.
string canonicalized = Regex.Replace(text, " +", " ");
// Note: patterns are immutable; you should generally store them in
// static readonly fields. Note that "uuuu" represents an absolute year number,
// whereas "yyyy" would be "year of era".
LocalDateTimePattern pattern =
LocalDateTimePattern.CreateWithInvariantCulture("uuuuMMdd HH:mm:ss");
ParseResult<LocalDateTime> result = pattern.Parse(canonicalized);
// Note: if you're happy with an exception being thrown on a parsing failure,
// juse use result.Value unconditionally. The approach below shows what to do
// if you want to handle parse failures without throwing an exception (or with
// extra behavior).
if (result.Success)
{
LocalDateTime value = result.Value;
Console.WriteLine(value);
}
else
{
// You can also access an exception with more information
Console.WriteLine("Parsing failed");
}
You can pass multiple formats to ParseExact as an array
var horribleTimestamp = "20220505 17:36:29";
var formats = new[]{"yyyyMMdd HH:mm:ss","yyyyMMdd HH:mm:ss","yyyyMMdd HH:mm:ss"};
var timestamp = DateTime.ParseExact(horribleTimestamp, formats, CultureInfo.InvariantCulture, 0);
dotnetfiddle
You have an error in your format. use HH instead of hh. See updated code below
var horribleTimestamp = "20220505 17:36:29";
var timestamp = DateTime.ParseExact(horribleTimestamp, "yyyyMMdd HH:mm:ss", CultureInfo.InvariantCulture)
Here is y link that explains what you can use in a format -> https://www.c-sharpcorner.com/blogs/date-and-time-format-in-c-sharp-programming1
You can solve the problem with the whitespaces in this way:
var horribleTimestamp = "20220505 17:36:29";
var date = horribleTimestamp.Substring(0, 8);
var index = horribleTimestamp.LastIndexOf(' ') + 1;
var time = horribleTimestamp.Substring(index, horribleTimestamp.Length - index);
var timestamp = DateTime.ParseExact($"{date} {time}", "yyyyMMdd HH:mm:ss", CultureInfo.InvariantCulture);
I suppose that date has always 8 characters and that space is always present. In other case, check index == -1.

Cannot perform an operation with converted label text

I'm a bit stuck: I am trying to perform an if statement comparing a label.text that originally has a currency string created from .ToString("C");
and a decimal. I have tried converting the label to decimal since I'm going to be comparing it to a decimal but it keeps triggering an exception:
Input string was not in a correct format.
here is my current code:
if(Convert.ToDecimal(SomeLabel.Text) > 1000.00m) { //DO SOMETHING }
//SomeLabel.Text has a value of $1000.00
//SomeLabel.Text has a value of $1000.00
The dollar sign is the reason for the issue. Yoa are probably using a different currency symbol. You can force it with decimal.Parse/decimal.TryParse(which handles invalid input):
string input = "$1000.00";
decimal decimalValue;
if(decimal.TryParse(input, out decimalValue))
{
// using current CurrencySymbol, same as Convert.ToDecimal
Console.WriteLine("Converted successfully: " + decimalValue);
}
else
{
var usCulture = new CultureInfo("en-US");
if (decimal.TryParse(input, NumberStyles.Currency, usCulture, out decimalValue))
{
// using dollar sign as CurrencySymbol
Console.WriteLine("Converted successfully with CultureInfo(en-US): " + decimalValue);
}
else
{
Console.WriteLine("Could not be parsed to decimal");
}
}
Output:
Converted successfully with CultureInfo(en-US): 1000.00
It's worth noting that NumberFormatInfo.InvariantInfo.CurrencySymbol does not return the dollar sign(what i thought) but ยค.
Convert.ToDecimal uses decimal.Parse explicitly this method uses NumberStyles.Number by default.
This is a composite style which includes AllowDecimalPoint but not AllowCurrencySymbol style even if your CurrentCulture's CurrencySymbol is $ and NumberDecimalSeparator is ..
You can use decimal.parse(String, NumberStyles, IFormatProvider) overlaod that takes these as a parameters like;
string s = "$1000.00";
var d = decimal.Parse(s, NumberStyles.AllowCurrencySymbol | NumberStyles.AllowDecimalPoint,
CultureInfo.GetCultureInfo("en-US"));
d will be 1000 after parsing.
As per your example. your string value is $1000.00.
This contains a $ sign that's why the compiler is unable to cast string to decimal.
try removing the unusable character by replace. Or try the method below
Regex digitsOnly = new Regex(#"[0-9.]"); // this regex matches only digits and decimal
string decimalnumberstring = digitsOnly.Replace(SomeLabel.Text, "");// replace all non numbers (except decimal) with empty string
then try to convert the string value like below.
if(Convert.ToDecimal(decimalnumberstring) > 1000.00m) { //DO SOMETHING }
hope it helps....
Take the Dollar Sign off of your text first:
Source: $1000
double result = 0M;
String value = SomeLabel.Text.Substring(1);
if (Double.TryParse(value, out result)) {
//
}
return result;
Try this
if(decimal.Parse(SomeLabel.Text) > 1000.00m)
{
}

Parse exact format not valid

I need to parse a string and convert it to DateTime . I have the following snippet :
using (StreamReader reader = new StreamReader(fichier))
{
while ((item = reader.ReadLine()) != null)
{
string[] table = item.Split('\t');
string _date = table[2];
pointages.Add(DateTime.ParseExact(_date,"yyyy-MM-dd-hh:mm:ss", CultureInfo.InvariantCulture,DateTimeStyles.None));
}
}
Edit2
the content of the file:
917 2014-06-24-07:43:47 Finger
the string _date =2014-06-24-07:43:47. When i execute the program i got this exception:
String was not recognized as a valid DateTime.
Edit
When i added a line before like this :
while ((item = reader.ReadLine()) != null)
{
string[] table = item.Split('\t');
string _date = table[2];
_date ="2014-06-24-07:43:47";
pointages.Add(DateTime.ParseExact(_date,"yyyy-MM-dd-hh:mm:ss", CultureInfo.InvariantCulture,DateTimeStyles.None));
}
It Works!!!
What are the reasons of this error?
How can i fix it?
Your sample string works for me, so it must be a different string. Use the debugger. Maybe it is actually using 24h clock like 17:43:47, then you need HH instead of hh.
You: no, it is really the string i've posted.
That's impossible. Maybe it has leading or trailing spaces, use Trim first:
_date = _date.Trim();
Trim removes not only spaces but all kind of characters that belong to SpaceSeparator, LineSeparator or ParagraphSeparator caregories. So maybe it was a tab or whatever. Have a look at the remarks section of Char.IsWhiteSpace which is used by String.Trim.
Side-Note: if you don't know if the format is valid you could use DateTime.TryParseExact instead which doesn't raise an exception but returns false if a string could not be parsed to DateTime:
bool couldBeParsed = DateTime.TryParseExact(
_date.Trim(),
"yyyy-MM-dd-HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out dt);

How i can convert string values in formats "1.123" and "1,123" to double by single double.TryParse?

I have an incoming source of string values representing double values with "." and "," delimiter and my program would run on PCs with different settings of delimiter ("," or ",")
Which way can I convert it with single line without trying first convert ".", then if fail, try ","?
I tried some combinations like that:
string dot_val = "1.12";
string non_dot_val = "1,12";
double dot_double = 0, non_dot_double = 0;
bool dot_res = double.TryParse(dot_val, NumberStyles.Any, CultureInfo.CurrentCulture, out dot_double);
bool non_dot_res = double.TryParse(non_dot_val, NumberStyles.Number | NumberStyles.AllowCurrencySymbol, CultureInfo.CurrentCulture, out non_dot_double);
But one of the attempts to convert is always fail.
If tell it shortly, I need an universal function to convert "." or "," delimited double values into double
Well, the current culture tells you whether . or , is the decimal separator. If you want your function to parse both formats, you need to pass in a culture that has the respective separator. In your example:
public double UniveralParse(string value)
{
double result;
// If we can not parse the "." format...
if (!double.TryParse(value, NumberStyles.Any, CultureInfo.GetCultureInfo("en-US"), out result))
// And also can not parse the "," format...
if (!double.TryParse(value, NumberStyles.Any, CultureInfo.GetCultureInfo("de-DE"), out result))
// we throw an exception
throw new ArgumentException("value is not in expected format!");
// Otherwise we can return the value
return result;
}
The easiest way is to replace ',' by '.' and parse the result using the invariant culture setting:
double.TryParse(
dot_val.Replace(',','.'),
NumberStyles.Any,
CultureInfo.InvariantCulture,
out dot_double);
The only limitation of this is that you shouldn't have grouping in your number (like 123,000.45)

String compare in C#

I have a string like 20090101 and I want to compare it with ????01??.
if (input == "----01--") { .... }
How can I compare the 5th and 6th characters with "01"?
Update: After seeing your comment I think you should parse the string as a DateTime:
string s = "20090101";
DateTime dateTime;
if (DateTime.TryParseExact(s, "yyyyMMdd", null, DateTimeStyles.None, out dateTime))
{
if (dateTime.Month == 1)
{
// OK.
}
}
else
{
// Error: Not a valid date.
}
I think this may be what you want:
if (input.Substring(4, 2) == "01")
{
// do something
}
This will get a two character substring of input (starting at character 5) and compare it to "01".
you should create a regex expression. to check if the 4th and 5th byte is 01, you can write
var r = new Regex("^.{4}01$");
if(r.Match(str) ...) ...
MSDN has a great article on comparing strings, but you may want to refer to the String documentation for specific help, most notably: String.Compare, String.CompareTo, String.IndexOf, and String.Substring.
As Bauer said you can use String functions, also you can convert string to Char Array and work with it char by char

Categories

Resources