Is there a way to determine if Convert.ToDateTime added the year? - c#

I have a large collection of text files that need to be parsed using Regexes. Some of the data that I'm collecting are dates that come in all sorts of formats, such as 12/1/15, Dec 1, 2015, 12-1-15, etc. They sometimes have a year listed and sometimes don't. My problem occurs when I have dates that span two years, i.e. 12/1 - 1/8, where the first date needs the year 2015 and the second date needs the year 2016. Currently I'm parsing them as strings and trying to convert them to DateTimes. This adds the current day's year, so if it's parsed in 2015, the second date is wrong and if it's parsed in 2016 the first date is wrong. Is there a way to determine when Convert.ToDateTime adds the year since the string was missing one? If I could determine this I have a way to determine which year needs to be added.

Convert.ToDateTime just uses DateTime.Parse. My understanding is that when interpreting MM/dd formats, it will always assume the current year.
In your scenario, it sounds like you will need to make some determination on how you want to handle this. For instance, you could test that if the latter date precedes the prior date, you add a year.

Related

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 format - one digit day not recognized

I need to read a String in the following format: "6102015" (meaning October 6th, 2015) and turn it into DateTime objects.
I tried the following code, which did not work:
DateTime.ParseExact("6102015", "dMyyyy", CultureInfo.CurrentCulture);
But when I tested the code using the date string with an extra 0, it worked.
DateTime.ParseExact("06102015", "dMyyyy", CultureInfo.CurrentCulture); // works correctly
Is there a way to read this date format without having to add the 0?
I thank you in advance for any help.
Is there a way to read this date format without having to add the 0?
Adding a 0 is the least of your worries, IMO. That takes one line of code.
Assuming you've got a copy of the database or something you can alter, effectively, I would:
Create a field of a date/time type, or if you must use a string, do so but use an ISO-8601 format (yyyy-MM-dd)
Parse all the values which are already 8 characters
Parse all the values which are 6 characters by inserting two 0s (so abcccc becomes 0a0bcccc)
For each remaining value, of the form abcyyyy:
Try parsing it as 0abcyyyy
Try parsing it as ab0cyyyy
If only one parse worked, store that result in the new column
Now look at all the remaining rows (i.e. the ones you haven't populated with a "known good" value
You may be able to use other data (such as insertion order) to work out which is the "right" parse...
You may not - in which case you need to decide what to do

Why does this attempt to parse DateTime fail?

This:
bool ret = DateTime.TryParse("Sunday 11 November", out date);
fails to parse the date string? Why?
I realize the string is an incomplete date, but why can't the framework handle it? Does the framework always try to return a legitimate date? Because if so, that would explain it (Sunday 11th November 2014 is not a valid date)
It's easy enough to verify, just change the date to a valid one (Sunday 9 November), and guess what, it works. You will also see that the year is set to 2014.
So yes, it appears that if the date is not valid, parsing will fail.
In the documentation for DateTime.TryParse, it states the following:
This method tries to ignore unrecognized data, if possible, and fills
in missing month, day, and year information with the current date.
In your example, the year is missing, so it will plug in the current year, giving Sunday 11 November 2014. I'm assuming it is invalid because the 11th of Nov does not fall on a Sunday. The documentation does include examples that include the name of the day.
It's funny to see this question, because this non-intuitive feature of TryParse (filling in missing parts) bit someone in my office just today.

C# Regex, formatting a time

I'm making a timecard program, where the user enters the start time, end time, and project name. They can click "Add" and it adds the entered details to a listbox.
I don't allow the data to be added unless the start time and end time are formatted like this: 08:14am It gets annoying, though, having to enter it exactly like that each time, so I decided to, via regexes, have it automatically format. So if you enter 8:14, it will change it to 08:14am. How can I accomplish this via Regex.Replace()?
If you have any other methods, don't hesitate to list them.
Edit 1: I also have other replacements in mind; for example 814 goes to 08:14am, and 8 goes to 08:00am
Edit 2: So Now I'm using this code:
string[] formats = { "h:mm", "h", "hh", "hmm", "hhmm", "h:mmtt", "htt", "hhtt" };
DateTime dt = DateTime.ParseExact(t.Text, formats, new CultureInfo("en-US"), DateTimeStyles.None);
t.Text = dt.ToString("hh:mmtt").ToLower();
And it replaces some things, like h:mm but not others like h.
Have you looked at DateTime.Parse? It accepts "08:14am", "8:14"[1] and other variants, and returns a DateTime set to 8:14 am on today's date.
[1] In the UK culture at least -- consider providing a CultureInfo parameter depending on whether you want to pay attention to the user's local format preferences, or adopt a fixed format.
EDIT I also have other replacements in mind; for example 814 goes to 08:14am, and 8 goes to 08:00am
Take a look at DateTime.ParseExact: you can provide an array of valid time formats (such as "hh:mm", "hmm", "h" etc.)
Coming at it from a completely different direction, how about using a mask on the input?
For example, there are a number of JavaScript and jQuery tools available to do this.
Using this approach retains some user control over the input, and lets the user see their input.
have you considered using a DateTimePicker? Making the user write the time looks like more of a hassle.
See e.g. http://msdn.microsoft.com/en-us/library/system.windows.forms.datetimepicker.aspx
I think regex are overkill for this. Why not simply append the "am" at the end, in case nto already added is a 2 line code in case you are working with strings in the method.
I would recommend against using regular expressions if possible (as others have said, it seems like overkill) and try using datetime formats. See here: http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx
The "HH" format tag will format the hour as a 24-hour time from 00 to 23. Traditionally, 12 hour times are not zero-padded to the left, but 24 hour times are (at least as often as I see them), probably to avoid confusion between 1800 and 0800 . Alternatively, if you don't want 24 hour times, you could probably just left-pad the hour part of the string with a zero to up to 2 digits.
EDIT:
Based on your new requirements, I'd say write a simple parser to let users input "814" meaning "08:14 AM" and make use of the time-formatting functionality for display.

Storing a short date in a DateTime object

I'm trying to store a shortened date (mm/dd/yyyy) into a DateTime object. The following code below is what I am currently trying to do; this includes the time (12:00:00 AM) which I do not want :(
DateTime goodDateHolder = Convert.ToDateTime(DateTime.Now.ToShortDateString());
Result will be 10/19/2009 12:00:00 AM
DateTime is an integer interpreted to represent both parts of DateTime (ie: date and time). You will always have both date and time in DateTime. Sorry, there's nothing you can do about it.
You can use .Date to get the date part. In these cases, the time will always be 12:00 but you can just ignore that part if you don't want it.
You only have two options in this situation.
1) Ignore the time part of the value.
2) Create a wrapper class.
Personally, I am inclined to use option 1.
A DateTime will always have a time component - even if it is 12:00:00 AM. You just need to format the DateTime when you display it (e.g. goodDateHolder.ToShortDateString()).
Instead of .Now you can use .Today which will not remove the time part, but will only fill the date part and leave time to the default value.
Later on, as others pointed out, you should try to get the date part ignoring the time part, depending on the situation.
You'll always get the time portion in a DateTime type.
DateTime goodDateHolder = Convert.ToDateTime(DateTime.Now.ToShortDateString());
will give you today's date but will always show the time to be midnight.
If you're worried about formatting then you would try something like this
goodDateHolder.ToString("mm/dd/yyyy")
to get the date in the format that you want.
This is a good resource msdn-dateformat
You can also check out Noda Time based off the Java Joda Time library.
DateTime object stores both the date and the time. To display only the date, you would use the DateTime.ToString(string) method.
DateTime goodDateHolder = DateTime.Now;
// outputs 10/19/2009
Console.WriteLine(goodDateHolder.ToString("MM/dd/yyyy"));
For more information on the ToString method, follow this link
You might not be able to get it as a DateTime object...but when you want to display it you can format it in the way you want by doing something like.
myDateTime.ToString("M/d/yyyy") which gives 10/19/2009 for your example.
DateTime is merely a UInt64 with useful and clever formatting wrapped around it to make it appear like a date plus a time. You cannot eliminate the time element.

Categories