So I think there is a simple answer to this problem. Essentially I am getting a decimal storage of a DateTime from a database that is in essence '9062017'. I was wanting to create a decimal extension method to account for decimals and parsing and do variable formats for an extensible DateTime. I was playing around with the logic, yet it keeps not working. I was looking up a few threads on SO like this: Parse datetime in multiple formats. But it's not explaining what I think would just work and does not.
static void Main(string[] args)
{
DateTime d = new DateTime(2017, 9, 6);
//Cool what I would expect to show the day position with two digits and the month uses one if needed else it will go to two if needed.
Console.WriteLine(d.ToString("Mddyyyy"));
//I can parse out an int and see it is exactly as above.
int i = Int32.Parse(d.ToString("Mddyyyy"));
Console.WriteLine(i.ToString());
DateTime dt;
string[] formats = { "Mddyyyy", "MMddyyyy" };
//Keeps default min value of DateTime and ignores parsing regardless of formats done in the first arg changes, the seconds formats to apply, or cultural changes.
DateTime.TryParseExact(i.ToString(), formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out dt);
Console.WriteLine(dt);
//Console.WriteLine(i);
Console.ReadLine();
}
I think you should avoid the string conversion entirely. It's pointless and error prone. It's much simpler just to do the maths:
public static DateTime Int32ToDateTime(int value)
{
int year = value % 10000;
int day = (value / 10000) % 100;
int month = value / 1000000;
// Specify whatever kind is appropriate; it's unclear from the question.
return new DateTime(year, month, day);
}
public static int DateTimeToInt32(DateTime date) =>
date.Year + (date.Day * 10000) + (date.Month * 1000000);
I wouldn't use an extension method for this. It's not appropriate for all integers. You should be really, really clear when you're doing this. If you have multiple numeric formats, you could have an interface an multiple implementations:
public interface IDateTimeInt32Converter
{
DateTime Int32ToDateTime(int value);
int Int32ToDateTime(DateTime date);
}
public class YearMonthDayConverter : IDateTimeInt32Converter
{
// etc
}
// Ditto for MonthDayYearConverter and DayMonthYearConverter
I think you should veer away from TryParseExact since it's going to be a trip down the garden path, in your case (as in, expect to write a lot more code than you've done so far).
A simpler, possibly easier approach, is to simply parse out the string representation of the decimal value.
Here's a sample to illustrate what I mean:
var d = 9062017.0;
var s = d.ToString();
if (s.IndexOf(".") > -1)
s = s.Substring(0, s.IndexOf("."));
string mm = "", dd = "", yy = "";
// single-digit month?
if (s.Length == 7)
{
mm = s.Substring(0, 1);
dd = s.Substring(1, 2);
yy = s.Substring(3);
}
if (s.Length == 8)
{
mm = s.Substring(0, 2);
dd = s.Substring(3, 2);
yy = s.Substring(4);
}
// rather than parse directly to DateTime, just parse
// the individual date portions as ints...
var year = Convert.ToInt32(yy);
var month = Convert.ToInt32(mm);
var day = Convert.ToInt32(dd);
// transform into the date...
var dt = new DateTime(year, month, day);
What is the recommended way of formatting TimeSpan objects into a string with a custom format?
Please note: this answer is for .Net 4.0 and above. If you want to format a TimeSpan in .Net 3.5 or below please see JohannesH's answer.
Custom TimeSpan format strings were introduced in .Net 4.0. You can find a full reference of available format specifiers at the MSDN Custom TimeSpan Format Strings page.
Here's an example timespan format string:
string.Format("{0:hh\\:mm\\:ss}", myTimeSpan); //example output 15:36:15
(UPDATE) and here is an example using C# 6 string interpolation:
$"{myTimeSpan:hh\\:mm\\:ss}"; //example output 15:36:15
You need to escape the ":" character with a "\" (which itself must be escaped unless you're using a verbatim string).
This excerpt from the MSDN Custom TimeSpan Format Strings page explains about escaping the ":" and "." characters in a format string:
The custom TimeSpan format specifiers do not include placeholder separator symbols, such as the symbols that separate days from hours, hours from minutes, or seconds from fractional seconds. Instead, these symbols must be included in the custom format string as string literals. For example, "dd.hh:mm" defines a period (.) as the separator between days and hours, and a colon (:) as the separator between hours and minutes.
For .NET 3.5 and lower you could use:
string.Format ("{0:00}:{1:00}:{2:00}",
(int)myTimeSpan.TotalHours,
myTimeSpan.Minutes,
myTimeSpan.Seconds);
Code taken from a Jon Skeet answer on bytes
For .NET 4.0 and above, see DoctaJonez answer.
One way is to create a DateTime object and use it for formatting:
new DateTime(myTimeSpan.Ticks).ToString(myCustomFormat)
// or using String.Format:
String.Format("{0:HHmmss}", new DateTime(myTimeSpan.Ticks))
This is the way I know. I hope someone can suggest a better way.
Simple. Use TimeSpan.ToString with c, g or G. More information at MSDN
I would go with
myTimeSpan.ToString("hh\\:mm\\:ss");
Personally, I like this approach:
TimeSpan ts = ...;
string.Format("{0:%d}d {0:%h}h {0:%m}m {0:%s}s", ts);
You can make this as custom as you like with no problems:
string.Format("{0:%d}days {0:%h}hours {0:%m}min {0:%s}sec", ts);
string.Format("{0:%d}d {0:%h}h {0:%m}' {0:%s}''", ts);
Dim duration As New TimeSpan(1, 12, 23, 62)
DEBUG.WriteLine("Time of Travel: " + duration.ToString("dd\.hh\:mm\:ss"))
It works for Framework 4
http://msdn.microsoft.com/en-us/library/ee372287.aspx
This is awesome one:
string.Format("{0:00}:{1:00}:{2:00}",
(int)myTimeSpan.TotalHours,
myTimeSpan.Minutes,
myTimeSpan.Seconds);
You can also go with:
Dim ts As New TimeSpan(35, 21, 59, 59) '(11, 22, 30, 30) '
Dim TimeStr1 As String = String.Format("{0:c}", ts)
Dim TimeStr2 As String = New Date(ts.Ticks).ToString("dd.HH:mm:ss")
EDIT:
You can also look at Strings.Format.
Dim ts As New TimeSpan(23, 30, 59)
Dim str As String = Strings.Format(New DateTime(ts.Ticks), "H:mm:ss")
if (timeSpan.TotalDays < 1)
return timeSpan.ToString(#"hh\:mm\:ss");
return timeSpan.TotalDays < 2
? timeSpan.ToString(#"d\ \d\a\y\ hh\:mm\:ss")
: timeSpan.ToString(#"d\ \d\a\y\s\ hh\:mm\:ss");
All literal characters must be escaped.
This is the approach I used my self with conditional formatting. and I post it here because I think this is clean way.
$"{time.Days:#0:;;\\}{time.Hours:#0:;;\\}{time.Minutes:00:}{time.Seconds:00}"
example of outputs:
00:00 (minimum)
1:43:04 (when we have hours)
15:03:01 (when hours are more than 1 digit)
2:4:22:04 (when we have days.)
The formatting is easy. time.Days:#0:;;\\ the format before ;; is for when value is positive. negative values are ignored. and for zero values we have;;\\ in order to hide it in formatted string. note that the escaped backslash is necessary otherwise it will not format correctly.
Here is my extension method:
public static string ToFormattedString(this TimeSpan ts)
{
const string separator = ", ";
if (ts.TotalMilliseconds < 1) { return "No time"; }
return string.Join(separator, new string[]
{
ts.Days > 0 ? ts.Days + (ts.Days > 1 ? " days" : " day") : null,
ts.Hours > 0 ? ts.Hours + (ts.Hours > 1 ? " hours" : " hour") : null,
ts.Minutes > 0 ? ts.Minutes + (ts.Minutes > 1 ? " minutes" : " minute") : null,
ts.Seconds > 0 ? ts.Seconds + (ts.Seconds > 1 ? " seconds" : " second") : null,
ts.Milliseconds > 0 ? ts.Milliseconds + (ts.Milliseconds > 1 ? " milliseconds" : " millisecond") : null,
}.Where(t => t != null));
}
Example call:
string time = new TimeSpan(3, 14, 15, 0, 65).ToFormattedString();
Output:
3 days, 14 hours, 15 minutes, 65 milliseconds
I used the code below. It is long, but still it is one expression, and produces very friendly output, as it does not outputs days, hours, minutes, or seconds if they have value of zero.
In the sample it produces output: "4 days 1 hour 3 seconds".
TimeSpan sp = new TimeSpan(4,1,0,3);
string.Format("{0}{1}{2}{3}",
sp.Days > 0 ? ( sp.Days > 1 ? sp.ToString(#"d\ \d\a\y\s\ "): sp.ToString(#"d\ \d\a\y\ ")):string.Empty,
sp.Hours > 0 ? (sp.Hours > 1 ? sp.ToString(#"h\ \h\o\u\r\s\ ") : sp.ToString(#"h\ \h\o\u\r\ ")):string.Empty,
sp.Minutes > 0 ? (sp.Minutes > 1 ? sp.ToString(#"m\ \m\i\n\u\t\e\s\ ") :sp.ToString(#"m\ \m\i\n\u\t\e\ ")):string.Empty,
sp.Seconds > 0 ? (sp.Seconds > 1 ? sp.ToString(#"s\ \s\e\c\o\n\d\s"): sp.ToString(#"s\ \s\e\c\o\n\d\s")):string.Empty);
I use this method. I'm Belgian and speak dutch so plural of hours and minutes is not just adding 's' to the end but almost a different word than singular.
It may seem long but it is very readable I think:
public static string SpanToReadableTime(TimeSpan span)
{
string[] values = new string[4]; //4 slots: days, hours, minutes, seconds
StringBuilder readableTime = new StringBuilder();
if (span.Days > 0)
{
if (span.Days == 1)
values[0] = span.Days.ToString() + " dag"; //day
else
values[0] = span.Days.ToString() + " dagen"; //days
readableTime.Append(values[0]);
readableTime.Append(", ");
}
else
values[0] = String.Empty;
if (span.Hours > 0)
{
if (span.Hours == 1)
values[1] = span.Hours.ToString() + " uur"; //hour
else
values[1] = span.Hours.ToString() + " uren"; //hours
readableTime.Append(values[1]);
readableTime.Append(", ");
}
else
values[1] = string.Empty;
if (span.Minutes > 0)
{
if (span.Minutes == 1)
values[2] = span.Minutes.ToString() + " minuut"; //minute
else
values[2] = span.Minutes.ToString() + " minuten"; //minutes
readableTime.Append(values[2]);
readableTime.Append(", ");
}
else
values[2] = string.Empty;
if (span.Seconds > 0)
{
if (span.Seconds == 1)
values[3] = span.Seconds.ToString() + " seconde"; //second
else
values[3] = span.Seconds.ToString() + " seconden"; //seconds
readableTime.Append(values[3]);
}
else
values[3] = string.Empty;
return readableTime.ToString();
}//end SpanToReadableTime
This is a pain in VS 2010, here's my workaround solution.
public string DurationString
{
get
{
if (this.Duration.TotalHours < 24)
return new DateTime(this.Duration.Ticks).ToString("HH:mm");
else //If duration is more than 24 hours
{
double totalminutes = this.Duration.TotalMinutes;
double hours = totalminutes / 60;
double minutes = this.Duration.TotalMinutes - (Math.Floor(hours) * 60);
string result = string.Format("{0}:{1}", Math.Floor(hours).ToString("00"), Math.Floor(minutes).ToString("00"));
return result;
}
}
}
The Substring method works perfectly when you only want the Hours:Minutes:Seconds. It's simple, clean code and easy to understand.
var yourTimeSpan = DateTime.Now - DateTime.Now.AddMinutes(-2);
var formatted = yourTimeSpan.ToString().Substring(0,8);// 00:00:00
Console.WriteLine(formatted);
No one has shown approach with decimal format specifier which is my favorite one, especially when used with string interpolation - https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings?redirectedfrom=MSDN#decimal-format-specifier-d
For example:
$"{time.Hours:D2}:{time.Minutes:D2}:{time.Seconds:D2}.{time.Milliseconds:D3}"
// Sample output: 00:00:09.200
You can of course wrap it up in some helper method.
Here is my version. It shows only as much as necessary, handles pluralization, negatives, and I tried to make it lightweight.
Output Examples
0 seconds
1.404 seconds
1 hour, 14.4 seconds
14 hours, 57 minutes, 22.473 seconds
1 day, 14 hours, 57 minutes, 22.475 seconds
Code
public static class TimeSpanExtensions
{
public static string ToReadableString(this TimeSpan timeSpan)
{
int days = (int)(timeSpan.Ticks / TimeSpan.TicksPerDay);
long subDayTicks = timeSpan.Ticks % TimeSpan.TicksPerDay;
bool isNegative = false;
if (timeSpan.Ticks < 0L)
{
isNegative = true;
days = -days;
subDayTicks = -subDayTicks;
}
int hours = (int)((subDayTicks / TimeSpan.TicksPerHour) % 24L);
int minutes = (int)((subDayTicks / TimeSpan.TicksPerMinute) % 60L);
int seconds = (int)((subDayTicks / TimeSpan.TicksPerSecond) % 60L);
int subSecondTicks = (int)(subDayTicks % TimeSpan.TicksPerSecond);
double fractionalSeconds = (double)subSecondTicks / TimeSpan.TicksPerSecond;
var parts = new List<string>(4);
if (days > 0)
parts.Add(string.Format("{0} day{1}", days, days == 1 ? null : "s"));
if (hours > 0)
parts.Add(string.Format("{0} hour{1}", hours, hours == 1 ? null : "s"));
if (minutes > 0)
parts.Add(string.Format("{0} minute{1}", minutes, minutes == 1 ? null : "s"));
if (fractionalSeconds.Equals(0D))
{
switch (seconds)
{
case 0:
// Only write "0 seconds" if we haven't written anything at all.
if (parts.Count == 0)
parts.Add("0 seconds");
break;
case 1:
parts.Add("1 second");
break;
default:
parts.Add(seconds + " seconds");
break;
}
}
else
{
parts.Add(string.Format("{0}{1:.###} seconds", seconds, fractionalSeconds));
}
string resultString = string.Join(", ", parts);
return isNegative ? "(negative) " + resultString : resultString;
}
}
If you want the duration format similar to youtube, given the number of seconds
int[] duration = { 0, 4, 40, 59, 60, 61, 400, 4000, 40000, 400000 };
foreach (int d in duration)
{
Console.WriteLine("{0, 6} -> {1, 10}", d, d > 59 ? TimeSpan.FromSeconds(d).ToString().TrimStart("00:".ToCharArray()) : string.Format("0:{0:00}", d));
}
Output:
0 -> 0:00
4 -> 0:04
40 -> 0:40
59 -> 0:59
60 -> 1:00
61 -> 1:01
400 -> 6:40
4000 -> 1:06:40
40000 -> 11:06:40
400000 -> 4.15:06:40
I wanted to return a string such as "1 day 2 hours 3 minutes" and also take into account if for example days or minuttes are 0 and then not showing them. thanks to John Rasch for his answer which mine is barely an extension of
TimeSpan timeLeft = New Timespan(0, 70, 0);
String.Format("{0}{1}{2}{3}{4}{5}",
Math.Floor(timeLeft.TotalDays) == 0 ? "" :
Math.Floor(timeLeft.TotalDays).ToString() + " ",
Math.Floor(timeLeft.TotalDays) == 0 ? "" : Math.Floor(timeLeft.TotalDays) == 1 ? "day " : "days ",
timeLeft.Hours == 0 ? "" : timeLeft.Hours.ToString() + " ",
timeLeft.Hours == 0 ? "" : timeLeft.Hours == 1 ? "hour " : "hours ",
timeLeft.Minutes == 0 ? "" : timeLeft.Minutes.ToString() + " ",
timeLeft.Minutes == 0 ? "" : timeLeft.Minutes == 1 ? "minute " : "minutes ");
I want to convert to timestamp in 24hrs fromat to 12 hrs format.Here is my code with output mentioned in braces.
date = Dyear + "" + Dmonth + "" + Dday + " " + strhour+""+strminute+""+"00"; (20130628 142900)
DateTime dt = new DateTime(Convert.ToInt32(Dyear), Convert.ToInt32(Dmonth), Convert.ToInt32(Dday), Convert.ToInt32(strhour), Convert.ToInt32(strminute), 00);(6/28/2013 2:29:00 PM)
TimeSpan ts = dt.Subtract(new DateTime(1970, 01, 01, 00, 00, 00));(15884.14:29:00)
String sTimeStamp = ts.TotalMilliseconds.ToString("0"); (1372429740000)
the above sTimeStamp will be in MM/DD/YYYY HH:MM:ttt format(06/28/2013 19:59:000) like "1372429740".
I want to display the time stamp in 12 hr format like MM/DD/YYYY hh:mm:ttt format(06/28/2013 07:59:000) like "1372386540"
Bear in mind that the format you refer is just for displaying purposes. If you want to account for this modification in your calculations (putting 2 instead of 14), a 12h lag would appear.
If you just want to display 6/28/2013 2:29:00, you can use the following string (the calculated miliseconds will not be affected):
string sTimeStamp = dt.ToString("MM/dd/yyyy hh:mm:ss tt");
If what you want is performing this change during the time calculations (not sure about the reason for doing that), you have to modify the way in which dt is generated (this time, the calculated milisenconds will be affected: 12h lag with respect to the option above):
DateTime dt = new DateTime(Convert.ToInt32(Dyear), Convert.ToInt32(Dmonth), Convert.ToInt32(Dday), Convert.ToInt32(new DateTime(2000, 1, 1, Convert.ToInt32(strhour), 0, 0).ToString("hh:mm tt").Split(':')[0]), Convert.ToInt32(strminute), 0);
In this second case, dt will always be formed on account of the "12h understanding" of the input value; for example: it will account for 2(am) if strhour is either 2 or 14.
internal static string ConvertTo_12_Format(string str)
{
//using system function
DateTime dt = DateTime.ParseExact(str, "HH:mm", System.Globalization.CultureInfo.InvariantCulture);
string s = dt.ToString("hh:mm");
//using logic
StringBuilder sb = new StringBuilder();
int h1 = (int)str[0] - '0';
int h2 = (int)str[1] - '0';
string Meridien;
int hh = h1 * 10 + h2;
if (hh < 12)
{
Meridien = "AM";
}
else
Meridien = "PM";
hh %= 12;
int c1 = (int)str[3] - '0';
int c2 = (int)str[4] - '0';
if (hh == 0)
{
sb.Append("12:");
//18:30
// Printing minutes and seconds
sb.Append(c1.ToString() + c2.ToString());
}
else
{
if(hh < 10)
{
sb.Append("0" + hh + ":");
sb.Append(c1.ToString() + c2.ToString());
}else
{
sb.Append(hh + ":");
sb.Append(c1.ToString() + c2.ToString());
}
}
sb.Append(" "+Meridien);
return sb.ToString();
}
What would be the most effective way to parse the hour and AM/PM value from a string format like "9:00 PM" in C#?
Pseudocode:
string input = "9:00 PM";
//use algorithm
//end result
int hour = 9;
string AMPM = "PM";
Try this:
string input = "9:00 PM";
DateTime result;
if (!DateTime.TryParse(input, out result))
{
// Handle
}
int hour = result.Hour == 0 ? 12
: result.Hour <= 12 ? result.Hour
: result.Hour - 12;
string AMPM = result.Hour < 12 ? "AM" : "PM";
Try this:
DateTime result;
string input = "9:00 PM";
//use algorithm
if (DateTime.TryParseExact(input, "h:mm tt",
CultureInfo.CurrentCulture,
DateTimeStyles.None, out result))
{
//end result
int hour = result.Hour > 12 ? result.Hour % 12 : result.Hour;
string AMPM = result.ToString("tt");
}
string input = "9:00 PM";
DateTime dt = DateTime.Parse(input);
int hour = int.Parse(dt.ToString("hh"));
string AMPM = dt.ToString("tt");
See Custom Date and Time Format Strings for getting information from a DateTime value in all kinds of formats.
Use DateTime.Parse:
string input = "9:00 PM";
DateTime parsed = DateTime.Parse(input);
int hour = int.Parse(dt.ToString("h"));
string AMPM = parsed.ToString("tt");
Edit: Removed %12 on hour since that fails for 12 AM.
begin pseudocode:
DateTime dt;
if (!DateTime.TryParse("9:00 AM", out dt))
{
//error
}
end pseudocode
I need a regular expression to validate time.
Valid values would be from 0:00 to 23:59.
When the time is less than 10:00 it should also support one character numbers.
These are valid values:
9:00
09:00
Try this regular expression:
^(?:[01]?[0-9]|2[0-3]):[0-5][0-9]$
Or to be more distinct:
^(?:0?[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$
I don't want to steal anyone's hard work but this is exactly what you're looking for, apparently.
using System.Text.RegularExpressions;
public bool IsValidTime(string thetime)
{
Regex checktime =
new Regex(#"^(20|21|22|23|[01]d|d)(([:][0-5]d){1,2})$");
return checktime.IsMatch(thetime);
}
I'd just use DateTime.TryParse().
DateTime time;
string timeStr = "23:00"
if(DateTime.TryParse(timeStr, out time))
{
/* use time or timeStr for your bidding */
}
The regex ^(2[0-3]|[01]d)([:][0-5]d)$ should match 00:00 to 23:59. Don't know C# and hence can't give you the relevant code.
/RS
If you want to allow military and standard with the use of AM and PM (optional and insensitive), then you may want to give this a try.
^(?:(?:0?[1-9]|1[0-2]):[0-5][0-9]\s?(?:[AP][Mm]?|[ap][m]?)?|(?:00?|1[3-9]|2[0-3]):[0-5][0-9])$
Very late to the party but I created this Regex which I found work the best for 24H format (HH:mm:ss OR HH:mm OR H:mm:ss OR H:mm):
private bool TimePatternValidation(string time)
=> new Regex(#"^(([0-1]?[0-9])|([2][0-3]))(:([0-5][0-9])){1,2}$").IsMatch(time);
[RegularExpression(#"^(0[1-9]|1[0-2]):[0-5][0-9]:[0-5][0-9] (am|pm|AM|PM)$",
ErrorMessage = "Invalid Time.")]
Try this
Better!!!
public bool esvalida_la_hora(string thetime)
{
Regex checktime = new Regex("^(?:0?[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$");
if (!checktime.IsMatch(thetime))
return false;
if (thetime.Trim().Length < 5)
thetime = thetime = "0" + thetime;
string hh = thetime.Substring(0, 2);
string mm = thetime.Substring(3, 2);
int hh_i, mm_i;
if ((int.TryParse(hh, out hh_i)) && (int.TryParse(mm, out mm_i)))
{
if ((hh_i >= 0 && hh_i <= 23) && (mm_i >= 0 && mm_i <= 59))
{
return true;
}
}
return false;
}
public bool IsTimeString(string ts)
{
if (ts.Length == 5 && ts.Contains(':'))
{
int h;
int m;
return int.TryParse(ts.Substring(0, 2), out h)
&& int.TryParse(ts.Substring(3, 2), out m)
&& h >= 0 && h < 24
&& m >= 0 && m < 60;
}
else
return false;
}