How to convert time only using DateTime.Parse? - c#

I have a string variable with it's value formatted to look like "1:23:45 AM"
I need to convert that into a DateTime variable for time without a date component.
I am receiving an "Unhandled exception" error that is being caused by the formatting. If I remove the "AM", it works fine but the "AM/PM" component is needed for what I am trying to do.
I am currently using the following code to attempt this...
"temp" is the name of the variable I am using until I come up with a more meaningful variable name...
public string PlusMinus12(string hour, string minute, string second, string ampm)
{
string PlusMinus;
int rndmTmp1 = Random1();
int rndmTmp2 = Random2();
if (rndmTmp1 == 0)
{
PlusMinus = hour + ":" + minute + ":" + second + ": " + ampm;
return PlusMinus;
}
else if (rndmTmp1 == 1)
{
string temp = hour + ":" + minute + ":" + second +": " + ampm;
**DateTime subtract = DateTime.Parse(temp);**
subtract.AddSeconds(-rndmTmp2);
PlusMinus = subtract.ToString("h:mm:ss tt");
return PlusMinus;
}
else
{
DateTime subtract = DateTime.Parse(temp); is the line causing the error
The error is:
An unhandled exception of type 'System.FormatException' occurred in mscorlib.dll
Additional information: String was not recognized as a valid DateTime.
Most of the information I have found so far on this topic include solutions that depend on the existence of the Date component, which I am not using.
Any ideas?
Thank you

You should try parsing it using DateTime.ParseExact using a custom format from here: Custom Date and Time Format Strings

Your problem is this
PlusMinus = hour + ":" + minute + ":" + second + ": " + ampm;
Change it to
PlusMinus = Int32.Parse(hour).ToString("00") + ":" + Int32.Parse(minute).ToString("00") + ":" + second.ToString("00") + " " + ampm;
A little convoluted since strings are passed in as input. No colon after the seconds and zero pad the numbers. Also, since they are input variables, at some point you should verify that they are between 0-59.

If you're only interested in returning the time part, add a extra variable that holds the date part and append it to the front of temp when you parse it?
like:
string tempDate = "2008-05-01 "

This works for me:
string timeString = "1:23:45 AM";
string format = "h:mm:ss tt";
CultureInfo provider = CultureInfo.InvariantCulture;
try
{
DateTime result = DateTime.ParseExact(timeString, format, provider);
Console.WriteLine("{0} converts to {1}.", timeString, result.ToString());
}
catch (FormatException)
{
Console.WriteLine("{0} is not in the correct format.", timeString);
}
Probably your issue is with a particular time.
UPDATE: You need to check you are passing minutes and seconds to this function with a 0 for values like 1-2..9. Because standard provider will not accept a string like '1:1:2 AM'.

public string PlusMinus12(string hour, string minute, string second, string ampm)
{
string PlusMinus;
int rndmTmp1 = Random1();
int rndmTmp2 = Random2();
if (rndmTmp1 == 0)
{
PlusMinus = hour + ":" + minute + ":" + second + ": " + ampm;
return PlusMinus;
}
else if (rndmTmp1 == 1)
{
string temp = hour + ":" + minute + ":" + second +": " + ampm;
DateTime subtract = DateTime.Parse("2000-01-01 " + temp);
subtract.AddSeconds(-rndmTmp2);
PlusMinus = subtract.ToString("h:mm:ss tt");
return PlusMinus;
}
else
{

Related

Valid Date Time conversion from String

I keep getting the error of "The string was not recognized as a valid DateTime. There is an unknown word starting at index 0." but I am unsure as the reason why.
//Date and Age
String months = Convert.ToString(txtMonth);
String days = Convert.ToString(txtDay);
String year = Convert.ToString(txtYear);
String DOB = days + " " + months + " " + year;
int age = AgeCalc(DOB);
//Age Function
private int AgeCalc(string date)
{
DateTime DOB = Convert.ToDateTime(date);
DateTime Year = DateTime.Now;
TimeSpan span = Year - DOB;
DateTime Age = DateTime.MinValue.AddDays(span.Days);
return Age.Year - 1;
}
//Separate Box
MessageBox.Show("First Name:" + fName + "\nLast Name:" + lName + "\nGender:" + gender + "\nAge:" +
age + "\nHeight (in inches):" + height + "\nWeight (lbs):" + weight + "\nMax Heart Rate:" + heartRate +
"\nTarget Heart Rate:" + targetRate + "\nBMI:" + BMI, "Result");
More code provided on request.
If you want to detect if the user entered the wrong value try this
string[] formats = { "dd/MM/yyyy", "dd/M/yyyy", "d/M/yyyy", "d/MM/yyyy","dd/MM/yy", "dd/M/yy", "d/M/yy", "d/MM/yy"};
if (DateTime.TryParseExact(date, formats, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out DateTime DOB))
{
// DOB variable is ready to use
Label1.Text = DOB.ToShortDateString();
} else {
//error handling goes here
Label1.Text = "ERROR: Invalid value";
}
DOB.ToShortDateString() will convert back into a string.
Assume that you only allow users to input correct value (valid integer). You can use this
new DateTime(Convert.ToInt32(txtYear), Convert.ToInt32(txtMonth), Convert.ToInt32(txtDay));

TimeSpan rounding on toString() C#

I measure the Time of a wav File and got it back in a TimeSpan.
When I look into the Timespan the totalSeconds value is the exact time i need!
For example: TotalSeconds = 6.6999999999999993
When I write it into a File, it will be roundet to 6.7!
I need the exact value in the textfile!
Here is the code:
TimeSpan duration = GetWavFileDuration(wav);
string[] wavStrings = wav.Split('\\');
using (TextWriter writer = new StreamWriter(wav.Replace(".wav", ".plist"), false, Encoding.UTF8))
{
writer.NewLine = "\n";
writer.Write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" +
"<plist version=\"1.0\">\n" +
"<dict>\n" +
"\t<key>bundle_id</key>\n" +
"\t<string>" + folderStrings[folderStrings.Length - 1] + "</string>\n" +
"\t<key>channels</key>\n" +
"\t<integer>2</integer>\n" +
"\t<key>duration</key>\n" +
"\t<real>" + duration.TotalSeconds.ToString().Replace(',', '.') + "</real>\n" +
"\t<key>filetitle</key>\n" +
"\t<string>" + wavStrings[wavStrings.Length - 1] + "</string>\n" +
"\t<key>sender</key>\n" +
"\t<string>" + folderStrings[folderStrings.Length - 1] + "</string>\n" +
"</dict>\n" +
"</plist>");
}
You can simply write the value of TotalSeconds to a file, e.g.:
TimeSpan ts = new TimeSpan(1234);
File.WriteAllText(#"C:\Temp\TimeTest.txt", ts.TotalSeconds.ToString());
// File contains: 0.0001234
You can pass the parameters to the ToString method:
ts.TotalSecondsToString("0.00"); //2dp Number
ts.TotalSecondsToString("n2"); // 2dp Number
ts.TotalSecondsToString("c2"); // 2dp currency
The first two options are for your issue.

iCal Creating Time Offset

When trying to create an iCal file I get a very strange issue that I cannot trace. The following is the code used and an example of an event that is set to start at 08:00 and end at 11:00. The file creates with relevant information, but when tryting to add it to Outlook an hour has been added to the end time.
DateTime eventDate = DateTime.Parse("19/06/2014");
DateTime startTime = DateTime.Parse("09:00:00");
DateTime endTime = DateTime.Parse("11:00:00");
string location = "Test Location";
string title = "Test Title";
context.Response.ContentType = "text/x-vcalendar";
string filename = String.Format("attachment; filename={0}.ics", eventname.Replace(" ", "-"));
context.Response.AddHeader("Content-disposition", filename);
context.Response.Write("BEGIN:VCALENDAR" + Environment.NewLine);
context.Response.Write("VERSION:2.0" + Environment.NewLine);
context.Response.Write("METHOD:PUBLISH" + Environment.NewLine);
context.Response.Write("BEGIN:VTIMEZONE" + Environment.NewLine);
context.Response.Write("TZID:Europe/London" + Environment.NewLine);
context.Response.Write("X-LIC-LOCATION:Europe/London" + Environment.NewLine);
context.Response.Write("BEGIN:DAYLIGHT" + Environment.NewLine);
context.Response.Write("TZOFFSETFROM:+0000" + Environment.NewLine);
context.Response.Write("TZOFFSETTO:+0100" + Environment.NewLine);
context.Response.Write("TZNAME:BST" + Environment.NewLine);
context.Response.Write("DTSTART:19700329T010000" + Environment.NewLine);
context.Response.Write("RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU" + Environment.NewLine);
context.Response.Write("END:DAYLIGHT" + Environment.NewLine);
context.Response.Write("BEGIN:STANDARD" + Environment.NewLine);
context.Response.Write("TZOFFSETFROM:+0100" + Environment.NewLine);
context.Response.Write("TZOFFSETTO:+0000" + Environment.NewLine);
context.Response.Write("TZNAME:GMT" + Environment.NewLine);
context.Response.Write("DTSTART:19701025T020000" + Environment.NewLine);
context.Response.Write("RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU" + Environment.NewLine);
context.Response.Write("END:STANDARD" + Environment.NewLine);
context.Response.Write("END:VTIMEZONE" + Environment.NewLine);
context.Response.Write("BEGIN:VEVENT" + Environment.NewLine);
context.Response.Write("ORGANIZER:MAILTO: test#domain.com" + Environment.NewLine);
context.Response.Write("UID: test2#domain.com" + Environment.NewLine);
context.Response.Write("DTSTART:" + startDate.ToUniversalTime().ToString("yyyyMMddTHHmmssZ") + Environment.NewLine);
context.Response.Write("DTEND:" + GetMeetingEndDate(startDate, endDate).ToString("yyyyMMddTHHmmssZ") + Environment.NewLine);
context.Response.Write("DTSTAMP:" + DateTime.Now.ToUniversalTime().ToString("yyyyMMddTHHmmssZ") + Environment.NewLine);
context.Response.Write("SUMMARY:" + subject + Environment.NewLine);
context.Response.Write("DESCRIPTION:" + description + Environment.NewLine);
context.Response.Write("LAST-MODIFIED:" + DateTime.Now.ToUniversalTime().ToString("yyyyMMddTHHmmssZ") + Environment.NewLine);
context.Response.Write("PRIORITY:5" + Environment.NewLine);
context.Response.Write("LOCATION;ENCODING=QUOTED-PRINTABLE:" + location + Environment.NewLine);
context.Response.Write("CLASS:PUBLIC" + Environment.NewLine);
context.Response.Write("END:VEVENT" + Environment.NewLine);
context.Response.Write("END:VCALENDAR");
The outcome of this is for the appointment to be added to Outlook with a start time of 09:00 and an end time of 12:00. The end time has increased by one hour.
Please note that the code about is intended for British/GMT use.
I have debugged this procedure and checked all the dates as they are being set and everything is correct. Is there anything that I am missing with this? I really don't want to have to force a reduction in the end hour just so it adds properly to Outlook.
Edit:
The following is the GetMeetingEndDate function.
DateTime GetMeetingEndDate(DateTime startDate, DateTime endDate)
{
DateTime newDate = new DateTime();
if (endDate < startDate)
{
newDate = endDate.AddHours(12);
}
else if (endDate == startDate)
{
newDate = startDate.AddDays(1).AddHours(-1);
}
else
{
newDate = endDate;
}
return newDate;
}
Thank you.
In the below code:-
context.Response.Write("DTSTART:" + startDate.ToUniversalTime().ToString("yyyyMMddTHHmmssZ") + Environment.NewLine);
context.Response.Write("DTEND:" + GetMeetingEndDate(startDate, endDate).ToString("yyyyMMddTHHmmssZ") + Environment.NewLine);
the DTSTART is set to value startDate.ToUniversalTime() whereas in function GetMeetingEndDate the dates are passed without converting into UTC. Because of this startdate is always correct but iCal is treating your local enddate as UTC date. That might be causing the problem of adding extra hour. The solution is to change the below code block as
context.Response.Write("DTEND:" + GetMeetingEndDate(startDate.ToUniversalTime(), endDate.ToUniversalTime()).ToString("yyyyMMddTHHmmssZ") + Environment.NewLine);

TimeSpan conversion from Custom Strings

I've got a custom control on my page that has a field for Hours, Minutes, and AM/PM. I need to be able to take each string Hour + Minutes + AM/PM and get a valid TimeSpan so I can combine with a Date.
I've tried a couple different ways but get Invalid TimeSpan errors. Here is my code
string date = DateDropDown.SelectedValue;
string hour = HourDropDown.SelectedValue;
string minute = MinuteDropDown.SelectedValue;
string timeofDay = AMPMDropDown.SelectedValue;
string timeStr = hour.PadLeft(2, '0') + ":" + minute + timeofDay;
TimeSpan custTime = TimeSpan.Parse(timeStr);
DateTime custDate = DateTime.Parse(date);
DateTime callBackDT = custDate.Add(custTime);
Aside from considering errors with the Parse. How can I get a valid timespan from with the time strings and am/pm?
Thanks
Just parse the DateTime once, at the end:
string date = DateDropDown.SelectedValue;
string hour = HourDropDown.SelectedValue;
string minute = MinuteDropDown.SelectedValue;
string timeofDay = AMPMDropDown.SelectedValue;
string dateStr = date + " " + hour.PadLeft(2, '0') + ":" + minute + " " + timeofDay;
DateTime callBackDT = DateTime.Parse(dateStr);
There is no reason to build a TimeSpan in this case, as DateTime.Parse can handle dates with times as a single DateTime.
If you don't have to use TimeSpan, just parse the entire string with DateTime.Parse:
var timeStr = string.Format("{0} {1}:{2} {3}", date, hour.PadLeft(2, '0'), minute, timeofDay);
var callBackDT = DateTime.Parse(timeStr, CultureInfo.CreateSpecificCulture("en-US"));
// Or whatever culture your string will be formatted with
TimeSpan objects don't have a concept of am / pm. You'd have to use a DateTime instead:
string timeStr = hour.PadLeft(2, '0') + ":" + minute.PadLeft(2, '0') + " " + timeofDay;
DateTime custDate = DateTime.ParseExact("HH:mm t", timeStr, null);
TimeSpan custTime = custDate.TimeOfDay;
Further Reading
Custom Date and Time Format Strings

Creating DateTime object from string

I currently am reading from a text file an assortment of data, and parsing out everything. One of the items being parsed out is a start time for an event in the format of:
yyMMddHHmm
1306050232
I then parse out to the following:
string year = "20" + time[0].ToString() + time[1].ToString();
string month = time[2].ToString() + time[3].ToString();
string day = time[4].ToString() + time[5].ToString();
string hour = time[6].ToString() + time[7].ToString();
string minute = time[8].ToString() + time[9].ToString();
string ampm ="";
int hourInt = Convert.ToInt32(hour);
if (hourInt <= 12)
{
time = month + "." + day + "." + year + "#" + hour + ":" + minute + " " + "AM";
ampm= "AM";
}
else
{
hourInt = hourInt - 12;
time = month + "." + day + "." + year + "#" + hourInt.ToString() + ":" + minute + " " + "PM";
ampm= "PM";
}
once these are parsed out, i combined the variables, and try to put it into a DateTime.
string tempStartTime = year + "-" + month + "-" + day + " " + hour + ":" + minute + " " + ampm;
string starttime = DateTime.ParseExact(tempStartTime, "yyyy-MM-dd HH:mm tt",null);
my issue is, I get a warning like this from the try catch:
System.FormatException: String was not recognized as a valid DateTime.
at System.DateTime.ParseExact(String s, String format, IFormatProvider provider)
at Project.GUI.parseSchedule(Int32 count)
I don't understand why, or how to correctly do this.
All I want is to take the start time from the file, convert it to a datetime object, and operate on it afterwards.
Why not simply parse with the format you are starting with?
var dt = DateTime.ParseExact(time, "yyMMddHHmm", CultureInfo.InvariantCulture);
There's no need for all of the pre-processing you're doing.
Parsing before parsing is generally quite unnecessary. If you have the input string
// yyMMddHHmm
string timestampString = "1306050232";
Then you should be able to do:
CultureInfo provider = CultureInfo.InvariantCulture;
DateTime timestamp = DateTime.ParseExact(timeStampString, "yyMMddHHmm", provider);
If not, I would like to have more information about the exact error you are getting.
Have a look at DateTime.ParseExact()
http://msdn.microsoft.com/en-us/library/w2sa9yss.aspx
DateTime result=null;
CultureInfo provider = CultureInfo.InvariantCulture;
// Parse date and time with custom specifier.
string dateString = "Sun 15 Jun 2008 8:30 AM -06:00";
string format = "ddd dd MMM yyyy h:mm tt zzz";
try {
result = DateTime.ParseExact(dateString, format, provider);
Console.WriteLine("{0} converts to {1}.", dateString, result.ToString());
}
catch (FormatException) {
Console.WriteLine("{0} is not in the correct format.", dateString);
}
You might want to look into custom formatters rather than trying to parse everything. I think that would make your code more maintainable, and probably somewhat easier to decode. There's a tool linked on that page that would let you test your format string before putting it into code, as well.

Categories