Say, I have two strings containing date/time in arbitrary user-provided format for an arbitrary culture:
string str1 = "6/19/2013";
string str2 = "6/19/2013 1 am";
I can parse them by doing:
DateTime dt1 = DateTime.Parse(str1);
DateTime dt2 = DateTime.Parse(str2);
But how do I know if the time part was present & parsed into the DateTime object?
What do you guys think about something like this?
public static DateTime ParseDateTimeWithTimeDifferentiation(string str, out bool bOutTimePresent)
{
//Parse date/time from 'str'
//'bOutTimePresent' = receives 'true' if time part was present
DateTime dtRes;
//Get formats for the current culture
DateTimeFormatInfo dtfi = CultureInfo.CurrentUICulture.DateTimeFormat;
DateTimeStyles dts = DateTimeStyles.AllowWhiteSpaces |
DateTimeStyles.AssumeLocal;
//Get all formats
string[] arrFmts = dtfi.GetAllDateTimePatterns();
foreach (string strFmt in arrFmts)
{
if (DateTime.TryParseExact(str, strFmt, CultureInfo.InvariantCulture, dts, out dtRes))
{
//Parsed it!
//These format codes come from here:
// http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx
bOutTimePresent = strFmt.IndexOfAny(new char[] { 'H', 'h', 'm', 's', 'f', 'F', 't', 'z' }) != -1;
return dtRes;
}
}
//As a fall-back, just parse it as-is
dtRes = DateTime.Parse(str);
//Assume it has time, as otherwise we'd catch the date-only above
bOutTimePresent = true;
return dtRes;
}
You can try using two separate calls to DateTime.ParseExact or DateTime.TryParseExact. This will be especially easy if you know the format of the date and time parts. The code would look something like this:
DateTime dateValue;
var culture = new CultureInfo("en-US");
if (DateTime.TryParseExact(dateString, "M/d/yyyy H:mm:ss", culture,
DateTimeStyles.None, out dateValue))) {
//Using date and time. dateValue var is set.
}
else if (DateTime.TryParseExact(dateString, "M/d/yyyy", culture,
DateTimeStyles.None, out dateValue))) {
//Using just date. dateValue var is set.
}
If you cannot anticipate the exact format of the date/time string, you can either enumerate a bunch of possible possible formats, or use regular expressions to try to extract the time part. Read more about custom date and time formats here. There are also some provided standard date and time formats.
If no time was specified in the string that was parsed, the TimeOfDay property of the DateTime object will be set to midnight (00:00:00). You can then check if that's the case with something like this:
if (dt1.TimeOfDay.Equals(new TimeSpan(0,0,0))) {
//do something
} else {
//do something else
}
EDIT: Another approach could be to separate the date and time sections of the string. This is assuming some type of numerical date format is passed using dashes, commas, or anything besides spaces.
string[] dateString = str1.Split(' ');
string[] date2String = str2.Split(' ');
You'll now have a string array that can be easily used to check for special values. dateString[0], for example, should contain your entire date. dateString[1] and beyond will have any time formats, and can be recombined and parsed into a TimeSpan object. Obviously if you have only a single entity in the array, they've not entered any time.
Related
I'd like to take a datetime string, and get the string version of its format:
e.g. 2017-01-02 would yield YYYY-MM-dd for logging purposes if a datetime is parsed incorrectly due to a parsing exception.
Is this possible with System.DateTime or any other built-in?
"2017-01-02" would yield "YYYY-MM-dd"
It's not possible. You are asking for magic, making something out of nothing.
There is no way without meta information for a computer (or a human) to decide if that is the 2nd January or the 1st February. Both is possible.
There is no reliable way of getting that format string based on a string that might look like a date.
The closest hack that I can come up with is iterating over all cultures and then trying to ParseExact the predefined DateTime patterns that are found in each culturinfo's DateTimeFormat property.
The hack would look like this:
var date = "2017-01-02";
var formats = new Dictionary<string,int>();
// go over all cultures
foreach(var ci in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
// each culture has a DateTimeFormatInfo that holds date and time patterns
foreach(var p in typeof(DateTimeFormatInfo)
.GetProperties()
.Where(prop => prop.Name.EndsWith("Pattern")))
{
// get a pattern property from the cultureinfo DateTimeFormat
var fmt = (string) p.GetValue(ci.DateTimeFormat, null);
try
{
// try to parse the date
DateTime.ParseExact(date,fmt , ci);
// add the format
if (formats.Keys.Contains(fmt))
{
formats[fmt]++; // how often this was a valid date
}
else
{
formats.Add(fmt, 1); // first time we found it
}
}
catch
{
// no date in this culture for this format, ignore
}
}
}
// output the formats that were parsed as a date
foreach(var kv in formats)
{
// Dump is a linqPad extension, use Console.WriteLine if that bothers you
kv.Value.Dump(kv.Key);
}
and on my box this returns
yyyy-MM-dd
40
yyyy-M-d
1
Now for 01/02/2017 it would return:
dd/MM/yyyy
255
d/M/yyyy
93
M/d/yyyy
20
d/MM/yyyy
11
MM/dd/yyyy
2
which shows a bit of the concerns raised in the comments. Without knowing the culture a date string was generated it is a guess what the date format was. Worst case it was a string with numbers and dashes between them.
I have a string like "1392/02/10 22:30:15", how can I separate each number in a variable with split? my code is in the following:
string str1="1392/02/10 22:30:15";
string[] str2 = str1.Split(new char[] { '/', ':',' '});
I got 1392, 02 and 10 but to get 22 by
int hour = int.Parse(str2[3]);
make an execption with this title:"Input string was not in a correct format."
I'd parse the date
string input = "1392/02/10 22:30:15";
string format = "yyyy'/'MM'/'dd HH:mm:ss";
DateTime result = DateTime.ParseExact(input, format, System.Globalization.CultureInfo.InvariantCulture);
int hour = result.Hour;
Fiddle: https://dotnetfiddle.net/489Ev3
It would make much more sense if you'd just parse the date as a DateTime:
string str1 = "1392/02/10 22:30:15";
DateTime d = DateTime.ParseExact(str1, "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture);
If you are not sure about the validness of your input, you can use TryParseExact:
if (DateTime.TryParseExact(str1, "yyyy/MM/dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime d))
{
// the date is valid, use it
}
Your current code works, but is quite error prone. You better rely on pieces of the framework that automate this task. One problem with your code could be an extra space, a tab instead of a space, etc.
When use the .ParseExact() method for the DateTime, i always get the same output as the string i put in. Here is my code:
[Authorize(Roles = "Backoffice, Manager")]
[HttpPost]
public ActionResult FilmShowCreate(FilmShowViewModel newFilmShow)
{
if (ModelState.IsValidField("FilmId") && ModelState.IsValidField("Time"))
{
DateTime unformattedDateTime = newFilmShow.Date.Date + newFilmShow.Time.TimeOfDay;
string dateString = unformattedDateTime.ToString("yyyy-MM-dd HH:mm:ss");
DateTime dbDate = DateTime.ParseExact(dateString, "yyyy-MM-dd HH:mm:ss",
CultureInfo.GetCultureInfo("en-US"), DateTimeStyles.AdjustToUniversal);
FilmShow filmShow = new FilmShow
{
Film = filmRepository.GetFilm(newFilmShow.FilmId),
Cinema = cinemaRepository.GetCinema(newFilmShow.CinemaId),
ThreeDimensional = newFilmShow.ThreeDimensional,
Date = dbDate,
SpecialEvent = newFilmShow.SpecialEvent
};
filmShowsRepository.AddShow(filmShow);
return View("SuccesfullFilmShowCreate");
The string dateString is formatted good, but it is a string and I need to store it in the database as a format DateTime like this "year-month-day hours:minutes:seconds". But for whatever reason the ParseExact doesn't seem to work in my case. The DateTime format i get is "dd-MM-yyyy HH:mm".
It doesn't do what you want because, well, that function isn't supposed to do what you are describing.
ParseExact simply indicates that the input must match the given format in order to be used (and not throw an exception). It is a counterpart to Parse which will accept any valid Date/Time format. It has absolutely no bearing on the future format of any string representation of the DateTime object it creates.
If you want to output it in a given format, pass your format string into ToString before sending that string to the database. Of course, if you are using something like EF, the conversion is done for you and it shouldn't matter.
Example:
string myFormattedDateTime = dbDate.ToString("yyyy-MM-dd HH:mm:ss");
Reading your question more closely, I realize that you seem to think that DateTime has some "stored" format. It does not. DateTime is just a collection of numbers that hold the information required to represent a date and time. The format you are describing only exists in string representations.
How can I convert a system date format (like 3/18/2014) to the format readable in DateTime?
I wanted to get the total days from two dates, which will come from two TextBoxes.
I have tried this syntax:
DateTime tempDateBorrowed = DateTime.Parse(txtDateBorrowed.Text);
DateTime tempReturnDate = DateTime.Parse(txtReturnDate.Text);
TimeSpan span = DateTime.Today - tempDateBorrowed;
rf.txtDaysBorrowed.Text = span.ToString();
But tempDateBorrowed always returns the minimum date for a DateTime varibale. I think this is because DateTime does not properly parse my system date format. As a consequence, it incorrectly displays the number of days. For example, if I try to enter 3/17/2014 and 3/18/2014 respectively, I always get -365241 days instead of 1.
Edit: I wanted my locale to be non-specific so I did not set a specific locale for my date format. (My system format by the way is en-US)
Try DateTime.ParseExact method instead.
See following sample code (I've used strings instead of TextBoxes since I used a Console app to write this code). Hope this helps.
class Program
{
static void Main(string[] args)
{
string txtDateBorrowed = "3/17/2014";
string txtReturnDate = "3/18/2014";
string txtDaysBorrowed = string.Empty;
DateTime tempDateBorrowed = DateTime.ParseExact(txtDateBorrowed, "M/d/yyyy", null);
DateTime tempReturnDate = DateTime.ParseExact(txtReturnDate, "M/d/yyyy", null);
TimeSpan span = DateTime.Today - tempDateBorrowed;
txtDaysBorrowed = span.ToString();
}
}
ToString is not Days
TimeSpan.TotalDays Property
You can try specifying the format of the datetime in the textboxes like this
DateTime tempDateBorrowed = DateTime.ParseExact(txtDateBorrowed.Text.Trim(), "M/d/yyyy", CultureInfo.InvariantCulture);
DateTime tempReturnDate = DateTime.ParseExact(txtReturnDate.Text.Trim(), "M/d/yyyy", CultureInfo.InvariantCulture);
Also you may have to check if the values from the textboxes are valid.
My first thought is to just replace the TextBox controls with a DateTimePicker or equivalent, depending on what platform you're developing on. Converting strings to dates or vice-versa is more of a pain than it seems at first.
Or you could try using DateTime.ParseExact instead, to specify the exact expected format:
DateTime tempDateBorrowed =
DateTime.ParseExact("3/17/2014", "M/dd/yyyy", CultureInfo.InvariantCulture);
Or you could specify a specific culture in the call to DateTime.Parse:
var tempDateBorrowed = DateTime.Parse("17/3/2014", new CultureInfo("en-gb"));
var tempDateBorrowed = DateTime.Parse("3/17/2014", new CultureInfo("en-us"));
try formatting your date to iso 8601 or something like that before parsing it with DateTime.Parse.
2014-03-17T00:00:00 should work with DateTime.Parse. ("yyyy-MM-ddTHH:mm:ssZ")
Try this:
if(DateTime.TryParseExact(txtDateBorrowed.Text, "M/d/yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out tempDateBorrowed))
{
TimeSpan span = DateTime.Today - tempDateBorrowed;
}
I am trying to convert my string formated value to date type with format dd/MM/yyyy. It runs fine but when I enter fromdate(dd/MM/yyyy) in textbox its fine and todate(dd/MM/yyyy) in textbox then it gives an error that string was not recognized as a valid datetime.What is the problem exactly i dont know. same code run on another appliction its run fine but in my application it shows Error.
Below I have used array for required format and split also used.
string fromdate = punchin.ToString();
string[] arrfromdate = fromdate.Split('/');
fromdate = arrfromdate[1].ToString() + "/" + arrfromdate[0].ToString() + "/" + arrfromdate[2].ToString();
DateTime d1 = DateTime.Parse(fromdate.ToString());
try with DateTime.TryParseExact as below
DateTime date;
if (DateTime.TryParseExact(inputText, "MM/dd/yyyy",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out date))
{
// Success
}
if you know the format of input date time you don't need to do any string manipulation.
But you need to give correct Date and Time Format String
I got 5/13/2013 12:21:35 PM in string fromdate
Use DateTime.TryParseExact, You don't have to split your string based on / and then get first three items from the array instead you can simply do:
DateTime dt;
if (DateTime.TryParseExact("5/13/2013 12:21:35 PM",
"M/d/yyyy hh:mm:ss tt",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out dt))
{
//date is fine
}
Using single d and single M as it can accomodate single digit as well as double digits day/Month part. You can simply pass punchin as the string parameter, Calling ToString on string types is redundant.
Try :
DateTime.ParseExact(fromdate, "MM/dd/yy", CultureInfo.InvariantCulture)
Obviously you can reformat the above, and use different providers by creating an instance of CultureInfo related to the string you are parsing, and you can modify the format string to reflect that culture or to accommodate more date parts