Click here to Skip to main content
13,594,948 members
Click here to Skip to main content
Add your own
alternative version


51 bookmarked
Posted 14 Apr 2006
Licenced CPOL

DateRangePicker (select date ranges with a single extended Calendar)

, 14 Apr 2006
Rate this:
Please Sign up or sign in to vote.
Extend a Calendar to let users pick a date range - with less than three pages of code.

Sample Image - DateRangePicker.gif


My custom control, DateRangePicker, provides the ability to select not just single dates but arbitrary date ranges. It is a trivially extended Calendar control.


I needed to provide users with the ability to select date ranges. Two calendars side by side take up a lot of space, so I had a look for custom controls. I noticed that Windows Forms let you select date ranges, but web form calendars can select days, weeks, or months. There were some commercial products on the internet, but once I saw what methods could be overridden on Calendar, I knew it would be easy enough to implement my own.

User Interface

The first time a user selects a date, that date is recorded as one end of the date range. Then, the second click on the same calendar will set the other end of the date range. A third click will clear the old date range and record a new date as the starting point of a date range, and so on.

Using the code

Once you have the code in a custom web control library project, all you have to do is drag the control from your toolbox onto the designer, just like any other custom control.

You should see something like the following code added to your page:

<%@ Register Assembly="CustomWebControls" 

      Namespace="CustomWebControls" TagPrefix="cc1" %>


<cc1:DateRangePicker ID="DateRangePicker1" 


How it works

There are two classes that make up the DateRangePicker control - DateRange, and DateRangePicker. DateRange is a struct to represent a range of dates, and DateRangePicker is the custom web control that extends System.Web.UI.Calendar.


A DateRange is essentially a from date and a to date. It would be possible to implement a DateRangePicker without this, but it helps us keep logic out of the UI code. It's marked as Serializable so that the WebControl can keep it in the viewstate. The most important logic method is Include, which adds a DateTime or another DateRange to the instance. We use this when a second DateTime is clicked, and it means the user doesn't have to click the earliest date first. Equals, HashCode, and the operators == and != are all overridden for efficiency.

using System;

namespace CustomWebControls
    public struct DateRange
        public static readonly DateRange EMPTY = new DateRange();
        readonly DateTime from;
        readonly DateTime to;

        public DateRange(DateTime from, DateTime to)
            this.from = from;
   = to;

        public DateTime From
            get { return from; }

        public DateTime To
            get { return to; }

        public TimeSpan TimeSpan
                return to - from;
        public bool Contains(DateTime time)
            return from <= time && time < to;

        public DateRange Include(DateRange otherRange)
            return Include(otherRange.From).Include(otherRange.To);

        public DateRange Include(DateTime date)
            if (date < from)
                return new DateRange(date, to);
            else if (date > to)
                return new DateRange(from, date);
                return this;

        /// <summary>
        /// Creates a one day (24 hr) long DateRange starting at DateTime
        /// </summary>
        public static DateRange CreateDay(DateTime dateTime){
            return new DateRange(dateTime, dateTime.AddDays(1));

        #region operators and overrides
        public override int GetHashCode()
            return from.GetHashCode() + 29*to.GetHashCode();

        public override bool Equals(object obj)
            if (ReferenceEquals(this, obj)) return true;
            if (!(obj is DateRange)) return false;
            DateRange dateRange = (DateRange) obj;
            if (!Equals(from, dateRange.from)) return false;
            if (!Equals(to, return false;
            return true;

        public static bool operator == (DateRange d1, DateRange d2)
            return d1.Equals(d2);

        public static bool operator !=(DateRange d1, DateRange d2)
            return !d1.Equals(d2);



This is the class that overrides Calendar. It has two properties, one for styling the selected DateRange and another to store the selected DateRange.

By default, the style has a BackColor of LightSteelBlue. This is initialised in the static constructor. The style is stored in a private variable, because whenever a Page is initialised, the new style will be set by the designer code. SelectedDateRange, however, is stored in the ViewState because it needs to persist across multiple page requests. If you don't use ViewState, you will need to find another way to persist this variable.

OnSelectionChanged is where we change the DateRange. OnDayRender is where we apply the styling to a DateRange. Note the special handling of whole days in OnSelectionChanged.

using System.ComponentModel;
using System.Drawing;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CustomWebControls
    /// <summary>
    /// An extended Calendar that can select DateRanges as well as Dates
    /// </summary>
    [ToolboxData("<{0}:DateRangePicker runat="server"></{0}:DateRangePicker>")]
    public class DateRangePicker : Calendar
        static readonly TableItemStyle defaultSelectedDateRangeStyle = new TableItemStyle();

        static DateRangePicker()
            //initialise a default colour for defaultSelectedDateRangeStyle
            defaultSelectedDateRangeStyle.BackColor = Color.LightSteelBlue;

        TableItemStyle selectedDateRangeStyle = defaultSelectedDateRangeStyle;

        protected override void OnDayRender(TableCell cell, CalendarDay day)
            if (SelectedDateRange.Contains(day.Date))

        protected override void OnSelectionChanged()

            bool emptyDateRange = SelectedDateRange == DateRange.EMPTY;
            bool dateRangeAlreadyPicked = SelectedDateRange.TimeSpan.TotalDays > 1;

            if (emptyDateRange || dateRangeAlreadyPicked)
                SelectedDateRange = DateRange.CreateDay(SelectedDate);
                //save this date as the first date in our date range
                SelectedDateRange = 
                //set the end date in our date range

        //DateRange gets stored in the viewstate since
        //it's a property that needs to persist across page requests.
        public DateRange SelectedDateRange
            get { return (DateRange) (ViewState["SelectedDateRange"]??DateRange.EMPTY); }
            set { ViewState["SelectedDateRange"] = value; }

        //SelectedDateRangeStyle goes into a private
        //variable since this property is designed.
        [Description("The Style that is aplied to cells within the selected Date Range")]
        public TableItemStyle SelectedDateRangeStyle
            get { return selectedDateRangeStyle; }
            set { selectedDateRangeStyle = value; }

Future Work

  • Better designer support.
  • Further extensions to OnDayRender to give the user more tooltips regarding what to do.
  • Your suggestions! I value all feedback. I'd love to hear if this works well for you, or if you have any improvements you'd like to offer.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Robert Ensor
Web Developer
New Zealand New Zealand
No Biography provided

You may also be interested in...

Comments and Discussions

BugError in page Pin
Vandana8718-Jul-17 20:59
memberVandana8718-Jul-17 20:59 
GeneralThanks! Exactly what I was looking for. Pin
Member 166015120-Jul-09 10:07
memberMember 166015120-Jul-09 10:07 
Generalinsert DateRangePicker into flash cs4 Pin
Leonado Zuzzi24-Jun-09 10:57
memberLeonado Zuzzi24-Jun-09 10:57 
Questionhow to apply styles. Pin
medasatheesh1-Apr-09 10:56
membermedasatheesh1-Apr-09 10:56 
GeneralGreat Control! Pin
planetregin21-Oct-08 10:15
memberplanetregin21-Oct-08 10:15 
QuestionHow to display selcted date range? Pin
Member 16601859-Mar-08 22:34
memberMember 16601859-Mar-08 22:34 
GeneralThe To Date is 1 day to much Pin
Marckus_E5-Sep-07 1:26
memberMarckus_E5-Sep-07 1:26 
GeneralOnSelectionChanged implementation Pin
xoph13-Mar-07 12:41
memberxoph13-Mar-07 12:41 
QuestionVisual Basic Pin
si_owen3-Nov-06 5:23
membersi_owen3-Nov-06 5:23 
AnswerRe: Visual Basic Pin
Robert Ensor6-Nov-06 10:10
memberRobert Ensor6-Nov-06 10:10 
QuestionRe: Visual Basic Pin
si_owen7-Nov-06 4:20
membersi_owen7-Nov-06 4:20 
AnswerRe: Visual Basic Pin
Robert Ensor7-Nov-06 10:00
memberRobert Ensor7-Nov-06 10:00 
QuestionRe: Visual Basic Pin
si_owen7-Nov-06 21:31
membersi_owen7-Nov-06 21:31 
AnswerRe: Visual Basic Pin
Robert Ensor8-Nov-06 11:04
memberRobert Ensor8-Nov-06 11:04 
GeneralRe: Visual Basic Pin
si_owen8-Nov-06 23:24
membersi_owen8-Nov-06 23:24 
Generaltest for single date and clear all dates Pin
pimming22-May-06 10:12
memberpimming22-May-06 10:12 
GeneralRe: test for single date and clear all dates Pin
Robert Ensor22-May-06 12:10
memberRobert Ensor22-May-06 12:10 
GeneralRe: test for single date and clear all dates Pin
pimming22-May-06 17:50
memberpimming22-May-06 17:50 
GeneralNice Pin
Dan Letecky14-May-06 12:04
memberDan Letecky14-May-06 12:04 
QuestionHow do I create this control in VS 2005 Pin
gkadery4-May-06 5:56
membergkadery4-May-06 5:56 
AnswerRe: How do I create this control in VS 2005 Pin
Robert Ensor4-May-06 12:02
memberRobert Ensor4-May-06 12:02 
GeneralClick and Drag.. Pin
MikeEast18-Apr-06 12:58
memberMikeEast18-Apr-06 12:58 
GeneralRe: Click and Drag.. Pin
Robert Ensor18-Apr-06 13:05
memberRobert Ensor18-Apr-06 13:05 
GeneralRe: Click and Drag.. Pin
MikeEast18-Apr-06 13:11
memberMikeEast18-Apr-06 13:11 
GeneralRe: Click and Drag.. Pin
Robert Ensor18-Apr-06 13:14
memberRobert Ensor18-Apr-06 13:14 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web04-2016 | 2.8.180621.3 | Last Updated 15 Apr 2006
Article Copyright 2006 by Robert Ensor
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid