Можно ли объединить объект .NET TimeSpan
?
У меня есть значение TimeSpan
: 00: 00: 00.6193789
Есть ли простой способ сохранить объект TimeSpan
, но округлить его до чего-то вроде
00: 00: 00,62
Можно ли объединить объект .NET TimeSpan
?
У меня есть значение TimeSpan
: 00: 00: 00.6193789
Есть ли простой способ сохранить объект TimeSpan
, но округлить его до чего-то вроде
00: 00: 00,62
Извините, ребята, но оба вопрос и популярный ответ до сих пор ошибочны: -)
Вопрос неверен, потому что Tyndall запрашивает способ round, но показывает пример усечения.
Не ответит ли Дин, потому что он также относится к усечению, а не к округлению. (Я полагаю, можно было бы утверждать, что ответ подходит для одного из двух вопросов, но на мгновение оставим философию...)
Вот простой способ округления:
int precision = 2; // Specify how many digits past the decimal point
TimeSpan t1 = new TimeSpan(19365678); // sample input value
const int TIMESPAN_SIZE = 7; // it always has seven digits
// convert the digitsToShow into a rounding/truncating mask
int factor = (int)Math.Pow(10,(TIMESPAN_SIZE - precision));
Console.WriteLine("Input: " + t1);
TimeSpan truncatedTimeSpan = new TimeSpan(t1.Ticks - (t1.Ticks % factor));
Console.WriteLine("Truncated: " + truncatedTimeSpan);
TimeSpan roundedTimeSpan =
new TimeSpan(((long)Math.Round((1.0*t1.Ticks/factor))*factor));
Console.WriteLine("Rounded: " + roundedTimeSpan);
При входном значении и количестве цифр в примере кода это результат:
Input: 00:00:01.9365678
Truncated: 00:00:01.9300000
Rounded: 00:00:01.9400000
Измените точность от 2 цифр до 5 цифр и получите вместо этого:
Input: 00:00:01.9365678
Truncated: 00:00:01.9365600
Rounded: 00:00:01.9365700
И даже измените его на 0, чтобы получить этот результат:
Input: 00:00:01.9365678
Truncated: 00:00:01
Rounded: 00:00:02
Наконец, если вы хотите получить немного больше контроля над выходом, добавьте некоторое форматирование. Вот один пример, показывающий, что вы можете отделить точность от числа отображаемых цифр. Точность снова установлена на 2, но отображаются 3 цифры, как указано в последнем аргументе строки управления форматированием:
Console.WriteLine("Rounded/formatted: " +
string.Format("{0:00}:{1:00}:{2:00}.{3:000}",
roundedTimeSpan.Hours, roundedTimeSpan.Minutes,
roundedTimeSpan.Seconds, roundedTimeSpan.Milliseconds));
// Input: 00:00:01.9365678
// Truncated: 00:00:01.9300000
// Rounded: 00:00:01.9400000
// Rounded/formatted: 00:00:01.940
Этот материал полезен, если вы ищете идеи; С тех пор я успел реализовать пакетное решение для тех, кто ищет готовый к использованию код.
Обратите внимание, что это код без комментирования. Полностью прокомментированная версия с комментариями XML-doc будет доступна в моей
Этот код улучшает мой код, который, хотя он округлен, все еще показывает 7 мест, заполненных нулями. Эта завершенная версия обходит и обрезает указанное количество цифр.
Вот пример вызова:
Console.Write(new RoundedTimeSpan(19365678, 2).ToString());
// Result = 00:00:01.94
И вот полный файл RoundedTimeSpan.cs:
using System;
namespace CleanCode.Data
{
public struct RoundedTimeSpan
{
private const int TIMESPAN_SIZE = 7; // it always has seven digits
private TimeSpan roundedTimeSpan;
private int precision;
public RoundedTimeSpan(long ticks, int precision)
{
if (precision < 0) { throw new ArgumentException("precision must be non-negative"); }
this.precision = precision;
int factor = (int)System.Math.Pow(10, (TIMESPAN_SIZE - precision));
// This is only valid for rounding milliseconds-will *not* work on secs/mins/hrs!
roundedTimeSpan = new TimeSpan(((long)System.Math.Round((1.0 * ticks / factor)) * factor));
}
public TimeSpan TimeSpan { get { return roundedTimeSpan; } }
public override string ToString()
{
return ToString(precision);
}
public string ToString(int length)
{ // this method revised 2010.01.31
int digitsToStrip = TIMESPAN_SIZE - length;
string s = roundedTimeSpan.ToString();
if (!s.Contains(".") && length == 0) { return s; }
if (!s.Contains(".")) { s += "." + new string('0', TIMESPAN_SIZE); }
int subLength = s.Length - digitsToStrip;
return subLength < 0 ? "" : subLength > s.Length ? s : s.Substring(0, subLength);
}
}
}
Я только что выпустил новую версию моих open-source библиотек вчера, скорее, чем ожидалось, включая RoundedTimeSpan, описанную выше. Код здесь; для запуска API здесь, перейдите к RoundedTimeSpan
в пространстве имен CleanCode.Data
. Библиотека CleanCode.DLL включает в себя код, показанный выше, но предоставляет его в готовом пакете. Обратите внимание, что я немного улучшил метод ToString(int)
выше, так как я опубликовал его в 2010.01.06.
TimeSpan - это немного больше, чем обертка вокруг члена 'Ticks'. Очень легко создать новый TimeSpan из закругленной версии других TimeSpan Ticks.
TimeSpan t1 = new TimeSpan(2345678);
Console.WriteLine(t1);
TimeSpan t2 = new TimeSpan(t1.Ticks - (t1.Ticks % 100000));
Console.WriteLine(t2);
дает:
00:00:00.2345678
00:00:00.2300000
Если вы хотите TimeSpan, его простой однострочный:
public static TimeSpan RoundSeconds( TimeSpan span, int nDigits ) {
return TimeSpan.FromSeconds( Math.Round( span.TotalSeconds, nDigits ) );
}
Если вам нужна строка:
public static string RoundSecondsAsString( TimeSpan span, int nDigits ) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < nDigits; i++)
sb.Append( "f" );
return span.ToString( @"hh\:mm\:ss\." + sb );
}
Credits:
cc1960 answer показывает использование FromSeconds
, но округляется до целых секунд. Мой ответ обобщается на указанное количество цифр.
Ответ Ed предлагает использовать строку формата и включает ссылку на документ форматирования.
new TimeSpan(tmspan.Hours, tmspan.Minutes, tmspan.Seconds, (int)Math.Round(Convert.ToDouble(tmspan.Milliseconds / 10)));
Учитывая некоторые комментарии о округлении до секунд, я думал, что округление до любого TimeSpan было бы приятным:
public static TimeSpan Round(this TimeSpan ts, TimeSpan rnd) {
if (rnd == TimeSpan.Zero)
return ts;
var rndticks = rnd.Ticks;
var ansTicks = ts.Ticks + rndticks / 2;
ansTicks -= ansTicks % rndticks;
return TimeSpan.FromTicks(ansTicks);
}
public static TimeSpan Round(this TimeSpan ts) {
return ts.Round(TimeSpan.FromSeconds(1));
}
Не уверен в отношении TimeSpan, но вы можете проверить этот пост в DateTimes:
http://mikeinmadison.wordpress.com/2008/03/12/datetimeround/
Вот хороший метод расширения:
public static TimeSpan RoundToSeconds(this TimeSpan timespan, int seconds = 1)
{
long offset = (timespan.Ticks >= 0) ? TimeSpan.TicksPerSecond / 2 : TimeSpan.TicksPerSecond / -2;
return TimeSpan.FromTicks((timespan.Ticks + offset) / TimeSpan.TicksPerSecond * TimeSpan.TicksPerSecond);
}
И вот несколько примеров:
DateTime dt1 = DateTime.Now.RoundToSeconds(); // round to full seconds
DateTime dt2 = DateTime.Now.RoundToSeconds(5 * 60); // round to full 5 minutes
Еще один способ округления миллисекунд до ближайшей секунды.
private const long TicksPer1000Milliseconds = 1000 * TimeSpan.TicksPerMillisecond;
// Round milliseconds to nearest second
// To round up, add the sub-second ticks required to reach the next second
// To round down, subtract the sub-second ticks
elapsedTime = new TimeSpan(elapsedTime.Ticks + (elapsedTime.Milliseconds >= 500 ? TicksPer1000Milliseconds - (elapsedTime.Ticks % TicksPer1000Milliseconds) : -(elapsedTime.Ticks % TicksPer1000Milliseconds)));
Мое решение:
static TimeSpan RoundToSec(TimeSpan ts)
{
return TimeSpan.FromSeconds((int)(ts.TotalSeconds));
}
Вместо того, чтобы математически пытаться округлить значение, вы можете просто отображать только те компоненты TimeSpan
, которые вы хотите показать.
TimeSpan currentTimeLapsed = DateTime.Now.Subtract(startTime);
Console.WriteLine (currentTimeLapsed.Hours.ToString() + ":" + currentTimeLapsed.Minutes.ToString() + ":" + currentTimeLapsed.Seconds.ToString());