Wrong DateTime format - c#

When I run the following code in a DotNetFiddle, I get the output I expect:
var myDate = new DateTime(2019, 6, 1);
Console.WriteLine(myDate.ToString("MM/dd/yy"));
// Output is: 06/01/19
But when I run the exact same code in a brand new C# Console application (.NET Framework 4.5.2) or in the C# Interactive window, I get this output:
06-01-19
Why does the Console app and the C# Interactive window replace / with - in the output? Based on this answer and the documentation, I would expect the date to be delimited with / not -. In this example from Microsoft's documentation, it shows the output containing /:
Console.WriteLine("The current date and time: {0:MM/dd/yy H:mm:ss zzz}",
thisDate2);
// The example displays the following output:
// The current date and time: 06/10/11 15:24:16 +00:00

When working with datetime format strings, the / character is special, just like d, M, or y. It means use the system-defined date separator character.
So the system date separator at DotNetFiddle is /, but the separator on your system is -.
If you really always need the / character, this excerpt from the linked documentation will help:
To change the date separator for a particular date and time string, specify the separator character within a literal string delimiter. For example, the custom format string mm'/'dd'/'yyyy produces a result string in which "/" is always used as the date separator.
Be careful with this. Over-riding the system and user's choices should not be done lightly. For example, I sometimes see people want to do this in order for format a date for use in an SQL command, and that is never okay; if you're formatting dates as strings for SQL, rather than using query parameters, you're doing something very wrong.

Related

What is this C#/.net5 notation called with a colon in a interpolated string?

I came across some notation in an interpolated string currentDate:d in the Microsoft documentation but they do not elaborate on how it works or what it is called, so I don't know how to look it up further. It appears to deconstruct a DateTime and get the date and time specifically, and only seems to work in the interpolated string; I can't use the same trick to pull the time out into a variable. I'm wondering if I can use that notation for other objects and how it works.
var currentDate = DateTime.Now;
var time = currentDate:t; // this throws error
Console.WriteLine($"{Environment.NewLine}It is currently {currentDate:d} at {currentDate:t}!");
outputs:
It is currently 2021-10-31 at 10:41 AM!
MS docs source: https://learn.microsoft.com/en-us/dotnet/core/tutorials/with-visual-studio-code?pivots=dotnet-5-0
I can't think of a better way to ask this question, so would appreciate a hint.
It is explained in the docs that you linked. It says:
The dollar sign ($) in front of a string lets you put expressions such as variable names in curly braces in the string. The expression value is inserted into the string in place of the expression. This syntax is referred to as interpolated strings.
The link there takes you to the page "$ - string interpolation - C# reference", which has a section named "Structure of an interpolated string" that says this:
The structure of an item with an interpolation expression is as follows:
{<interpolationExpression>[,<alignment>][:<formatString>]}
[...]
formatString: A format string that is supported by the type of the expression result. For more information, see Format String Component.
The link "Format String Component" then gives you all the info you need:
The optional formatString component is a format string that is appropriate for the type of object being formatted. Specify a standard or custom numeric format string if the corresponding object is a numeric value, a standard or custom date and time format string if the corresponding object is a DateTime object, or an enumeration format string if the corresponding object is an enumeration value.
[...]
Date and time types: Standard Date and Time Format Strings / Custom Date and Time Format Strings
The linked page "Standard Date and Time Format Strings" explains d as follows:
Format Specifier
Description
Examples
d
Short date pattern. - More information: The short date ("d") format specifier
2009-06-15T13:45:30 -> 6/15/2009 (en-US) [...]
This already explains it in short, but the link provided in the table leads to an even more detailed explanation.
This also shows an example of how to use such a format string outside of an interpolated string, using the ToString method:
DateTime date1 = new DateTime(2008, 4, 10);
Console.WriteLine(date1.ToString("d",
DateTimeFormatInfo.InvariantInfo)); // Displays 04/10/2008
Console.WriteLine(date1.ToString("d",
CultureInfo.CreateSpecificCulture("en-US"))); // Displays 4/10/2008
Console.WriteLine(date1.ToString("d",
CultureInfo.CreateSpecificCulture("en-NZ"))); // Displays 10/04/2008
Console.WriteLine(date1.ToString("d",
CultureInfo.CreateSpecificCulture("de-DE"))); // Displays 10.04.2008
It's just some of the standard date and time format specifiers.
"d" is the short date format specifier, "t" is the short time format specifier.
More info can be found at Standard date and time format strings on MSDocs.
Aside: You could have achieved this without string interpolation as well:
Console.WriteLine("It is currently {0:d} at {0:t}!", currentDate);

Get Date From Filename Using ParseExact

I am trying to find the file that has the highest date in a single directory. The problem is that the dates are attached to filenames. I am using the following code to try to pull the max date but am running into trouble with the ParseExact.
//Gather all of the files in the local directory
var files = Directory.EnumerateFiles(r.getLeadLocalFile());
returnDateTime = files.Max(f => DateTime.ParseExact(f, "MMddyyXXXX.csv", CultureInfo.InvariantCulture));
I continue to get the following error:
String was not recognized as a valid DateTime.
I can tell that the value of the file path is being passed in because the value of 'f' is below:
\\\\vamarnas02\\users\\meggleston\\User Files\\Leads\\110716ENH9.csv
The value of ENH9 can change depending on the file.
How can I get the DateTime from my filename?
Here's another approach. No need to split out anything. But one bad filename (as with your current approach) will ruin it:
//Gather all of the files in the local directory
var files = new DirectoryInfo(r.getLeadLocalFile()).GetFiles("*.csv");
returnDateTime = files.Max(f => DateTime.ParseExact(f.Name.Substring(0, 6), "MMddyy", CultureInfo.InvariantCulture));
You need to split out the date text before parsing. The following code snippet should help.
Assume the variable f is the filename.
DateTime.ParseExact(f.Substring( f.LastIndexOf("\\") + 1, 6), "MMddyy", CultureInfo.InvariantCulture);
Do you really need to use ParseExact here? Because it seems that you just need to get Int32 values and compare them afterwards.
So another approach: you can extract your date parts with some regex, from the path provided. For example you can use this one:
\\\d{6} // 2 slashes and 6 digits. I'm not an expert in regex, but seems that this one is enough for your task.
And trim the \\ part afterwards. So something like this in the loop:
private string ExtractDateFromFilename(string filename) {
var m = Regex.Match(filename, #"\\\d{6}");
if (!string.IsNullOrEmpty(m.Value))
return m.Value.Substring(1);
return "";
}
Try only passing the filename "110716ENH9.csv" instead of the full path of the file.
From MSDN DateTime.ParseExact Documentation:
Converts the specified string representation of a date and time to its DateTime equivalent using the specified format and culture-specific format information. The format of the string representation must match the specified format exactly.
From what you've provided, your format does not match exactly.
--
Only pass the first 6 characters of the filename to the ParseExact function and amend your format to be "MMddyy."

Is a DateTime.ToString format expression affected by the current culture locale?

I have some code that is logging a timestamp in format from a thick client app
DateTime.UtcNow.ToString("MM/dd/yy HH:mm:ss")
Now, on a client running in China (not sure exactly which locale) this is producing a date in the log with the format
11-20-13 02:14:03
I notice it's using - instead of / to delimit the parts, even though I explicitly wanted /
I tried to set the current culture to Chinese simplified zh-CN but I wasn't able to reproduce how the remote client was able to produce that string
Does current culture locale affect the output of this format string? Or does / have some other meaning I'm not aware of?
Yes, the / character is a placeholder for whatever the current culture uses to separate parts of the date. From MSDN:
The "/" custom format specifier represents the date separator, which is used to differentiate years, months, and days. The appropriate localized date separator is retrieved from the DateTimeFormatInfo.DateSeparator property of the current or specified culture.
As with other format specifiers, you can escape the / with a \:
DateTime.UtcNow.ToString(#"MM\/dd\/yy HH\:mm\:ss")
Or specify an explicit culture when formatting the string:
DateTime.UtcNow.ToString("MM/dd/yy HH:mm:ss", CultureInfo.InvariantCulture)
Yes, that's how it works. / is being replaced with the local date separator. The same applies to : as a time separator. You can find more on MSDN: Custom Date and Time Format Strings.
To change that, escape them with \:
DateTime.UtcNow.ToString(#"MM\/dd\/yy HH\:mm\:ss")

DotNet DateTime.ToString strange results

Why does:
DateTime.Now.ToString("M")
not return the month number? Instead it returns the full month name with the day on it.
Apparently, this is because "M" is also a standard code for the MonthDayPattern. I don't want this...I want to get the month number using "M". Is there a way to turn this off?
According to MSDN, you can use either "%M", "M " or " M" (note: the last two will also include the space in the result) to force M being parsed as the number of month format.
What's happening here is a conflict between standard DateTime format strings and custom format specifiers. The value "M" is ambiguous in that it is both a standard and custom format specifier. The DateTime implementation will choose a standard formatter over a customer formatter in the case of a conflict, hence it is winning here.
The easiest way to remove the ambiguity is to prefix the M with the % char. This char is way of saying the following should be interpreted as a custom formatter
DateTime.Now.ToString("%M");
Why not use
DateTime.Now.Month?
You can also use System.DateTime.Now.Month.ToString(); to accomplish the same thing
You can put an empty string literal in the format to make it a composite format:
DateTime.Now.ToString("''M")
It's worth mentioning that the % prefix is required for any single-character format string when using the DateTime.ToString(string) method, even if that string does not represent one of the built-in format string patterns; I came across this issue when attempting to retrieve the current hour. For example, the code snippet:
DateTime.Now.ToString("h")
will throw a FormatException. Changing the above to:
DateTime.Now.ToString("%h")
gives the current date's hour.
I can only assume the method is looking at the format string's length and deciding whether it represents a built-in or custom format string.

Region Agnostic Char.IsSeparator(ch)?

I have a function that parses a string containing a date(and/or time) e.g. "2009-12-10". I get the order of year-month-day from the Short Date pattern. When going through the string I use Char.IsSeparator(ch) to figure out when the numbers end.
Now however in the case of Korean it seems the Char.IsSeparator(ch) returns false on separator characters. Is there any way to know whether the chars in between the numbers are separator regardless of region setting?
(I also parse strings that are more free containing things like "*20 May 200*9" so doing Char.IsAlphaNum() on the separator will not work either as I don't know the content basically)
Example inputs: "20.10.2009" "2009-05-20" "20 May 2009" "20.05.2009 10:00 AM" "1/1/2009" (in Singapore its D/M/Y in US it is M/D/Y") "Tisdag, 1 Januari 1962" (all strings localized)
Output would be an equivalent of a DateTime instance filled as much as possible (although we use our own types).
Korean seems to have a couple of characters in front of the time and as separator it looks like the symbols are different depending on position in the string.
If you pick up the format using the current short format, you could perhaps also be able to pick up the separator through DateTimeFormatInfo.CurrentInfo.DateSeparator.
Is there any reason why you need to parse the string manually?
If you used the built-in date/time parsing methods - Parse, ParseExact, TryParse or TryParseExact - then you could pass in the required culture-specific format info and let the framework worry about separators etc.

Categories

Resources