Reputation: 586
I have a DateTimePicker control on a form specified like so:
dtpEntry.Format = DateTimePickerFormat.Custom;
dtpEntry.CustomFormat = "dd/MM/yyyy hh:mm:ss";
dtpEntry.ShowUpDown = true;
I would like the user to only be able to increment or decrement the time by 5 minute increments.
Any suggestions on how one would accomplish this?
Upvotes: 7
Views: 16552
Reputation: 11
By combining the math logic above with an override class I found at Getting the previous value of an object at ValueChanged event, you can do this in a generic fashion rather than having to precreate a variable for every DateTimePicker on the form.
Here's the override class:
internal class LastDateTimePicker : DateTimePicker
{
protected override void OnValueChanged(EventArgs eventargs)
{
base.OnValueChanged(eventargs);
LastValue = Value;
}
public DateTime LastValue { get; private set; }
public new DateTime Value
{
get { return base.Value; }
set
{
base.Value = value;
}
}
}
And then here is the updated calculation method where I also generalized the increment:
private bool navigatingDateTimePicker = false;
private int incrementMinutes = 15;
private void DateTimePicker_ValueChanged(object sender, EventArgs e)
{
LastDateTimePicker picker = sender as LastDateTimePicker;
//TODO: make this actually work
if (picker != null)
{
if (!navigatingDateTimePicker)
{
/* First set the navigating flag to true so this method doesn't get called again while updating */
navigatingDateTimePicker = true;
/* using timespan because that's the only way I know how to round times well */
TimeSpan tempTS = picker.Value - picker.Value.Date;
TimeSpan roundedTimeSpan;
TimeSpan TDBug = picker.Value - picker.LastValue;
if (TDBug.TotalMinutes == 59)
{
// first: if we are going back and skipping an hour it needs an adjustment
roundedTimeSpan = TimeSpan.FromMinutes(incrementMinutes * Math.Floor((tempTS.TotalMinutes - 60) / incrementMinutes));
picker.Value = picker.Value.Date + roundedTimeSpan;
}
else if (picker.Value > picker.LastValue)
{
// round up to the nearest interval
roundedTimeSpan = TimeSpan.FromMinutes(incrementMinutes * Math.Ceiling(tempTS.TotalMinutes / incrementMinutes));
picker.Value = picker.Value.Date + roundedTimeSpan;
}
else
{
// round down to the nearest interval from prev
roundedTimeSpan = TimeSpan.FromMinutes(incrementMinutes * Math.Floor(tempTS.TotalMinutes / incrementMinutes));
picker.Value = picker.Value.Date + roundedTimeSpan;
}
navigatingDateTimePicker = false;
}
}
}
Upvotes: 1
Reputation: 1
@Hans Passant Just needed to handle 59 for it to work right.
private void dateTimePickerReportScheduleTime_ValueChanged(object sender, EventArgs e)
{
if (!mBusy)
{
mBusy = true;
DateTime dt = dateTimePickerReportScheduleTime.Value;
if ((dt.Minute * 60 + dt.Second) % 300 != 0)
{
TimeSpan diff = dt - mPrevDate;
if (dt.Minute == 59)
{
dateTimePickerReportScheduleTime.Value = mPrevDate.AddMinutes(-15);
}
else
{
if (diff.Ticks < 0) dateTimePickerReportScheduleTime.Value = mPrevDate.AddMinutes(-15);
else dateTimePickerReportScheduleTime.Value = mPrevDate.AddMinutes(15);
}
}
mBusy = false;
}
mPrevDate = dateTimePickerReportScheduleTime.Value;
}
Upvotes: 0
Reputation: 21
Or simply try this:
private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
{
if (this.dateTimePicker1.Value.Minute % 5 == 0)
return;
if (this.dateTimePicker1.Value.Minute % 5 == 1)
this.dateTimePicker1.Value = this.dateTimePicker1.Value.AddMinutes(4);
if (this.dateTimePicker1.Value.Minute % 5 == 4)
this.dateTimePicker1.Value = this.dateTimePicker1.Value.AddMinutes(-4);
}
Upvotes: 2
Reputation: 81
I've changed a little the answer from SixOThree, to eliminate the bug found by Necromporph. It should be ok like this:
in the class
private DateTime prevTimePicker1;
private bool navigatingDateTimePicker = false;
in the constructor
prevTimePicker1 = dateTimePickerStart.Value;
navigatingDateTimePicker = false;
the event
private void dateTimePickerStart_ValueChanged(object sender, EventArgs e)
{
if (!navigatingDateTimePicker) {
/* First set the navigating flag to true so this method doesn't get called again while updating */
navigatingDateTimePicker = true;
/* using timespan because that's the only way I know how to round times well */
TimeSpan tempTS = dateTimePickerStart.Value - dateTimePickerStart.Value.Date;
TimeSpan roundedTimeSpan;
TimeSpan TDBug = dateTimePickerStart.Value - prevTimePicker1;
if (TDBug.TotalMinutes == 59)
{
// first: if we are going back and skipping an hour it needs an adjustment
roundedTimeSpan = TimeSpan.FromMinutes(5 * Math.Floor((tempTS.TotalMinutes - 60) / 5));
dateTimePickerStart.Value = dateTimePickerStart.Value.Date + roundedTimeSpan;
}
else if (dateTimePickerStart.Value > prevTimePicker1)
{
// round up to the nearest interval
roundedTimeSpan = TimeSpan.FromMinutes(5 * Math.Ceiling(tempTS.TotalMinutes / 5));
dateTimePickerStart.Value = dateTimePickerStart.Value.Date + roundedTimeSpan;
} else {
// round down to the nearest interval from prev
roundedTimeSpan = TimeSpan.FromMinutes(5 * Math.Floor(tempTS.TotalMinutes / 5));
dateTimePickerStart.Value = dateTimePickerStart.Value.Date + roundedTimeSpan;
}
navigatingDateTimePicker = false;
}
prevTimePicker1 = dateTimePickerStart.Value;
}
Upvotes: 8
Reputation: 1729
you could add this code
int minuteDiff = dtpJamAppointmentDokter.Value.Minute - prevTimePicker1.Minute;
if (minuteDiff == 59)
{
dtpJamAppointmentDokter.Value = dtpJamAppointmentDokter.Value.AddHours(-1);
}
before
TimeSpan tempTS = dtpJamAppointmentDokter.Value - dtpJamAppointmentDokter.Value.Date;
Upvotes: 0
Reputation: 771
I know this is an old article, but I created a better solution to this problem based on the answer above.
in the class
private DateTime prevTimePicker1;
private bool navigatingDateTimePicker = false;
in the constructor
prevTimePicker1 = dateTimePickerStart.Value;
navigatingDateTimePicker = false;
the event
private void dateTimePickerStart_ValueChanged(object sender, EventArgs e)
{
if (!navigatingDateTimePicker) {
/* First set the navigating flag to true so this method doesn't get called again while updating */
navigatingDateTimePicker = true;
/* using timespan because that's the only way I know how to round times well */
TimeSpan tempTS = dateTimePickerStart.Value - dateTimePickerStart.Value.Date;
TimeSpan roundedTimeSpan;
if (dateTimePickerStart.Value > prevTimePicker1) {
// round up to the nearest interval
roundedTimeSpan = TimeSpan.FromMinutes(5 * Math.Ceiling(tempTS.TotalMinutes / 5));
dateTimePickerStart.Value = dateTimePickerStart.Value.Date + roundedTimeSpan;
} else {
// round down to the nearest interval from prev
roundedTimeSpan = TimeSpan.FromMinutes(5 * Math.Floor(tempTS.TotalMinutes / 5));
dateTimePickerStart.Value = dateTimePickerStart.Value.Date + roundedTimeSpan;
}
navigatingDateTimePicker = false;
}
prevTimePicker1 = dateTimePickerStart.Value;
}
Upvotes: 0
Reputation: 942538
It's possible by watching the ValueChanged event and override the value. This sample form worked well:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
dateTimePicker1.CustomFormat = "dd/MM/yyyy hh:mm";
dateTimePicker1.Format = DateTimePickerFormat.Custom;
dateTimePicker1.ShowUpDown = true;
dateTimePicker1.Value = DateTime.Now.Date.AddHours(DateTime.Now.Hour);
mPrevDate = dateTimePicker1.Value;
dateTimePicker1.ValueChanged += new EventHandler(dateTimePicker1_ValueChanged);
}
private DateTime mPrevDate;
private bool mBusy;
private void dateTimePicker1_ValueChanged(object sender, EventArgs e) {
if (!mBusy) {
mBusy = true;
DateTime dt = dateTimePicker1.Value;
if ((dt.Minute * 60 + dt.Second) % 300 != 0) {
TimeSpan diff = dt - mPrevDate;
if (diff.Ticks < 0) dateTimePicker1.Value = mPrevDate.AddMinutes(-5);
else dateTimePicker1.Value = mPrevDate.AddMinutes(5);
}
mBusy = false;
}
mPrevDate = dateTimePicker1.Value;
}
}
Upvotes: 11
Reputation: 37847
The problem is that the up/down control automatically increments or decrements the currently highlighted portion of the date/time picker (i.e. year/month/day/hour/etc.).
You are probably better off adding your own up/down control (perhaps a very small vscrollbar) immediately adjacent to the date/time picker and wiring it up to increment/decrement five minute intervals from the date/time picker's value.
Upvotes: 1