11 ответов:
DateTime RoundUp(DateTime dt, TimeSpan d) { return new DateTime((dt.Ticks + d.Ticks - 1) / d.Ticks * d.Ticks, dt.Kind); }пример:
var dt1 = RoundUp(DateTime.Parse("2011-08-11 16:59"), TimeSpan.FromMinutes(15)); // dt1 == {11/08/2011 17:00:00} var dt2 = RoundUp(DateTime.Parse("2011-08-11 17:00"), TimeSpan.FromMinutes(15)); // dt2 == {11/08/2011 17:00:00} var dt3 = RoundUp(DateTime.Parse("2011-08-11 17:01"), TimeSpan.FromMinutes(15)); // dt3 == {11/08/2011 17:15:00}
придумал решение, которое не включает умножение и деление
longцифры.public static DateTime RoundUp(this DateTime dt, TimeSpan d) { var modTicks = dt.Ticks % d.Ticks; var delta = modTicks != 0 ? d.Ticks - modTicks : 0; return new DateTime(dt.Ticks + delta, dt.Kind); } public static DateTime RoundDown(this DateTime dt, TimeSpan d) { var delta = dt.Ticks % d.Ticks; return new DateTime(dt.Ticks - delta, dt.Kind); } public static DateTime RoundToNearest(this DateTime dt, TimeSpan d) { var delta = dt.Ticks % d.Ticks; bool roundUp = delta > d.Ticks / 2; var offset = roundUp ? d.Ticks : 0; return new DateTime(dt.Ticks + offset - delta, dt.Kind); }использование:
var date = new DateTime(2010, 02, 05, 10, 35, 25, 450); // 2010/02/05 10:35:25 var roundedUp = date.RoundUp(TimeSpan.FromMinutes(15)); // 2010/02/05 10:45:00 var roundedDown = date.RoundDown(TimeSpan.FromMinutes(15)); // 2010/02/05 10:30:00 var roundedToNearest = date.RoundToNearest(TimeSpan.FromMinutes(15)); // 2010/02/05 10:30:00
Если вам нужно округлить до ближайшего интервала времени (не) тогда я предлагаю использовать следующее
static DateTime RoundToNearestInterval(DateTime dt, TimeSpan d) { int f=0; double m = (double)(dt.Ticks % d.Ticks) / d.Ticks; if (m >= 0.5) f=1; return new DateTime(((dt.Ticks/ d.Ticks)+f) * d.Ticks); }
void Main() { var date1 = new DateTime(2011, 8, 11, 16, 59, 00); date1.Round15().Dump(); var date2 = new DateTime(2011, 8, 11, 17, 00, 02); date2.Round15().Dump(); var date3 = new DateTime(2011, 8, 11, 17, 01, 23); date3.Round15().Dump(); var date4 = new DateTime(2011, 8, 11, 17, 00, 00); date4.Round15().Dump(); } public static class Extentions { public static DateTime Round15(this DateTime value) { var ticksIn15Mins = TimeSpan.FromMinutes(15).Ticks; return (value.Ticks % ticksIn15Mins == 0) ? value : new DateTime((value.Ticks / ticksIn15Mins + 1) * ticksIn15Mins); } }результаты:
8/11/2011 5:00:00 PM 8/11/2011 5:15:00 PM 8/11/2011 5:15:00 PM 8/11/2011 5:00:00 PM
поскольку я ненавижу изобретать колесо, я бы, вероятно, следовал этому алгоритму, чтобы округлить значение DateTime до заданного приращения времени (Timespan):
- преобразование
DateTimeзначение округляется до десятичного значения с плавающей запятой, представляющее целое и дробное числоTimeSpanединицы измерения.- округлите это до целого числа, используя
Math.Round().- масштабирование до тиков путем умножения округленного целого числа на количество тиков в
TimeSpanблок.- создать новый
DateTimeзначение из округленного числа ТИКов и возвращает его вызывающему абоненту.вот код:
public static class DateTimeExtensions { public static DateTime Round( this DateTime value , TimeSpan unit ) { return Round( value , unit , default(MidpointRounding) ) ; } public static DateTime Round( this DateTime value , TimeSpan unit , MidpointRounding style ) { if ( unit <= TimeSpan.Zero ) throw new ArgumentOutOfRangeException("unit" , "value must be positive") ; Decimal units = (decimal) value.Ticks / (decimal) unit.Ticks ; Decimal roundedUnits = Math.Round( units , style ) ; long roundedTicks = (long) roundedUnits * unit.Ticks ; DateTime instance = new DateTime( roundedTicks ) ; return instance ; } }
Внимание: приведенная выше формула неверна, т. е. следующее:
DateTime RoundUp(DateTime dt, TimeSpan d) { return new DateTime(((dt.Ticks + d.Ticks - 1) / d.Ticks) * d.Ticks); }следует переписать как:
DateTime RoundUp(DateTime dt, TimeSpan d) { return new DateTime(((dt.Ticks + d.Ticks/2) / d.Ticks) * d.Ticks); }
более подробное решение, которое использует модуль и позволяет избежать ненужных вычислений.
public static class DateTimeExtensions { public static DateTime RoundUp(this DateTime dt, TimeSpan ts) { return Round(dt, ts, true); } public static DateTime RoundDown(this DateTime dt, TimeSpan ts) { return Round(dt, ts, false); } private static DateTime Round(DateTime dt, TimeSpan ts, bool up) { var remainder = dt.Ticks % ts.Ticks; if (remainder == 0) { return dt; } long delta; if (up) { delta = ts.Ticks - remainder; } else { delta = -remainder; } return dt.AddTicks(delta); } }
моя версия
DateTime newDateTimeObject = oldDateTimeObject.AddMinutes(15 - oldDateTimeObject.Minute % 15);как метод он будет блокировать, как это
public static DateTime GetNextQuarterHour(DateTime oldDateTimeObject) { return oldDateTimeObject.AddMinutes(15 - oldDateTimeObject.Minute % 15); }и это называется
DateTime thisIsNow = DateTime.Now; DateTime nextQuarterHour = GetNextQuarterHour(thisIsNow);
Это простое решение для округления до ближайшей 1 минуты. Он сохраняет информацию о часовом поясе и виде DateTime. Он может быть изменен в соответствии с вашими потребностями в дальнейшем (если вам нужно округлить до ближайших 5 минут и т. д.).
DateTime dbNowExact = DateTime.Now; DateTime dbNowRound1 = (dbNowExact.Millisecond == 0 ? dbNowExact : dbNowExact.AddMilliseconds(1000 - dbNowExact.Millisecond)); DateTime dbNowRound2 = (dbNowRound1.Second == 0 ? dbNowRound1 : dbNowRound1.AddSeconds(60 - dbNowRound1.Second)); DateTime dbNow = dbNowRound2;
вы можете использовать этот метод, он использует указанную дату, чтобы гарантировать, что он поддерживает любой тип глобализации и datetime, ранее указанный в объекте datetime.
const long LNG_OneMinuteInTicks = 600000000; /// <summary> /// Round the datetime to the nearest minute /// </summary> /// <param name = "dateTime"></param> /// <param name = "numberMinutes">The number minute use to round the time to</param> /// <returns></returns> public static DateTime Round(DateTime dateTime, int numberMinutes = 1) { long roundedMinutesInTicks = LNG_OneMinuteInTicks * numberMinutes; long remainderTicks = dateTime.Ticks % roundedMinutesInTicks; if (remainderTicks < roundedMinutesInTicks / 2) { // round down return dateTime.AddTicks(-remainderTicks); } // round up return dateTime.AddTicks(roundedMinutesInTicks - remainderTicks); }Если вы хотите использовать временной интервал для округления, вы можете использовать это.
/// <summary> /// Round the datetime /// </summary> /// <example>Round(dt, TimeSpan.FromMinutes(5)); => round the time to the nearest 5 minutes.</example> /// <param name = "dateTime"></param> /// <param name = "roundBy">The time use to round the time to</param> /// <returns></returns> public static DateTime Round(DateTime dateTime, TimeSpan roundBy) { long remainderTicks = dateTime.Ticks % roundBy.Ticks; if (remainderTicks < roundBy.Ticks / 2) { // round down return dateTime.AddTicks(-remainderTicks); } // round up return dateTime.AddTicks(roundBy.Ticks - remainderTicks); }
Comments