c#


Rounding DateTime objects


I want to round dates/times to the nearest interval for a charting application. I'd like an extension method signature like follows so that the rounding can be acheived for any level of accuracy:
static DateTime Round(this DateTime date, TimeSpan span);
The idea is that if I pass in a timespan of ten minutes, it will round to the nearest ten minute interval. I can't get my head around the implementation and am hoping one of you will have written or used something similar before.
I think either a floor, ceiling or nearest implementation is fine.
Any ideas?
Edit: Thanks to #tvanfosson & #ShuggyCoUk, the implementation looks like this:
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);
}
}
And is called like so:
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));
...
Cheers!
Floor
long ticks = date.Ticks / span.Ticks;
return new DateTime( ticks * span.Ticks );
Round (up on midpoint)
long ticks = (date.Ticks + (span.Ticks / 2) + 1)/ span.Ticks;
return new DateTime( ticks * span.Ticks );
Ceiling
long ticks = (date.Ticks + span.Ticks - 1)/ span.Ticks;
return new DateTime( ticks * span.Ticks );
This will let you round to any interval given, is slightly faster than dividing and then multiplying the ticks, and most importantly it's readable.
private static DateTime Floor(DateTime dateTime, TimeSpan interval)
{
return dateTime.AddTicks(-(dateTime.Ticks % interval.Ticks));
}
private static DateTime Ceiling(DateTime dateTime, TimeSpan interval)
{
var overflow = dateTime.Ticks % interval.Ticks;
return overflow == 0 ? dateTime : dateTime.AddTicks(interval.Ticks - overflow);
}
private static DateTime Round(DateTime dateTime, TimeSpan interval)
{
var halfIntervelTicks = (interval.Ticks + 1) >> 1;
return dateTime.AddTicks(halfIntervelTicks - ((dateTime.Ticks + halfIntervelTicks) % interval.Ticks));
}
You should also be clear if you want your rounding to:
be to the start, end or middle of the interval
start is the easiest and often the expected but you should be clear in your initial spec.
How you want boundary cases to round.
normally only an issue if you are rounding to the middle rather than the end.
Since rounding to the middle is an attempt at a bias free answer you need to use something like Bankers Rounding technically round half even to be truly free from bias.
It is quite likely that you really only care about the first point but in these 'simple' questions the resulting behaviour can have far reaching consequences as you use it in the real world (often at the intervals adjacent to zero)
tvanfosson's solution's cover all the cases listed in 1.
The midpoint example is biased upwards. It is doubtful that this would be a problem in time related rounding.
Just use the Ticks, using that to divide, floor/ceil/round the value, and multiply it back.

Related Links

C# Send input to separate process through command prompt
How does .NET know when to continue to the next line of code?
NLog with AutoFac - How to give logger name
Execute Insert command and return inserted Id in SQL Server using C#
How to include a local webpage in C# VisualStudio 2015
Set gridview column width?
Unity - NullReferenceException when deserializing xml file [duplicate]
Nuget Conflicting projectreference and packagereference
WPFrepeated(multiple) node
How can I access files outside of “public_html” with webclient or FTP in C#?
Saving list of Bitmap Images
Bad request when trying to post to rest service with byte[] input
Should assembly guid attribute vary for different target framework builds of the same .NET library?
Entity Framework: Many-to-many relationship with unusual keys
Problems with LextmSharpSNMPLib
C# callback from c++ works only once

Categories

HOME
youtube-api
grizzly
mobile
network-programming
locale
postgresql-9.3
openacc
packet
azure-eventhub
popover
crm
nltk
azure-resource-manager
lithium
query-string
ms-application-insights
msbi
multipartform-data
genexus
yacc
sahi
token
ejb-3.0
rename
suitecrm
captcha
hdf5
repeater
appsettings
typedef
gnu-screen
connection-pooling
rvm
v4l2
sha
aws-certificate-manager
multiple-inheritance
typeclass
language-detection
rtos
dropdownbox
wit-ai
scip
cowboy
jvisualvm
python-venv
piranha-cms
weld
azure-data-catalog
geminabox
opos
g77
jscoverage
nservicebus6
cc
chain
group
turbolinks
firebase-polymer
alfred
deck.js
diameter-protocol
laterjs
3d-rendering
periodic-processing
dday
controlpanel
identifying
autoscaling
borland-c++
firewire
vspackage
targetprocess
teamstudio-unplugged
yosemite
famous-engine
mvcgrid
reactjs-native
android-relativelayout
vbaccelerator
nop
facebook-likebox
lastinsertid
nokogiri
angularjs-select2
typography
panelgrid
outlook-object-model
gssapi
orchestration
report-viewer2010
beep
systrace
bash4
jmesa
towerjs
cherokee
httppostedfilebase
versions
pixel-bender

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App