Comparison between dates in C# application - c#

I have an asp.net application in which i have these three dates:
now = 08-10-13 15:56:19
cloture1 = 01-10-13 00:00:00
cloture2= 01-01-50 00:00:00
The format of dates is DD-MM-YY HH:MM:SS. the problem is that the function DateTime.Compare() gives me the same result ie
DateTime.Compare(now,cloture1) > 0 and DateTime.Compare(now,cloture2) > 0.
So what is the reasons of this problem? How can i fix my snippet?

The problem is your program most probably interpreting cloture2 as 1950, not 2050.
Because you have not posted the code in which you set cloture2, I cannot offer a concrete solution, but the best I can offer is that you use 01-10-2050 explicitly in your code.

From The "yy" Custom Format Specifier
In a parsing operation, a two-digit year that is parsed using the "yy"
custom format specifier is interpreted based on the
Calendar.TwoDigitYearMax property of the format provider's current
calendar.
In a parsing operation, a two-digit year that is parsed using the "yy"
custom format specifier is interpreted based on the
Calendar.TwoDigitYearMax property of the format provider's current
calendar. The following example parses the string representation of a
date that has a two-digit year by using the default Gregorian calendar
of the en-US culture.
From GregorianCalendar.TwoDigitYearMax
This property allows a 2-digit year to be properly translated to a
4-digit year. For example, if this property is set to 2029, the
100-year range is from 1930 to 2029. Therefore, a 2-digit value of 30
is interpreted as 1930, while a 2-digit value of 29 is interpreted as
2029.
Your application should set this value to 99 to indicate that 2-digit
years are to be taken literally. For example, if this property is set
to 99, the 100-year range is from 0 (not a valid value for most
calendars) to 99. Therefore, a 2-digit value of 30 is interpreted as
30.
Even when you decompile GregorianCalendar.TwoDigitYearMax property, you can see yourself;
public override int TwoDigitYearMax
{
get
{
if (this.twoDigitYearMax == -1)
this.twoDigitYearMax = Calendar.GetSystemTwoDigitYearSetting(this.ID, 2029);
return this.twoDigitYearMax;
}
Boluc's answer is completely right. I want to point also your format part.
You can't format two digit year with YYYY format. You need to use yy format which allows two digit formatting.
DateTime dt = DateTime.ParseExact("01-01-50 00:00:00", "dd-MM-yy HH:mm:ss", CultureInfo.InvariantCulture);
Prints
01.01.1950 00:00:00
Here a DEMO.
Check out for more informations from Custom Date and Time Format Strings

If now is later than cloture1 then the returned value will be 1 (or Greater than Zero).
The code you have supplied along with the example dates seems to work fine in reference to the MSDN article for DateTime.Compare method.
Please check the following link for more information on the DateTime.Compare method:
http://msdn.microsoft.com/en-us/library/system.datetime.compare.aspx
If you believe that your code is still incorrect please elaborate on your question.

Related

Strange behaviour of the "M" custom format specifier in c#

This Code produces the output in the comments bellow each Console.WriteLine statement.
Can anyone explain this kind of behaviour?
DateTime date1 = new DateTime(2008, 8, 18);
Console.WriteLine(date1.ToString("M"));
// Displays August 18
Console.WriteLine(date1.ToString("M "));
// Displays 8
Console.WriteLine(date1.ToString("(M)"));
// Displays (8)
Console.WriteLine(date1.ToString("(M) MMM, MMMM"));
// Displays (8) Aug, August
Can anyone explain this kind of behaviour?
Yes, it's completely documented in standard date and time format strings and custom date and time format strings.
Let's go through them one at a time:
date1.ToString("M"): That uses a single character 'M', so it's the standard format string for "month/day pattern"
date1.ToString("M "): That uses a format string with two characters, so it's a custom format string using M which is the month number, 1-12 with no padding.
date1.ToString("(M)"): Again, a custom format string using M
date1.ToString("(M) MMM, MMMM"): A custom format string using M, as well as MMM ("abbreviated name of the month") and MMMM (" full name of the month")
The important difference between the first two is that a format string is only considered to be a standard format if it's a single character. Otherwise, it's considered to be a custom format. If you want to use a single-character custom format specifier on its own, you can use % as a leading character - so date1.ToString("%M") would return "8" rather than "August 18".
Date and Time in C# are handled by DateTime struct in C# that provides properties and methods to format dates in different datetime formats.
M-> Month number(eg.3)
MM-> Month number with leading zero(eg.04)
MMM-> Abbreviated Month Name (e.g. Dec)
MMMM-> Full month name (e.g. December)
https://www.c-sharpcorner.com/blogs/date-and-time-format-in-c-sharp-programming1

What is the longest string that would convert to a valid DateTime?

I am writing a data parser and trying to work out if a field is a number, a date, a string etc.
The .NET DateTime.TryParse is understandably slow when checking many records (as it checks many different date formats). Therefore, I want to shortcut the processing if possible. A simple check I can do initially is look at the length of the string and reject it if it falls outside of some bounds.
The shortest date I think I should reasonably expect is 6 characters long (e.g. d/M/yy) so I can make the following check:
if (fieldValue.Length < 6)
{
// no datetime is shorter than 6 chars (e.g. d/M/yy is the shotest I can think of)
return false;
}
What is the longest string that still represents a parse-able DateTime?
(For example, "Wednesday, 30th September 2020 12:34:56" is pretty long but I bet there are longer examples!)
A few points:
I am not looking for tricksy answers where the date is padded out with white space or something like that.
I am focused on English dates initially but would be interested if other cultures can throw up longer examples.
What is the longest string that still represents a parse-able
DateTime?
Take a look at the list of custom format specifiers for a DateTime, and take all of those into account.
For instance, this:
DateTime dt = DateTime.Now;
string strNow = dt.ToString("dddd, MMMM dd, yyyy gg hh:mm:ss.fffffff tt K");
Console.WriteLine(strNow);
Gives:
Tuesday, June 16, 2020 A.D. 08:47:02.2667911 AM -06:00
But those different types of values can be output differently based on the information in the DateTime. Look CLOSELY at all the different possible outputs for each specifier in the documentation to see what I mean.

How does DateTime.TryParse know the date format?

Here is a scenario.
You have a string that represents a date i.e. "Jan 25 2016 10:10 AM".
You want to know whether it represents a date in a specific culture.
You want to know what dateTime pattern satisfies this date string.
Example:
Date string is "Jan 25 2016 10:10 AM"
Culture is en-US
The POSSIBLE format for it could be "MMM dd yyyy HH:mm tt"
Implementation:
To get the list of all dateTime patterns you can get a CultureInfo.DateTimeFormat.GetAllDateTimePatterns()
Then try the overloaded version of DateTime.TryParseExact(dateString, pattern, culture, DateTimeStyles.None, out resultingDate) for each of the patterns above and see whether it can parse a date.
That should give you the needed dateTime pattern.
HOWEVER if we iterate all those patterns it will not find any matches!
This is even more weird if you try and use a DateTime.TryParse(dateString, culture, DateTimeStyles.None, out resultingDate) and it DOES parse the correct date!
So the question is how come the DateTime.TryParse knows the pattern of a date string when this info is not a part of CultureInfo and how to get to this info in a culture?
Thanks!
I agree with xanatos, there is no perfect solution for that and you can't assume that every format GetAllDateTimePatterns returns can be perfectly parsable with Parse or TryParse methods.
From DateTimeFormatInfo.GetAllDateTimePatterns;
You can use the custom format strings in the array returned by the
GetAllDateTimePatterns method in formatting operations. However, if
you do, the string representation of a date and time value returned in
that formatting operation cannot always be parsed successfully by the
Parse and TryParse methods. Therefore, you cannot assume that the
custom format strings returned by the GetAllDateTimePatterns method
can be used to round-trip date and time values.
If you see Remarks section on the page, there are only 42 formats that can be parsed by TryParse method in 96 formats that GetAllDateTimePatterns method returns for it-IT culture for example.7
Tarek Mahmoud Sayed responded as;
Parse/TryParse are implemented as finite state machine so it doesn’t
really use the date patterns in parsing. It just split the parsed
string into tokens and try to find if the token match specific part of
the date (like Month, day, day of week…etc.). in the other hand
ParseExact/TryParseExact will just parse the string according to the
passed format pattern.
In short, Parsing is really hard because there are a lot of things that can trip it up. And someone in some government could suddenly decide that country X should use D/M/Y instead of M/D/Y, or could have someone entering data used to the other format.
I talk a little about this on a blog post (toward the bottom-ish) https://web.archive.org/web/20190110065542/https://blogs.msdn.microsoft.com/shawnste/2005/04/05/culture-data-shouldnt-be-considered-stable-except-for-invariant/
DateTime.Parse attempts to guess what the input might be based on the pattern(s) and separators it sees in the specified culture. Unfortunately, some cultures are REALLY hard to guess at. For example, . has been used for time formats in some locales, so is 1.1.1 12.12.12 the 12th day of December 2012? Or the 1st day of January 2001?
ParseExact (as the other answers suggest) is more reliable as you can tell it exactly what you're looking for - even better, you can also tell the user exactly what to enter. (Hopefully this is human input). Unfortunately it requires the user to follow the template.
This is also why most date controls you encounter, especially on the web, have separate fields for month, day & year.
For machine readable formats its best to spit it out in some standard format and read it back in with that exact same format. We've had customers send data from one country to another using the CurrentCulture and wonder why their vendor can't read it ;-)

DateTime.TryParse - What was actually parsed?

I'm struggling a little bit in C# with DateTime.TryParse().
Essentially, given a string I need to extract the year and/or month and day in the current display culture. Sometimes I only get a year, or a month, or all three. Depending on what I get, I have a different control flow.
So far, I managed to parse a variety of strings into a DateTime; that isn't my problem.
My problem is that I wish to know WHAT was actually parsed (i.e. did I get a month or a year, or both).
The uninitialized DateTime defaults to 01/01/0001, and I cannot set everything to an invalid date, such as 99/99/9999 and then see what was filled.
I was thinking maybe I need to do regex, but the DateTime class provides that parsing for multiple cultures, which is very important in this project.
I've tried searching for this, but maybe I'm not using the right terms, because surely someone else must have had this issue before.
Update:
Here's some sample code of what I've got:
string strIn = Console.ReadLine();
DateTimeStyles enStyles = DateTimeStyles.AllowInnerWhite | DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.AssumeLocal;
bFound = DateTime.TryParse(strIn, CultureInfo.CreateSpecificCulture("en-US"), enStyles, out cDT);
Now, bFound will be true if something was parsed successfully. However, I need to know which parts of the date were parsed successfully
I dont understand you but are you looking for a specified format for your datetime?
string dateAndTimeFormat = "yyyy.MM.dd HH:mm:ss:fff"; // example of format
string dateAndTime = yourdatetimevalue;
DateTime toDateTime = DateTime.ParseExact(dateTime, dateTimeFormat, System.Globalization.CultureInfo.InvariantCulture)
How formats are used:
http://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.71).aspx
EDIT 1
The tryparse returns true or false. False if it fails. Maybee that can be usefull?
Otherwise you can set the culture before the tryparse, if you are able to do so.
DateTime.TryParse(dateString, culture, styles, out dateResult)
Check the examples here :http://msdn.microsoft.com/en-us/library/9h21f14e.aspx
Under remarks:
"This method tries to ignore unrecognized data, if possible, and fills in missing month, day, and year information with the current date. If s contains only a date and no time, this method assumes the time is 12:00 midnight. If s includes a date component with a two-digit year, it is converted to a year in the current culture's current calendar based on the value of the Calendar.TwoDigitYearMax property. Any leading, inner, or trailing white space character in s is ignored. The date and time can be bracketed with a pair of leading and trailing NUMBER SIGN characters ('#', U+0023), and can be trailed with one or more NULL characters (U+0000)."
Hope some of that helps.
The DateTime.TryParse() returns value only on success.
So for below code example the variable dt is initialized to 01/01/0001 00:00:00 when declared.
When TryParse tries to extract date from string(MM/DD/YYYY format), and if it failes, then dt variable is having value 01/01/0001 00:00:00. Otherwise dt will contain the actual extracted datetime value (as in 2).
1)
DateTime dt;
DateTime.TryParse("23/15/2013", out dt);
// dt contains "01/01/0001 00:00:00"`
2)
`DateTime dt;
DateTime.TryParse("23/12/2013 6:25", out dt);
// dt contains "23/12/2013 06:25:00"`
There is no need to check WHAT was actually parsed.
Datetime value will be parsed if it's valid otherwise default datetime value will be returned.

.NET: Why is TryParseExact failing on Hmm and Hmmss?

I'm trying out the DateTime.TryParseExact method, and I have come over a case that I just don't get. I have some formats and some subjects to parse that each should match one of the formats perfectly:
var formats = new[]
{
"%H",
"HH",
"Hmm",
"HHmm",
"Hmmss",
"HHmmss",
};
var subjects = new[]
{
"1",
"12",
"123",
"1234",
"12345",
"123456",
};
I then try to parse them all and print out the results:
foreach(var subject in subjects)
{
DateTime result;
DateTime.TryParseExact(subject, formats,
CultureInfo.InvariantCulture,
DateTimeStyles.NoCurrentDateDefault,
out result);
Console.WriteLine("{0,-6} : {1}",
subject,
result.ToString("T", CultureInfo.InvariantCulture));
}
I get the following:
1 : 01:00:00
12 : 12:00:00
123 : 00:00:00
1234 : 12:34:00
12345 : 00:00:00
123456 : 12:34:56
And to my question... why is it failing on 123 and 12345? Shouldn't those have become 01:23:00 and 01:23:45? What am I missing here? And how can I get it to work as I would expect it to?
Update: So, seems like we might have figured out why this is failing sort of. Seems like the H is actually grabbing two digits and then leaving just one for the mm, which would then fail. But, does anyone have a good idea on how I can change this code so that I would get the result I am looking for?
Another update: Think I've found a reasonable solution now. Added it as an answer. Will accept it in 2 days unless someone else come up with an even better one. Thanks for the help!
Ok, so I think I have figured this all out now thanks to more reading, experimenting and the other helpful answers here. What's happening is that H, m and s actually grabs two digits when they can, even if there won't be enough digits for the rest of the format. So for example with the format Hmm and the digits 123, H would grab 12 and there would only be a 3 left. And mm requires two digits, so it fails. Tadaa.
So, my solution is currently to instead use just the following three formats:
var formats = new[]
{
"%H",
"Hm",
"Hms",
};
With the rest of the code from my question staying the same, I will then get this as a result:
1 : 01:00:00
12 : 12:00:00
123 : 12:03:00
1234 : 12:34:00
12345 : 12:34:05
123456 : 12:34:56
Which I think should be both reasonable and acceptable :)
0123
012345
I'm guessing it looks for a length of 2/4/6 when it finds a string of numbers like that. Is 123 supposed to be AM or PM? 0123 isn't ambiguous like that.
If you do not use date or time
separators in a custom format pattern,
use the invariant culture for the
provider parameter and the widest form
of each custom format specifier. For
example, if you want to specify hours
in the pattern, specify the wider
form, "HH", instead of the narrower
form, "H"
cite:
http://msdn.microsoft.com/en-us/library/ms131044.aspx
As others have pointed out H is ambiguous because it implies a 10 hour day, where as HH is 12
To quote from MSDN's Using Single Custom Format Specifiers:
A custom date and time format string consists of two or more characters. For example, if the format string consists only of the specifier h, the format string is interpreted as a standard date and time format specifier. However, in this particular case, an exception is thrown because there is no h standard date and time format specifier.
To use a single custom date and time format specifier, include a space before or after the date and time specifier, or include a percent (%) format specifier before the single custom date and time specifier. For example, the format strings "h " and "%h" are interpreted as custom date and time format strings that display the hour represented by the current date and time value. Note that, if a space is used, it appears as a literal character in the result string.
So, should that have been % H in the first element in the formats array?
Hope this helps,
Best regards,
Tom.
I could be wrong, but I suspect it may have to do with the ambiguity inherent in the "H" part of your format string -- i.e., given the string "123", you could be dealing with hour "1" (01:00) or hour "12" (12:00); and since TryParseExact doesn't know which is correct, it returns false.
As for why the method does not supply a "best guess": the documentation is not on your side on this one, I'm afraid. From the MSDN documentation on DateTime.TryParse (emphasis mine):
When this method returns, contains the
DateTime value equivalent to the date
and time contained in s, if the
conversion succeeded, or
DateTime.MinValue if the
conversion failed. The conversion
fails if either the s or format
parameter is null, is an empty string, or does not
contain a date and time that
correspond to the pattern specified in
format. This parameter is passed
uninitialized.
"123" and "12345" seem to be ambiguous with respect to the TryParseExact method. "12345" could be either 12:34:50 or 01:23:45 for instance. Just a guess though.

Categories