Im trying to convert a decmial number of hours to days, hours and minutes.
This is what I have so far, its not quite there yet. I need to subtract the number of hours from the days from the hours part if that makes sense?
/// <summary>
/// Converts from a decimal value to DD:HH:MM
/// </summary>
/// <param name="dHours">The total number of hours</param>
/// <returns>DD:HH:MM string</returns>
public static string ConvertFromDecimalToDDHHMM(decimal dHours)
{
try
{
decimal hours = Math.Floor(dHours); //take integral part
decimal minutes = (dHours - hours) * 60.0M; //multiply fractional part with 60
int D = (int)Math.Floor(dHours / 24);
int H = (int)Math.Floor(hours);
int M = (int)Math.Floor(minutes);
//int S = (int)Math.Floor(seconds); //add if you want seconds
string timeFormat = String.Format("{0:00}:{1:00}:{2:00}", D, H, M);
return timeFormat;
}
catch (Exception)
{
throw;
}
}
SOLUTION:
/// <summary>
/// Converts from a decimal value to DD:HH:MM
/// </summary>
/// <param name="dHours">The total number of hours</param>
/// <returns>DD:HH:MM string</returns>
public static string ConvertFromDecimalToDDHHMM(decimal dHours)
{
try
{
decimal hours = Math.Floor(dHours); //take integral part
decimal minutes = (dHours - hours) * 60.0M; //multiply fractional part with 60
int D = (int)Math.Floor(dHours / 24);
int H = (int)Math.Floor(hours - (D * 24));
int M = (int)Math.Floor(minutes);
//int S = (int)Math.Floor(seconds); //add if you want seconds
string timeFormat = String.Format("{0:00}:{1:00}:{2:00}", D, H, M);
return timeFormat;
}
catch (Exception)
{
throw;
}
}
You could use TimeSpan.FromHours to get the timespan, then you have all you need:
TimeSpan ts = TimeSpan.FromHours(Decimal.ToDouble(dHours));
For example:
int D = ts.Days;
int H = ts.Hours;
int M = ts.Minutes;
You need to subtract (D * 24) from hours... or you could just use:
int H = ((int) dHours) % 24;
If you're going to cast to int anyway, there's no need to call Math.Floor. So for example, you could actually use:
// I'd rename dHours as well, by the way...
int wholeHours = (int) dHours;
int days = wholeHours / 24;
int hours = wholeHours % 24;
int minutse = (int) ((dHours % 1M) * 60);
On the other hand, you need to be careful if it can be negative - all kinds of things could end up screwy in that case. If you don't believe you have to handle that, I'd explicitly check it and throw an exception if dHours is negative before you do anything else.
(Note that your try/catch block is pointless and distracting at the moment. Just get rid of it.)
Why not do something like this?
double d = 25.23523;
Timespan t = TimeSpan.FromHours(d);
This will give you:
t = 1.01:14:06.8280000
Then you can interrogate the TimeSpan object as you wish: http://msdn.microsoft.com/en-us/library/system.timespan.aspx
NOTE: TimeSpan.FromHours needs a double input, not a decimal.
Simple.
double counter = 0.25;
TimeSpan span = TimeSpan.FromMinutes(counter);
textbox1.Text = span.ToString(#"hh\:mm\:ss");
result will be 00:00:15 seconds. If counter = 1, then the result will be 00:01:00 and so on.
here is another post which expains it pretty good.
Convert date to string format yyyy-mm-dd HH:MM:SS - C#
MyDateTime.ToString("yyyy-MM-dd hh:mm:ss");
also
http://blog.stevex.net/string-formatting-in-csharp/
public static string GetTimeString(Decimal dHours)
{
DateTime dTime = new DateTime().AddHours(dHours);
return dTime.ToString("HH:mm:ss"); // HH: 24h or hh: 12h
}
Related
How to parse string like 30:15 to TimeSpan in C#? 30:15 means 30 hours and 15 minutes.
string span = "30:15";
TimeSpan ts = TimeSpan.FromHours(
Convert.ToDouble(span.Split(':')[0])).
Add(TimeSpan.FromMinutes(
Convert.ToDouble((span.Split(':')[1]))));
This does not seem too elegant.
If you're certain that the format will always be "HH:mm" then try something like this:
string span = "35:15";
TimeSpan ts = new TimeSpan(int.Parse(span.Split(':')[0]), // hours
int.Parse(span.Split(':')[1]), // minutes
0); // seconds
Similar to Luke's answer:
String span = "123:45";
Int32 colon = span.IndexOf(':');
TimeSpan timeSpan = new TimeSpan(Int32.Parse(span.Substring(0, colon - 1)),
Int32.Parse(span.Substring(colon + 1)), 0);
Obviously it assumes the original string is well-formed (composed of two parts separated by colon and parsable to an integer number).
I'm using a simple method that I devised a long time ago and just posted today to my blog:
public static class TimeSpanExtensions
{
static int[] weights = { 60 * 60 * 1000, 60 * 1000, 1000, 1 };
public static TimeSpan ToTimeSpan(this string s)
{
string[] parts = s.Split('.', ':');
long ms = 0;
for (int i = 0; i < parts.Length && i < weights.Length; i++)
ms += Convert.ToInt64(parts[i]) * weights[i];
return TimeSpan.FromMilliseconds(ms);
}
}
This can handle a lot more situations than the simpler solutions provided before, but has its own shortcomings. I discuss it further here.
Now, if you're in .NET 4 you can shorten the ToTimeSpan implementation to:
public static TimeSpan ToTimeSpan(this string s)
{
return TimeSpan.FromMilliseconds(s.Split('.', ':')
.Zip(weights, (d, w) => Convert.ToInt64(d) * w).Sum());
}
You can even make it an one-liner if you don't mind using horizontal screen state...
Similar to Lukes answer, with a lot more code and room for improvement. BUT it deals with negatives Hours ("-30:15") aswell, so maybe it can help someone.
public static double GetTotalHours(String s)
{
bool isNegative = false;
if (s.StartsWith("-"))
isNegative = true;
String[] splitted = s.Split(':');
int hours = GetNumbersAsInt(splitted[0]);
int minutes = GetNumbersAsInt(splitted[1]);
if (isNegative)
{
hours = hours * (-1);
minutes = minutes * (-1);
}
TimeSpan t = new TimeSpan(hours, minutes, 0);
return t.TotalHours;
}
public static int GetNumbersAsInt(String input)
{
String output = String.Empty;
Char[] chars = input.ToCharArray(0, input.Length);
for (int i = 0; i < chars.Length; i++)
{
if (Char.IsNumber(chars[i]) == true)
output = output + chars[i];
}
return int.Parse(output);
}
usage
double result = GetTotalHours("30:15");
double result2 = GetTotalHours("-30:15");
Normally one would use TimeSpan.ParseExact where a specific format is required. But the only hours formats that can be specified are as parts of days (see Custom TimeSpan Format Strings).
Therefore you will need to do the work yourself:
string input = "30:24";
var parts = input.Split(':');
var hours = Int32.Parse(parts[0]);
var minutes = Int32.Parse(parts[1]);
var result = new TimeSpan(hours, minutes, 0);
(But with some error checking.)
The three integer constructor of timespan allows hours >= 24 overflowing into the days count.
Based on Jan's Answer
.NET 5
/// <summary>
/// 1 number : hours "0" to "0:0:0" , "-1" to "-01:00:00"
/// 2 numbers : hours, minutes "1:2" to "01:02:00"
/// 3 numbers : hours, minutes, seconds "1:2:3" to "01:02:03"
/// 4 numbers : days, hours, minutes, seconds "1:2:3:4" to "1.02:03:04"
/// Any char can be used as separator. "1,2 3aaaa4" to "1.02:03:04"
/// </summary>
/// <param name="timeSpanString"></param>
/// <param name="ts"></param>
/// <returns>true : conversion succeeded</returns>
public static bool GetTimeSpan(string timeSpanString, ref TimeSpan ts)
{
bool isNegative = timeSpanString.StartsWith("-"); // "-1:2:3" is true
var digitsString = Regex.Replace(timeSpanString, "[^0-9]", " "); // "-1:2:3" to " 1 2 3"
var s = digitsString.Split(' ', StringSplitOptions.RemoveEmptyEntries); // "1","2","3"
int days = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
switch (s.Length)
{
case 1:
hours = int.Parse(s[0]);
break;
case 2:
hours = int.Parse(s[0]);
minutes = int.Parse(s[1]);
break;
case 3:
hours = int.Parse(s[0]);
minutes = int.Parse(s[1]);
seconds = int.Parse(s[2]);
break;
case 4:
days = int.Parse(s[0]);
hours = int.Parse(s[1]);
minutes = int.Parse(s[2]);
seconds = int.Parse(s[3]);
break;
default:
return false; //no digits or length > 4
}
if (isNegative)
{
ts = new TimeSpan(-days, -hours, -minutes, -seconds);
}
else
{
ts = new TimeSpan(days, hours, minutes, seconds);
}
return true;
}
TimeSpanHelper
Convert TimeSpan to over 24 hours number. TimeSpan Converter, Rule for TextBox.
here is my code
private void button2_Click(object sender, EventArgs e)
{
try
{
ans = double.Parse(txtb1.Text) - double.Parse(txtb2.Text);
string time = ans.ToString();
double seconds = TimeSpan.Parse(time); // Duration is not working
label1.Text = seconds.ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
i am trying to round up from after the point i.e if its greater than or equals to 60 it should add one to the integer and subtract it from the mantissa(decimal)
what i mean is that if i have a value of 1.70, i should have 2.10 i.e 2hrs 10min
If you want to manipulate the double value of 1.70 to Hours and minutes with your logic you should do the following.
var dbl = 1.70;
var hours = Math.Floor(dbl);
var minutes = (dbl - hours) * 100;
var ts = TimeSpan.FromHours(hours).Add(TimeSpan.FromMinutes(minutes));
Console.WriteLine("{0}h {1}min", Math.Floor(ts.TotalHours), ts.Minutes);
If your value is actually "{Hours}.{Minutes}" and could have "100.500" for 100hours 500minutes then you would need to change how you parse the value to get hours and minutes.
You might be looking for Math.Ceiling(ans).
It will always round up, even if the decimal value is below 0.5
If you want to correct a time string from the format that you posted I would suggest to use this method:
public static double correctTime(string commaTime)
{
double d = Convert.ToDouble(commaTime, CultureInfo.InvariantCulture);
int basis = (int)d;
// if the number after the comma is larger than 0.6 then just add 0.4
return d - basis > 0.6 ? d = d + 0.4 : d;
}
As for the conversion into a TimeSpan you need to get your number into the right format:
string s = "1.7";
double cor_s = correctTime(s);
string time = cor_s.ToString("00.00").Replace('.', ':'); // or
now you can parse it into a TimeSpan:
TimeSpan t = TimeSpan.Parse(time);
or if you want only the seconds:
double total_seconds = TimeSpan.Parse(time).TotalSeconds;
I hope I understood your problem correctly
const double PERCENT = 0.25;
DateTime t1 = Convert.ToDateTime(txtB_StartT.Text);
DateTime t2 = Convert.ToDateTime(txtB_EndT.Text);
TimeSpan ts = t1.Subtract(t2);
I cant seem to get this to parse into a DateTime
double tsMin = Convert.ToDouble(ts);
double tsMinTot = ts.TotalMinutes;
short tsMinPercent = (short)(((double)tsMinTot) * PERCENT);
double tsAndPercentTot = tsMinPercent + tsMinTot;
My goal here was to find a timediff, find what 25% of that timediff is and add it to the timediff.
DateTime newTimeMinTot = Convert.ToDateTime(tsAndPercentTot);
int hours = newTimeMinTot.Hour;
int minutes = newTimeMinTot.Minute;
An attempt to get a calculated new Datetime
string newTimeStrg = string.Format("{0:d1}:{1:d2}", hours, minutes);
txtB_NewDelivT.Text = newTimeStrg;
Attempt to output new DateTime to TextBox.
Someone please explain. How can I make the user input in military time and make this work.
Do it like this:
const double PERCENT = 0.25;
DateTime t1 = Convert.ToDateTime(txtB_StartT.Text);
DateTime t2 = Convert.ToDateTime(txtB_EndT.Text);
TimeSpan ts = t1.Subtract(t2);
long tsMinPercent = ts.Ticks + (long)(ts.Ticks * PERCENT);
var tsAndPercentTot = TimeSpan.FromTicks(tsMinPercent);
string newTimeStrg = string.Format("{0:d1}:{1:d2}", tsAndPercentTot.Hours, tsAndPercentTot.Minutes);
txtB_NewDelivT.Text = newTimeStrg;
Here I am using DateTime.Ticks to calculate percentage of time of difference and TimeSpan.FromTicks to find DateTime again from calculated percentage DateTime.
Instead using TextBox you can use TimePicker.
to force your date/datetime format
DateTime mydate = DateTime.ParseExact(TextBox1.Text.Trim(), "dd/MM/yyyy", null);
Based on your comment where you write that the input values are "0945" and "1445", I suggest you to replace your TextBox controls with DateTimePicker controls.
Just to have them display values as you are doing right now, you'll have to set some properties as I show you here.
picker.Format = DateTimePickerFormat.Custom;
picker.CustomFormat = "HHmm";
picker.ShowUpDown = true;
later, the picker.Value will return a whole date with time, where minutes and seconds will resemble the input values.
You can obvously set the properties' values from the designer.
Regards,
Daniele.
Since I don't have your form, I'll leave out the UI interaction. Here's how you can parse an input stream. I've show how to parse a hh:mm format, as well as a hhmm format:
var start = TimeSpan.ParseExact("10:00", "hh\\:mm", CultureInfo.InvariantCulture);
var finish = TimeSpan.ParseExact("1100", "hhmm", CultureInfo.InvariantCulture);
Once you have the start and finish, all we have to do is the math. We'll create a new TimeSpan from the ticks (the smallest unit of measurement on a TimeSpan) multiplied by our percentage (0.25). Then we just add the adjustment to our start time and we're done! You can then assign that into where ever you need the output.
var diff = finish - start;
var adjustment = TimeSpan.FromTicks((long)(diff.Ticks * 0.25));
var adjustedStart = start + adjustment;
You can run the code out at dotNetFiddle. I've included output there so you can see the intermediate results along the way.
Ok well i took a different approach and it worked out fairly easy.
I'm not sure if I'm allowed to answer my own question but i figure it
will help someone with the same issue i had.
// Set Constant values.
const double PERCENT = .25;
const int HUN_PART = 100, SIXTY = 60, one = 1;
// Parse start time textbox value as int
// Calculate start time hours and minutes
int sT = int.Parse(textBox1.Text);
int sH = sT / HUN_PART;
int sM = sT % HUN_PART;
// Calculate total start time in minutes
int sH_M = sH * SIXTY;
int sTotM = sH_M + sM;
// Parse end time textbox value as int
// Calculate end time hours and minutes
int eT = int.Parse(textBox2.Text);
int eH = eT / HUN_PART;
int eM = eT % HUN_PART;
// Calculate total end time in minutes
int eH_M = eH * SIXTY;
int eTotM = eH_M + eM;
// Calculate time difference in minutea
// Calculate percent of time difference
double dT_M = Convert.ToInt32(eTotM - sTotM);
int perc = Convert.ToInt32(dT_M * PERCENT);
// Calculate new arrival time in total min then in hours
double newD_M = perc + eTotM;
double newD_H = newD_M / SIXTY;
// Calculate new arrivaltime in remaining minutes
double nD_H_Convert = Math.Truncate(newD_H);
int nD_H = Convert.ToInt32(nD_H_Convert);
int nD_Hours = nD_H * HUN_PART;
double nD_Min = nD_H * SIXTY;
int nD_M = Convert.ToInt32(newD_M - nD_Min);
int newDeliveryTime = (nD_H * HUN_PART) + nD_M;
// Put values for new arive time hours and minutes in appropriate string format
string newTime = string.Format("{0:d4}", newDeliveryTime);
// Output arrival time string in textbox
textBox3.Text = newTime;
I was apparently trying to do more than was actually required, so by using a few simple calculations the issue was resolved.
Thank you for the help everyone.
I have two properties of time stamp without AM/PM. What's needed is to find the total time spent in quarter unit determined by _factor. Then there is a rounddown & roundup concept which is determined by _roundDown value as cut off point. Finally, returning a decimal value back after the calculation.
This resides in a class definition that sets up a property TotalTime. Because of this reason, I would like the code to be efficient. Excuse my code as this is the last piece of the project and want to get it done.
How can I improve the code: I am using mod calculation.
private decimal ComputeTotalTime(int _increment)
{
decimal _TotalHours = 0;
int _roundDown = 7, _factor = 15;
int int_TotalHours = 0;
if (String.IsNullOrEmpty(StartTime) || String.IsNullOrEmpty(EndTime)) return _TotalHours;
DateTime timeFromInput = DateTime.ParseExact(StartTime, "H:m", null);
DateTime timeToInput = DateTime.ParseExact(EndTime, "H:m", null);
//Here found a problem that we need to ensure that EndTime is greater than StartTime
//In one run, StartTime is 10:30 and EndTime is 2:32
//but the DateTime variables took is as 10:30 PM and 2:32 PM hence producing negative difference
TimeSpan ts = timeToInput.Subtract(timeFromInput)
int_TotalHours = ts.Hours * 60 + ts.Minutes;
if (int_TotalHours % _factor == 0) { /*I'm Perfect, no need to round*/ }
else if (int_TotalHours % _factor <= _roundDown) {
//Round down to nearest 15th, quarter
int_TotalHours = int_TotalHours - (int_TotalHours % _factor); }
else { //Round up to nearest quarter
int_TotalHours = int_TotalHours + (_factor - int_TotalHours % _factor); }
_TotalHours = Convert.ToDecimal(int_TotalHours / 60.00);
_TotalHours = (_TotalHours * 100) / 100;
return _TotalHours;
}
Thank you for your help.
How to parse string like 30:15 to TimeSpan in C#? 30:15 means 30 hours and 15 minutes.
string span = "30:15";
TimeSpan ts = TimeSpan.FromHours(
Convert.ToDouble(span.Split(':')[0])).
Add(TimeSpan.FromMinutes(
Convert.ToDouble((span.Split(':')[1]))));
This does not seem too elegant.
If you're certain that the format will always be "HH:mm" then try something like this:
string span = "35:15";
TimeSpan ts = new TimeSpan(int.Parse(span.Split(':')[0]), // hours
int.Parse(span.Split(':')[1]), // minutes
0); // seconds
Similar to Luke's answer:
String span = "123:45";
Int32 colon = span.IndexOf(':');
TimeSpan timeSpan = new TimeSpan(Int32.Parse(span.Substring(0, colon - 1)),
Int32.Parse(span.Substring(colon + 1)), 0);
Obviously it assumes the original string is well-formed (composed of two parts separated by colon and parsable to an integer number).
I'm using a simple method that I devised a long time ago and just posted today to my blog:
public static class TimeSpanExtensions
{
static int[] weights = { 60 * 60 * 1000, 60 * 1000, 1000, 1 };
public static TimeSpan ToTimeSpan(this string s)
{
string[] parts = s.Split('.', ':');
long ms = 0;
for (int i = 0; i < parts.Length && i < weights.Length; i++)
ms += Convert.ToInt64(parts[i]) * weights[i];
return TimeSpan.FromMilliseconds(ms);
}
}
This can handle a lot more situations than the simpler solutions provided before, but has its own shortcomings. I discuss it further here.
Now, if you're in .NET 4 you can shorten the ToTimeSpan implementation to:
public static TimeSpan ToTimeSpan(this string s)
{
return TimeSpan.FromMilliseconds(s.Split('.', ':')
.Zip(weights, (d, w) => Convert.ToInt64(d) * w).Sum());
}
You can even make it an one-liner if you don't mind using horizontal screen state...
Similar to Lukes answer, with a lot more code and room for improvement. BUT it deals with negatives Hours ("-30:15") aswell, so maybe it can help someone.
public static double GetTotalHours(String s)
{
bool isNegative = false;
if (s.StartsWith("-"))
isNegative = true;
String[] splitted = s.Split(':');
int hours = GetNumbersAsInt(splitted[0]);
int minutes = GetNumbersAsInt(splitted[1]);
if (isNegative)
{
hours = hours * (-1);
minutes = minutes * (-1);
}
TimeSpan t = new TimeSpan(hours, minutes, 0);
return t.TotalHours;
}
public static int GetNumbersAsInt(String input)
{
String output = String.Empty;
Char[] chars = input.ToCharArray(0, input.Length);
for (int i = 0; i < chars.Length; i++)
{
if (Char.IsNumber(chars[i]) == true)
output = output + chars[i];
}
return int.Parse(output);
}
usage
double result = GetTotalHours("30:15");
double result2 = GetTotalHours("-30:15");
Normally one would use TimeSpan.ParseExact where a specific format is required. But the only hours formats that can be specified are as parts of days (see Custom TimeSpan Format Strings).
Therefore you will need to do the work yourself:
string input = "30:24";
var parts = input.Split(':');
var hours = Int32.Parse(parts[0]);
var minutes = Int32.Parse(parts[1]);
var result = new TimeSpan(hours, minutes, 0);
(But with some error checking.)
The three integer constructor of timespan allows hours >= 24 overflowing into the days count.
Based on Jan's Answer
.NET 5
/// <summary>
/// 1 number : hours "0" to "0:0:0" , "-1" to "-01:00:00"
/// 2 numbers : hours, minutes "1:2" to "01:02:00"
/// 3 numbers : hours, minutes, seconds "1:2:3" to "01:02:03"
/// 4 numbers : days, hours, minutes, seconds "1:2:3:4" to "1.02:03:04"
/// Any char can be used as separator. "1,2 3aaaa4" to "1.02:03:04"
/// </summary>
/// <param name="timeSpanString"></param>
/// <param name="ts"></param>
/// <returns>true : conversion succeeded</returns>
public static bool GetTimeSpan(string timeSpanString, ref TimeSpan ts)
{
bool isNegative = timeSpanString.StartsWith("-"); // "-1:2:3" is true
var digitsString = Regex.Replace(timeSpanString, "[^0-9]", " "); // "-1:2:3" to " 1 2 3"
var s = digitsString.Split(' ', StringSplitOptions.RemoveEmptyEntries); // "1","2","3"
int days = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
switch (s.Length)
{
case 1:
hours = int.Parse(s[0]);
break;
case 2:
hours = int.Parse(s[0]);
minutes = int.Parse(s[1]);
break;
case 3:
hours = int.Parse(s[0]);
minutes = int.Parse(s[1]);
seconds = int.Parse(s[2]);
break;
case 4:
days = int.Parse(s[0]);
hours = int.Parse(s[1]);
minutes = int.Parse(s[2]);
seconds = int.Parse(s[3]);
break;
default:
return false; //no digits or length > 4
}
if (isNegative)
{
ts = new TimeSpan(-days, -hours, -minutes, -seconds);
}
else
{
ts = new TimeSpan(days, hours, minutes, seconds);
}
return true;
}
TimeSpanHelper
Convert TimeSpan to over 24 hours number. TimeSpan Converter, Rule for TextBox.