Someone stole my minute: /

I am trying to convert the time represented in double to something like 23.40 , which means 23 hours 40 minutes using the following method:

 private TimeSpan DoubleToTimeSpan(double time) { double hour = Math.Floor(time); double minute = (time - hour) * 100d; TimeSpan ts = new TimeSpan((int)hour, (int)minute, 0); return ts; } 

When testing several times, for example 23.40 :

 Console.WriteLine(DoubleToTimeSpan(23.40)); 

It shows 23:39:00 , the whole minute was stolen by the system! Where is my minute?

Note : I know about TimeSpan.FromHours , this does not help me because this method counts minutes as a percentage, so 23.40 is 23 hours and 40% of the hour, which is 23:24:00 .

+4
source share
7 answers

Since 0.4 cannot be represented exactly in Double floating point format, you will get its closest representation, which in the case of (23.4-23)*100 , probably looks like 39.999999999999858 . When you use (int) , you crop the fraction, leaving you 39.

You need to round, not trim, so use (int)Math.Round(minute) .

Alternatively, you can use the Decimal type, which can accurately represent decimal numbers, such as 23.40 .

+9
source

Try to round it instead of int

 private TimeSpan DoubleToTimeSpan(double time) { double hour = Math.Floor(time); hour.Dump(); double minute = (time - hour) * 100d; minute.Dump(); TimeSpan ts = new TimeSpan((int)hour, (int)Math.Round(minute), 0); return ts; } 

If you execute only (int) a minute, it will take the whole part of your double.

+2
source

When you drop from double to int , it truncates your value in a minute - thus your lost minute.

0
source
 (time - hour) * 100d 

Will be evaluated to 39.999999999999998 and therefore 39 when cast in int.

0
source

You used Math.Floor for an hour, so use Math.Ceiling for a minute. It seems to be working fine.

 private static TimeSpan DoubleToTimeSpan(double time) { return new TimeSpan((int)Math.Floor(time), (int)Math.Ceiling((time - Math.Floor(time)) * 100d), 0); } 
0
source

Another option is to use decimal places. This will prevent loss of accuracy.

 decimal minute = ((decimal)time)-((decimal)hour)*100; 
0
source

Not sure if this is the best solution, but if you are using .NET 4.0 or later, you can also go through string . It seems that "23.40" is a sequence of characters with one interpretation as double and the other as TimeSpan .

If you like this idea, use:

 TimeSpan DoubleToTimeSpan(double time) { string str = time.ToString("F2", CultureInfo.InvariantCulture); TimeSpan ts = TimeSpan.ParseExact(str, "h'.'mm", CultureInfo.InvariantCulture); return ts; } 

Perhaps not as fast as the multiply-by-100-and-round method, although I have not tested this.

0
source

Source: https://habr.com/ru/post/1494960/


All Articles