Click here to Skip to main content
Click here to Skip to main content

MS Outlook style date edit control/date picker

By , 26 Jan 2002
Rate this:
Please Sign up or sign in to vote.

Screen Shots

How I arrived at this solution

The project I am currently working on is data entry intensive and I have used the opportunity to perform extensive usability testing on the application we are developing.  I have learned quite a bit from the experience, although I think the user sample I have to work with is somewhat limited.

In the process of user testing I uncovered numerous issues users were having using the application.  One of the problems users were having was entering dates and times.  At first, the application used a masked edit control.  I tried various masks for various users and basically discovered that any given user is likely to enter a date any one of many possible ways.  I could have just considered this a training problem but because this application will be shipped nation-wide (USA), this was not a good option.  I tried the date time picker control only to find that this slowed down data entry significantly.

I began looking at other applications and how they allow dates/times to be entered.  I focused in on MS Outlook since it has mass appeal (or at least mass distribution and usage.)  I discovered that MS Outlook allows dates to be entered in just about any valid format.  I also found that it allows for some interesting data entry situations as well. Try entering "2 weeks from now" in a date entry control in MS Outlook, also try using "Christmas" or "2 weeks before Christmas".  To my surprise, outlook correctly calculated the date.  It also dealt with some date calculation situations like "2 weeks from now + 3 days".

I looked around on the web for a control that worked this way to no avail.  Since my date entry problem was important, I took a day to try and simulate the MS Outlook functionality.  This is the result of that effort.

My Solution

My application is a MFC app, so I decided to derive a class off of COleDateTime and re-implement the ParseDateTime function to extend its abilities.  I created a COleDateTimeEx class.  This class implements many of the capabilities of the MS Outlook control (although not all).  Once I had this implemented, I wrote a CEdit derived class (CFPSDateTimeCtrl) to utilize the COleDateTimeEx class. The CFPSDateTimeCtrl control allows the user to enter a date in an open-ended fashion and then when the control looses focus, reformats the entered date into a specific format.

What it can do

The core text parser is contained entirely in the COleDateTimeEx class.  This class can deal with all of the situations the normal COleDateTime class can parse as well as the following situations.

DATE SITUATIONS  
MMDDYY or YYMMDD Example: 091601, 010123
MMDDYYYY Example: 09162001
"today" or "now"
"yesterday"
"day before yesterday"
"tomorrow"
"day after tomorrow"
"next week" 7 days from today
"last week" 7 days ago
"Christmas" or "xmas" or  "x-mass" or "xmass" or "x mass" December 25 of current year (if before 12-25) or 12-25 of next year otherwise.
"Christmas eve" or "xmas eve" or "x-mas eve" or "x-mass eve" or "xmass eve" or "x mass eve" December 24 of current year (if before 12-24) or 12-24 of next year otherwise.
* Other holidays handled: New Years, New Years Eve, 4th of July, Easter, Good Friday, Ash Wednesday, Veterans Day, Memorial Day, Labor Day, Columbus Day, Thanksgiving, and Presidents day.
"last [Day of Week]" Example: "Last Sunday" or "Last Tuesday", etc.
"next [Day of Week]" Example: "Next Sunday" or "Next Tuesday", etc.
"[X] days ago" Note: Also works for weeks, months and years
"[X] days from now" Note: Also works for weeks, months and years
"[X] [Day of Week] in [Month]" Example: "2nd Sunday in December", "1st Tuesday in January", etc.
"[X] days from [N]" or "[X days after [N]" Example: "2 days from Christmas", "2 days from 12/01/2002".
Note: Also works for weeks, months and years.
"[X] days before [N]" Example "2 days before Christmas", "2 days before 12/01/2001".
Note: Also works for weeks, months and years.
"IN [X] days" Example: "in 12 days", "in 30 days", etc.
Note: Also works for weeks, months and years.
"[X] [Day of week] Ago" Example: "2 Sundays ago", "4 Fridays ago"
"[X] [Day of Week] From Now" Example: "2 Sundays from now", "4 Fridays from now"
Simple date arithmetic situations. Example: "Christmas + 2 days", "New Years + 2 days", etc.
Example: "Haloween - 2 weeks", etc.
TIME SITUATIONS
"noon" 12:00 PM
"midnight" 12:00 AM
"XXX" or "XXXX" Example: "430", "515", "1625", "0710", etc.
"X" or "XX" Example: "6", "7", "11", etc.
"[X] O'clock" Example: 6 o'clock
Note: Also works with "oclock" and "o clock"
"[X] minutes from now" or "[X] hours from now" Example: "2 hours from now", "15 minutes from now", etc.
"[X] minutes ago" or "[X] hours ago" Example: "2 hours ago", "15 minutes ago", etc.
"[X] minutes until [XXX]" or "[X] minutes till [XXX]" or "[X] till [XXX]" or "[X] until [XXX]" Example: "15 minutes until noon", 20 minutes till 6", "10 minutes til 1300"
"[X] minutes past [XXX]" or "[X] minutes after [XXX]" or "[X] after [XXX]" or "[X] past [XXX]" Example: "15 minutes after 6", "20 minutes past noon"
"Half past [XXX]" Example: "Half past 6"

What it can't do

The MS Outlook control allows for some complex date calculations (like "2 days from now + 2 weeks + 1 month").  My implementation does not deal with this (although some limited arithmetic is supported.)

More importantly, my class is limited to English only.  In order to support other languages it would be necessary to write a completely new parsing function.  Because this is not needed for my application, I have not attempted to do this.

This class is not fully UNICODE compliant, although I don't believe it would be very difficult to make it UNICODE compliant.  Again, because this is not needed for my application, I have not attempted to do this.

How to use

Using this code is very easy.  If you just wish to use the parser and not the edit control, you only need to use COleDateTimeEx instead of COleDateTime.  The ParseDateTime function has been re-implemented to deal with the new situations.

If you wish to use the edit control, the simplest way to do this is to 

1. Setup the dialog/form resource as normal with an edit control where you want the date edit control to be.

2. Add the IDB_DATEPICKER_BUTTON bitmap (from demo project) to your project.

3. Add a member to your dialog/view/control class of type CFPSDateTimeCtrl

MyDialog.h
//
// a member of type CFPSDateTimeCtrl to be attached to an edit control
CFPSDateTimeCtrl m_wndDate;
CFPSDateTimeCtrl m_wndTime;

4. In the OnInitDialog (or OnInitialUpdate or OnCreate) function call the AttachEdit member function to subclass the existing edit control.  You will also probably want to call the SetParserOption and SetDisplayFormat functions.  The default parser options attempt both date and time parsing.  The default display format is %m%/d/%Y.  

MyDialog.cpp
//
BOOL CMyDialog::OnInitDialog()
{
   ... whatever else
  m_wndDate.SetShowPickerButton(TRUE);
  m_wndDate.AttachEdit(this, IDC_DATE);
  m_wndDate.SetParserOption(VAR_DATEVALUEONLY);
  m_wndDate.SetDisplayFormat("%m/%d/%Y");

  m_wndTime.AttachEdit(this, IDC_TIME);
  m_wndTime.SetParserOption(VAR_TIMEVALUEONLY);
  m_wndTime.SetDisplayFormat("%I:%M %p");
}

That's it.

I have found it pretty easy to use and have not had any complaints from users yet.  However, the application I use this code in is currently in "late-alpha" testing.  So there may well be some problems found as time goes on.  If problems are uncovered, I will correct the code and post the changes to CodeProject as quickly as I can.

The code

The code is not heavily commented, but the comments I believe are adequate to explain the code.  Basically, there are 2 key functions in the COleDateTimeEx class which you will probably want to look at.  These are the "EvaluateInputTextDate" and "EvaluateInputTextTime" functions.  These functions contain the actual parsing algorithms for date and time situations.  WARNING: These functions are basically a hard-coded set of the situations listed above.  As I mentioned earlier and in the code I did not have time to develop a rules-based engine for parsing date text.

Notes

This code is not perfect and not suited for all situations but at least for my project it has been very well received (especially by the end users.)  I would appreciate any comments you have to make regarding my implementation or code.  Thanks.


CHANGES INTRODUCED ON 01-26-2002

Added support for the date picker drop down.  See screen shots above for how it looks.  The control used for the calendar can be used separately from this control.  I have posted an article on CP with just this control and a demo project.  See it for more details.

The date picker control works in much the same way that the MS Outlook date picker control works. 

I am aware of one problem with the date picker option.  When the user drops down the calendar control, it is possible for the user to click on certain UI elements (frame controls) and the calendar control will not automatically be hidden.  This has not been a problem in my app so I have not attempted to correct this yet.  If you have a solution to this issue, please let me know.

CHANGES INTRODUCED ON 01-16-2002

Added methods for ease-of-use in code.

IsValid()
IsSunday()
IsMonday()
Is[XXX] where XXX is the name of day of week
IsWeekDay()
IsWeekendDay()
IsJanuary()
IsFebruary()
Is[XXX] where XXX is name of month
IsLeapYear()

Previously the special time parser always interpreted numeric input as hours based from 7AM and on.  For example, if you entered 8, the parser considered this to be 8 AM, but if you entered 6, it recognized this as 6PM.

Daebi (see threads below) suggested and provided code for allowing options to control this functionality.  I incorporated the code (with some changes to make code more uniform) to allow this to work.  You can now use the SetHourOption and SetHourThreshold functions to control how the time parser handles hour numbers.  See the code for additional details.

Some users have reported having problems entering times with AM/PM indicators.  This was caused because instead of "AM", they entered "A.M." or some other variant.  The standard parser did not understand these.  I have modified the code to check for AM, PM variants and deal with them appropriately.

CHANGES INTRODUCED ON 01-09-2002

White space handling has been improved.

Now supports generic use of the "next", "this next", "last" and "this last" prefixes.  This allows for data entry in the form of "next easter", "next christmas", "last christmas", "last 4th of july".

Support has been added for year suffix situations like "easter 2005", "halloween 2005", etc.

Methods added to CFPSDateTimeCtrl  class. 

SetDate
GetDate

Finally, support has been added for shortcuts.  There are numerous built-in shortcuts, but these can be programmatically removed or modified.  The shortcuts currently supported are listed below.

T Today
N Now
Y Yesterday
TM Tomorrow
NW Next week
NM Next month
LW Last week
LM Last month
DY Day before yesterday
DT Day after tomorrow
X Christmas
XE Christmas eve
E Easter
GF Good friday
AW Ash wednesday
NY New years
NYE New years eve
J4 July 4th
MD Memorial day
LD Labor day
VD Veterans day
CD Columbus day
TH Thanksgiving
PD Presidents day

Updates

01-07-2002A Corrected demo zip file to include files from \res directory
01-07-2002B Thanks to Richard Jones for pointing out flaw involving dependence on ParseDateTime and regional settings. Modified code to use SetDate instead of ParseDateTime. Appears to correct problem. Will try with numerous regional settings.
01-09-2002 Thanks to Rick Crone for identifying need for shortcuts. (See article for more info). Also, Rick identified the need for better white space management and enhancements to date arithemtic algorithms.
Thanks to Pål K Tønder for identifying the need for generic "next" and "last" prefix keywords.

Added support for shortcuts.
Added support for various "next"/"last" situations involving holidays and pre-coded dates.
Added support for situations like "easter 2005">
Added Get/SetDate members to CFPSDateTimeCtrl
01-09-2002 Thanks to Rick Crone for identifying need for shortcuts. (See article for more info). Also, Rick identified the need for better white space management and enhancements to date arithemtic algorithms.
Thanks to Pål K Tønder for identifying the need for generic "next" and "last" prefix keywords.

Added support for shortcuts.
Added support for various "next"/"last" situations involving holidays and pre-coded dates.
Added support for situations like "easter 2005">
Added Get/SetDate members to CFPSDateTimeCtrl
01-11-2002 Thanks to daebi for pointing out a problem with time parsing logic.
I have corrected the time parsing logic as noted.
01-16-2002 Thanks to daebi for point out issues with tome cutoffs used in parser.  daebi provided code to allow for various control options for time parsing (see notes in code)
Time parsing further enhanced to deal with users entering "A.M." (and variants) instead of "AM".
Added copy constructors.
Added IsValid method.
Added numerous other methods for ease-of-use.  (Ie. IsSunday(), IsJanuary(), etc.)
01-26-2002 I added support for the date picker "mode".  This feature displays a button to the right of the control similar to Outlook.  When the user clicks the button a mini-month calendar control is displayed below the control (like standard date picker.)  This mini calendar control simulates the MS Outlook's date picker control.

The mini-calendar control can be used independent of the date time control.  I have posted the code and a demo project for the mini calendar control separately from this article.  See that article for details on using the mini calendar control.

License

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

About the Author

Matt Gullett
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
GeneralLanguage setting for calendar PinmemberBledar Dindi29-May-07 23:47 
GeneralProblems when using in a CDialogBar PinmemberJaniOrca10-Feb-04 6:31 
GeneralVB PinmemberGummi18-Aug-03 22:34 
Generalme too Pinmemberhisofty25-Mar-04 18:41 
GeneralXP Style PinmemberBen G.9-Jul-03 22:34 
GeneralCrashing PinsussAnonymous12-Aug-02 5:40 
GeneralButton Display PinsussAnonymous17-Jul-02 6:38 
GeneralTime validation PinmemberRick Crone15-Jan-02 4:30 
GeneralRe: Time validation PinmemberMatt Gullett15-Jan-02 4:37 
GeneralRe: Time validation PinmemberMatt Gullett16-Jan-02 9:55 
Generalbug PinmemberRick Crone15-Jan-02 4:16 
GeneralError in Some Time Parsing Pinmemberdaebi11-Jan-02 4:05 
GeneralRe: Error in Some Time Parsing PinmemberMatt Gullett11-Jan-02 5:00 
GeneralThanks! PinmemberRick Crone9-Jan-02 5:14 
GeneralRe: Thanks! PinmemberMatt Gullett9-Jan-02 5:28 
GeneralRe: Thanks! PinmemberMatt Gullett9-Jan-02 13:13 
GeneralSuggestion PinmemberPål K Tønder8-Jan-02 22:31 
GeneralRe: Suggestion PinmemberMatt Gullett9-Jan-02 2:15 
GeneralRe: Suggestion PinmemberMatt Gullett9-Jan-02 13:14 
GeneralA few questions / comments. PinmemberRick Crone8-Jan-02 9:13 
GeneralRe: A few questions / comments. PinmemberMatt Gullett8-Jan-02 13:40 
GeneralRe: A few questions / comments. PinmemberRick Crone9-Jan-02 9:42 
GeneralCouple of errors PinmemberRichard Jones7-Jan-02 6:32 
GeneralRe: Couple of errors PinmemberMatt Gullett7-Jan-02 7:14 
GeneralRe: Couple of errors PinmemberRichard Jones7-Jan-02 7:31 
GeneralRe: Couple of errors PinmemberRichard Jones7-Jan-02 7:34 
GeneralRe: Couple of errors PinmemberMatt Gullett7-Jan-02 8:05 
GeneralRe: Couple of errors PinmemberMatt Gullett7-Jan-02 7:39 
GeneralVery interesting PinmemberJames Pullicino7-Jan-02 1:55 
GeneralRe: Very interesting PinmemberMatt Gullett7-Jan-02 8:50 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140421.2 | Last Updated 27 Jan 2002
Article Copyright 2002 by Matt Gullett
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid