TimeSpan FromMilliseconds странная реализация? - PullRequest
27 голосов
/ 27 марта 2011

Недавно я столкнулся с некоторым странным поведением в реализации .net timespan.

        TimeSpan test = TimeSpan.FromMilliseconds(0.5);
        double ms = test.TotalMilliseconds; // Returns 0

Параметр FromMilliseconds принимает удвоение в качестве параметра. Однако, кажется, что значение округлено внутри.

Если я создаю новый временной интервал с 5000 тиков (0,5 мс), значение TotalMilliseconds будет правильным.

Глядя на реализацию TimeSpan в отражателе, вы обнаруживаете, что входные данные фактически преобразуются в длинные.

Почему Microsoft разработала метод FromMilliseconds для получения двойного параметра вместо длинного (поскольку в данной реализации двойное значение бесполезно)?

Ответы [ 5 ]

24 голосов
/ 27 марта 2011

Первое соображение вызывает удивление, почему они выбрали double в качестве возвращаемого значения. Использование long было бы очевидным выбором. Несмотря на то, что уже есть очень хорошее свойство, которое является длинным, Ticks недвусмысленны с единицей измерения в 100 наносекунд. Но они выбрали двойной, вероятно, с намерением вернуть дробное значение.

Однако это создало новую проблему, которая, возможно, была обнаружена позже. Двойник может хранить только 15 значащих цифр. TimeSpan может хранить 10000 лет. очень желательно преобразовать из TimeSpan в миллисекунды, затем обратно в TimeSpan и получить то же значение.

Это невозможно с двойным. Делаем математику: 10000 лет - это примерно 10000 x 365,4 x 24 x 3600 x 1000 = 315 705 600 000 000 миллисекунд. Отсчитайте 15 цифр, лучше всего это может сделать двойное число, и вы получите ровно одну миллисекунду как наименьшую единицу, которую можно сохранить без ошибки округления. Любые дополнительные цифры будут случайным шумом.

Застряв между молотом и наковальней, разработчикам (тестерам?) Пришлось выбирать между округлением значения при преобразовании из TimeSpan в миллисекунды. Или сделать это позже при переходе от миллисекунд к TimeSpan. Они решили сделать это рано, смелое решение.

Решите вашу проблему, используя свойство Ticks и умножив на 1E-4, чтобы получить миллисекунды.

3 голосов
/ 27 марта 2011

Это по замыслу, очевидно. документация говорит столько же:

Значение параметра преобразуется в тики, и это количество тиков используется для инициализации нового TimeSpan. Следовательно, значение будет только считается точным до ближайшего миллисекунды.

2 голосов
/ 27 марта 2011

Принятие двойного логического плана.У вас могут быть доли миллисекунд.

Внутри происходит дизайн реализации.Даже если все текущие реализации (из CLI) округляют это сначала, это не должно иметь место в будущем.

1 голос
/ 08 августа 2014

Проблема с вашим кодом на самом деле в первой строке, где вы звоните FromMilliseconds.Как отмечалось ранее, примечания в документации утверждают следующее:

Параметр value преобразуется в тики, и это количество тиков используется для инициализации нового TimeSpan.Следовательно, значение будет считаться точным только с точностью до миллисекунды.

В действительности это утверждение не является ни правильным, ни логически обоснованным.В обратном порядке:

  • Тики определены как «сто наносекунд».По этому определению документация должна быть записана как:

    Следовательно, значение будет считаться точным только с точностью до ближайшего миллисекунды тика,или одна десятая миллионная доли секунды .

  • Из-за ошибки или недосмотра параметр value не преобразуется непосредственно в тики доинициализации нового экземпляра TimeSpan.Это можно увидеть в эталонном источнике для TimeSpan , где значение millis округляется до до его преобразования в тики, а не после.Если бы сохранялась максимальная точность, эта строка кода должна была бы выглядеть следующим образом (и корректировка на 0,5 миллисекунды на 3 строки раньше была бы удалена):

    return new TimeSpan((long)(millis * TicksPerMillisecond));
    

Резюме:

Документация для различных TimeSpan.From*, за исключением FromTicks, должна быть обновлена, чтобы указать, что аргумент округляется до ближайшей миллисекунды (без учета ссылки на тики).

0 голосов

Или вы можете сделать:

double x = 0.4;

TimeSpan t = TimeSpan.FromTicks((long)(TimeSpan.TicksPerMillisecond * x)); // where x can be a double
double ms = t.TotalMilliseconds; //return 0.4

- сарказм

TimeSpan преобразует двойные миллисекунды в тики, чтобы " ЯВНО " вы могли иметь TimeSpanс гранулярностью менее 1 мс.

- / sarcasm

- это совершенно не очевидно ... почему это не делается в методе .FromMilliseconds, вне моего понимания.

...