Calculating days from TimeSpan hours
Asked Answered
M

6

2

I have 1 single text box which a user will enter the number of hours. At present, if they enter 26 hours, we get an error because of the TimeSpan's HH limit. This value is going to get stored in a SQL Server 2008 Time(7) field.

How can I get it to recognize more than 23 hours? It is not an option to store it as a decimal because another section of the program requires this field to be a time(7) field.

 TimeSpan estiamtedHours;

 private void btnSave_Click(object sender, EventArgs e)
 {
     estimatedHours = TimeSpan.Parse(tbEstHours.Text);
 }

The time(7) field also has the limit of 24 hours, what would be the best way round this as Time(7) is required for a Stopwatch on another form.

Thanks

Mingle answered 20/8, 2013 at 10:2 Comment(1)
Well is 26 a valid value ? you should parse it as int and then check if it is more than 23 or not. Guess the value won't save in the database too if its more than 24 hrsDrandell
J
1

Be careful. TimeSpan is meant to measure an elapsed duration of time, while time in SQL Server is specifically a time-of-day. These are two different concepts.

Sometimes these get mixed up. For example, DateTime.TimeOfDay is a TimeSpan type - which goes against its design. It's a reasonable compromise since there is no Time type in .Net and it can fit.

But a TimeSpan that is 24 hours or greater will not fit into a SQL Server time field.

Also, a TimeSpan is based on standard days. You can create one with TimeSpan.FromHours(26) and it will represent "1 day and 2 hours". If you call TimeSpan.FromHours(26).ToString() it will be "1.02:00:00".

If you're storing an elapsed duration of time (not a time of day), then use a TimeSpan in .Net, but use an integer type in SQL Server. Decide what units you want precision for, and that will help you choose a data type.

For example, you can store the full precision of TimeSpan.Ticks using a SQL Server bigint type. But probably you will store TimeSpan.TotalSeconds using an int. When loading, you can use TimeSpan.FromSeconds to get back to a TimeSpan type.

Also be aware that a TimeSpan can be negative, which represents moving backwards in time.

By the way, if you used the Noda Time library - these concepts would be separated for you in types called Duration and LocalTime.

If what you were after is a way to parse a string like "26:00:00" you can't do that with a TimeSpan. But you can use Noda Time:

// starting from this string
string s = "26:00:00";

// Parse as a Duration using the Noda Time Pattern API
DurationPattern pattern = DurationPattern.CreateWithInvariantCulture("H:mm:ss");
Duration d = pattern.Parse(s).Value;
Debug.WriteLine(pattern.Format(d));  // 26:00:00

// if you want a TimeSpan, you can still get one.
TimeSpan ts = d.ToTimeSpan();
Debug.WriteLine(ts);  // 1.02:00:00
Judgment answered 20/8, 2013 at 21:45 Comment(0)
L
4

If you know the input value is an hour value as a floating point number, you can use TimeSpan.FromHours():

TimeSpan estiamtedHours;

private void btnSave_Click(object sender, EventArgs e)
{
  estimatedHours = TimeSpan.FromHours(Double.Parse(tbEstHours.Text));
}
Lindley answered 20/8, 2013 at 10:6 Comment(3)
you gotta convert the string to int / doubleDorathydorca
this will throw exceptionPage
Ops, Updated with the parse. This of course still needs validation and error handling, but so did the original (Handling invalid/negative/etc.)Lindley
E
3

Parse the text into an int and pass that int as the hours parameter in the TimeSpan constructor.

int hours;
if (Int32.TryParse(tbEstHours.Text, out hours))
{
    TimeSpan ts = new TimeSpan(hours, 0, 0);
}

You can also do the same with minutes and seconds. Alternatively, if you just want hours, you can use TimeSpan.FromHours in the same manner instead of the TimeSpan constructor.

Euthenics answered 20/8, 2013 at 10:5 Comment(5)
I would use this as it protects against user typing errors in the middle of your program. i.e. 2a6 if you just parse this it will exception. but use Double.TryParse for better precision.Swayne
Even if this works, i guess the time field expects a duration and would fail for more than 24 hr ones. Please correct me if i am wrongDrandell
@Drandell - I might be misunderstanding you but it should return 26 hours if you use the TotalHours property (as opposed to Hours, which would return 2 as it loops round).Euthenics
@Euthenics No, actually my point was that even if its a valid timespan it won't be inserted into the database as it is a time field, creation or parse of timespan is not the actual issue but how to limit it to the 24 hr cycleDrandell
@Drandell - Ah, I see what you mean. In that case, there doesn't appear to be a an SQL equivalent. It would have to be stored in another format or in a different field as mentioned here #8503632Euthenics
Y
1

After parsing the input, use the FromHours method:

double hours
if (double.TryParse(tbEstHours.Text, out hours)
{
    TimeSpan time = TimeSpan.FromHours(hours);
}
Yuletide answered 20/8, 2013 at 10:7 Comment(1)
@DarrenDavies Haha aye. Looks like you never left mate ;)Yuletide
B
1

The TimeSpan.Parse Method expects the input in the format

[ws][-]{ d | [d.]hh:mm[:ss[.ff]] }[ws]

where hh is the hour part, ranging from 0 to 23.

For example,

  • TimeSpan.Parse("5") returns 5 days,
  • TimeSpan.Parse("5:14") returns 5 hours and 14 minutes.

If you just want your users to enter a number of hours, you can simply parse the input as an integer and construct a TimeSpan from that:

TimeSpan result = TimeSpan.FromHours(int.Parse("26"));
// result == {1.02:00:00}

(Use int.TryParse for user input.)

If you want your users to enter both hours and minutes (such as 26:14), then you need to implement some parsing method yourself.

Brutify answered 20/8, 2013 at 10:7 Comment(0)
D
1

Since the other answers don't address this

The concern here is the time column in the database and it expects a valid duration which would be limited to the 24 hr time where as TimeSpan can have them beyond the 24 hr limit.

So you should ideally parse the value as int (use int.Parse or int.TryParse) and then check if it is less than 24 and then create the appropriate TimeSpan

Drandell answered 20/8, 2013 at 10:28 Comment(1)
Yes, this is a concern I had not considered. int.Parse will not work if say 3.30 is entered. The Time(7) is required as another form uses a stopwatch to count down this value.Mingle
J
1

Be careful. TimeSpan is meant to measure an elapsed duration of time, while time in SQL Server is specifically a time-of-day. These are two different concepts.

Sometimes these get mixed up. For example, DateTime.TimeOfDay is a TimeSpan type - which goes against its design. It's a reasonable compromise since there is no Time type in .Net and it can fit.

But a TimeSpan that is 24 hours or greater will not fit into a SQL Server time field.

Also, a TimeSpan is based on standard days. You can create one with TimeSpan.FromHours(26) and it will represent "1 day and 2 hours". If you call TimeSpan.FromHours(26).ToString() it will be "1.02:00:00".

If you're storing an elapsed duration of time (not a time of day), then use a TimeSpan in .Net, but use an integer type in SQL Server. Decide what units you want precision for, and that will help you choose a data type.

For example, you can store the full precision of TimeSpan.Ticks using a SQL Server bigint type. But probably you will store TimeSpan.TotalSeconds using an int. When loading, you can use TimeSpan.FromSeconds to get back to a TimeSpan type.

Also be aware that a TimeSpan can be negative, which represents moving backwards in time.

By the way, if you used the Noda Time library - these concepts would be separated for you in types called Duration and LocalTime.

If what you were after is a way to parse a string like "26:00:00" you can't do that with a TimeSpan. But you can use Noda Time:

// starting from this string
string s = "26:00:00";

// Parse as a Duration using the Noda Time Pattern API
DurationPattern pattern = DurationPattern.CreateWithInvariantCulture("H:mm:ss");
Duration d = pattern.Parse(s).Value;
Debug.WriteLine(pattern.Format(d));  // 26:00:00

// if you want a TimeSpan, you can still get one.
TimeSpan ts = d.ToTimeSpan();
Debug.WriteLine(ts);  // 1.02:00:00
Judgment answered 20/8, 2013 at 21:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.