Strange behaviour of the "M" custom format specifier in c# - 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

Related

Formatting Date with abbreviated month, while adhering to culture date structure

Developing a multilanguage application, and trying to format a DateTime object to string within a limited space in a table. Full month names might be too long, so we have to use abbreviations.
Some cultures have the format "Oct 12", some have "12. okt" and so on.
The standard .ToString("m") is almost what I want, but with abbreviations:
https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings#MonthDay
Similar question, but the answer won't work for us, as this dictates the order of month and day:
Formatting Date String abbreviating month
Is there any way of getting the overall structure of a culture's date formatting, like order of day and month, with or without "." after the number etc? Or another way of generating the required string? This feels like it should be fairly straight forward, as all the pieces are already present.
As per the documentation you linked, the custom date and time format "m" is defined by a CultureInfo's DateTimeFormat.MonthDayPattern property. So I'd look that up for the current culture and customize the format string. Then use the modified format string with ToString.
I was able to solve this myself using the culture's DateTimeFormat wich provides a MonthDayPattern. By simply replacing "MMMM" with "MMM" this will solve the challenge, at least for the locales that we plan to support. I have not tested with all possible locales.
(I know it won't work for "ja-JP", wich has special characters in their pattern)
DateTime date = DateTime.Now;
CultureInfo culture = new("en-US", false);
DateTimeFormatInfo dateTimeFormat = culture.DateTimeFormat;
string pattern = dateTimeFormat.MonthDayPattern.Replace("MMMM", "MMM");
string formatted = date.ToString(pattern, culture);
The pattern for "en-US" goes from "MMMM d" to "MMM d" giving "Oct 13"
The pattern for "nb-NO" goes from "d. MMMM" to "d. MMM" giving "13. okt."

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.

Comparison between dates in C# application

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.

DateTime.ParseExact string format exception

I am trying to convert a string into datetime with the following C# code,
DateTime dTo = DateTime.ParseExact(dateTo, "mm/dd/yyyy", CultureInfo.InvariantCulture);
eachtime I pass dateTo as 1/1/2010 it fails, instead it needs the string to be 01/01/2010.
What string format should I use to support both 01/01/2010 and 1/1/2010?
Using the following date format expression will allow you to use either single or double digit day and month elements.
"M/d/yyyy"
Note that the capital M is significant - a lower case m is the placeholder for minutes.
You will find more information related to date format strings here.
You can use the following Powershell command to test them.
[DateTime]::ParseExact('01/01/2010', 'M/d/yyyy', $null)
Capital M is month, little m is mins i think.
But to the point of the question, use Parse. ParseExact implies you know the exact format of the input.
You could try this format: MM/dd/yyyy, but I think there's no single format string that could support both inputs. You could test if the length of your dateTo string is less than 10 characters use M/d/yyyy, otherwise MM/dd/yyyy.

Why do these two date formats differ?

I'm trying to produce just the day number in a WPF text block, without leading zeroes and without extra space padding (which throws off the layout). The first produces the day number with a space, the second produces the entire date. According to the docs, 'd' should produce the day (1-31).
string.Format("{0:d }", DateTime.Today);
string.Format("{0:d}", DateTime.Today);
UPDATE:Adding % is indeed the trick. Appropriate docs here.
See here
d, %d
The day of the month. Single-digit days do not have a leading zero. The application specifies "%d" if the format pattern is not combined with other format patterns.
Otherwise d is interpreted as:
d - 'ShortDatePattern'
PS. For messing around with format strings, using LinqPad is invaluable.
From the MSDN documentation for "Custom Date and Time Format Strings":
Any string that is not a standard date
and time format string is interpreted
as a custom date and time format
string.
{0:d} is interpreted as a standard data and time format string. From "Standard Date and Time Format Strings", the "d" format specifier:
Represents a custom date and time
format string defined by the current
ShortDatePattern property.
With the space, {0:d } doesn't match any standard date and time format string, and is interpreted as a custom data and time format string. From "Custom Date and Time Format Strings", the "d" format specifier:
Represents the day of the month as a
number from 1 through 31.
The {0:d} format uses the patterns defined in the Standard Date and Time Format Strings document of MSDN. 'd' translates to the short date pattern, 'D' to the long date pattern, and so on and so forth.
The format that you want appears to be the Custom Date and Time Format Modifiers, which work when there is no matching specified format (e.g., 'd ' including the space) or when you use ToString().
You could use the following code instead:
string.Format("{0}", DateTime.Today.ToString("d ", CultureInfo.InvariantCulture));

Categories