Je veux arrondir les dates/heures à l'intervalle le plus proche pour une application graphique. Je voudrais une signature de méthode d'extension comme suit afin que l'arrondi puisse être obtenu pour n'importe quel niveau de précision:
static DateTime Round(this DateTime date, TimeSpan span);
L'idée est que si je passe dans un intervalle de temps de dix minutes, il arrondira à l'intervalle de dix minutes le plus proche. Je n'arrive pas à comprendre l'implémentation et j'espère que l'un de vous aura déjà écrit ou utilisé quelque chose de similaire auparavant.
Je pense que soit un sol, un plafond ou une mise en œuvre la plus proche est très bien.
Des idées?
Edit: Grâce à @tvanfosson & @ShuggyCoUk, l'implémentation ressemble à ceci:
public static class DateExtensions {
public static DateTime Round(this DateTime date, TimeSpan span) {
long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;
return new DateTime(ticks * span.Ticks);
}
public static DateTime Floor(this DateTime date, TimeSpan span) {
long ticks = (date.Ticks / span.Ticks);
return new DateTime(ticks * span.Ticks);
}
public static DateTime Ceil(this DateTime date, TimeSpan span) {
long ticks = (date.Ticks + span.Ticks - 1) / span.Ticks;
return new DateTime(ticks * span.Ticks);
}
}
Et s'appelle ainsi:
DateTime nearestHour = DateTime.Now.Round(new TimeSpan(1,0,0));
DateTime minuteCeiling = DateTime.Now.Ceil(new TimeSpan(0,1,0));
DateTime weekFloor = DateTime.Now.Floor(new TimeSpan(7,0,0,0));
...
À votre santé!
Sol
long ticks = date.Ticks / span.Ticks;
return new DateTime( ticks * span.Ticks );
Arrondi (au milieu)
long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;
return new DateTime( ticks * span.Ticks );
Plafond
long ticks = (date.Ticks + span.Ticks - 1)/ span.Ticks;
return new DateTime( ticks * span.Ticks );
Cela vous permettra d'arrondir à n'importe quel intervalle donné. C'est aussi légèrement plus rapide que de diviser puis de multiplier les ticks.
public static class DateTimeExtensions
{
public static DateTime Floor(this DateTime dateTime, TimeSpan interval)
{
return dateTime.AddTicks(-(dateTime.Ticks % interval.Ticks));
}
public static DateTime Ceiling(this DateTime dateTime, TimeSpan interval)
{
var overflow = dateTime.Ticks % interval.Ticks;
return overflow == 0 ? dateTime : dateTime.AddTicks(interval.Ticks - overflow);
}
public static DateTime Round(this DateTime dateTime, TimeSpan interval)
{
var halfIntervalTicks = (interval.Ticks + 1) >> 1;
return dateTime.AddTicks(halfIntervalTicks - ((dateTime.Ticks + halfIntervalTicks) % interval.Ticks));
}
}
Vous devez également être clair si vous voulez que votre arrondi:
Il est très probable que vous ne vous souciez vraiment que du premier point, mais dans ces questions `` simples '', le comportement résultant peut avoir des conséquences d'une grande portée lorsque vous l'utilisez dans le monde réel (souvent à des intervalles adjacents à zéro)
la solution de tvanfosson couvre tous les cas répertoriés en 1. L'exemple du milieu est biaisé vers le haut. Il est douteux que ce soit un problème d'arrondi lié au temps.
Utilisez simplement les tiques, en utilisant cela pour diviser, plancher/plafond/arrondir la valeur et multipliez-la.