Selecting Start and Finish times from dropdownlists - 00:00 is not recognised as being later than 22:00

Hi Experts,

I'm using a bit of code to populate a couple of drop down lists with a 24hr array of times at 15minute intervals and I want users to be able to select a start time from the first drop down and a finish time from the second. The array in each case begins at 00:00 and ends with 23:45 so when a user selects a start of 22:00 and a finish of 00:00 the validation I have on the application thinks that 00:00 is before 22:00 and rejects the selection as being invalid. Can anyone help me to resolve this? The code to populate the dropdowns is below:
DDLStart.Items.Add("--select start time--");
        DDLStop.Items.Add("--select finish time--");
        List<string> times = new List<string>();
        for (int hour = 0; hour < 24; hour++)
            for (int minute = 0; minute < 60; minute++)
                if (minute % 15 == 0)
                    times.Add(string.Format("{0:00}:{1:00}", hour, minute));

        foreach (string child in times)
        {

            DDLStart.Items.Add(child);
            DDLStop.Items.Add(child);

        }

Open in new window


Many thanks in advance
forstersAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Guy Hengel [angelIII / a3]Billing EngineerCommented:
first, a small comment:
for (int minute = 0; minute < 60; minute++)
                if (minute % 15 == 0)

should be in a single step, incrementing by 15 directly...
for (int minute = 0; minute < 60; minute+=15)


next, you shall maybe check if 24:00 would be acceptable, or 23:59 as alternative, which you could end after your loop to the dropdown.
AndyAinscowFreelance programmer / ConsultantCommented:
>>I have on the application thinks that 00:00 is before 22:00 and rejects the selection as being invalid.

Your app is correct, 00:00 is earlier than 22:00.  As is 00:15 earlier than 22:00 and so on....
You might need to have a serious think of how your user select things (but then again you haven't actually told us how that is done).  If the only possible problem is concerning 00:00 then just provide an extra check that if the finish is 00:00 then the selection is always valid else you perform your current validity check.
forstersAuthor Commented:
Hi, thanks for the comment, very helpful, I've amended my code.
Yes I was wondering about 24:00 (which I think is my preferred option) how would I do that can you show me ?
CompTIA Security+

Learn the essential functions of CompTIA Security+, which establishes the core knowledge required of any cybersecurity role and leads professionals into intermediate-level cybersecurity jobs.

forstersAuthor Commented:
Hi Andy,  thanks yes I realise that the app is technically correct and I think I have been fairly clear on how the user selects the times...?
I like the solution however so I will have a look at my validation and see how easily I can amend. Thanks for your comments
Guy Hengel [angelIII / a3]Billing EngineerCommented:
between the 2 loops:
times.Add("24:00");
AndyAinscowFreelance programmer / ConsultantCommented:
Select finish time - I understand what you are saying with the drop downs but I know from experience sometimes things finish the next day and that a user that did in fact finish at 00:15 could realistically assume that was a valid selection (unless the bit of the UI you don't tell us about will cope with that).
Guy Hengel [angelIII / a3]Billing EngineerCommented:
I concur with AndyAinscow, you may indeed rather have as second drop down a "duration" (or a slider) and show the end time based on start time + duration ...
forstersAuthor Commented:
Ah I see what you are both saying, apologies, there is a rule applying to this particular situation that anything crossing over into a new day must be regarded as a separate occurrence and entered separately, midnight being the cut off and therefore the only slight fly in the ointment. Thank you both I'm going to just have a play about with both suggestions and see which is going to be the easiest to work into the app at this stage. I will likely divvy up point equally as you've both been really helpful thank you.
AndyAinscowFreelance programmer / ConsultantCommented:
OK.  So if I understand the first possible start time is 00:00 and the last possible start time is 23:45.  HOWEVER the first possible finish is then 00:15 and the last possible is 24:00.
So just fill the two drop downs with those ranges and continue as you currently do.
forstersAuthor Commented:
Indeed, I think you're possibly right...
The problem I am having with this (which may be easier to overcome than I realise) is that having tried Guy's suggestion of inserting times.Add("24:00"); which does exactly as I want, if I then select 24:00 as my finish time my SQL insert complains that it cant convert the character string - Conversion failed when converting date and/or time from character string.
The second challenge I'm realising is that I have a series of JavaScript validations that calculate the duration between start-time and finish-time, so I that has to 'understand' that a start of 00:00 and a finish of 24:00 equates to zero not 24hrs whereas 00:15 to 24:00 is 23:45hrs etc. so its kinda more complex than I first thought...
beginning to think I've done this all wrong :\
AndyAinscowFreelance programmer / ConsultantCommented:
Remember, a user WILL find any possible way to abuse your app - unfortunately even those you haven't thought would be possible.
Think paranoid  ;-)


I once spent about 10 minutes over the phone helping a user whose mouse had stopped working.  I kept telling them to use the arrow keys on the keyboard.  The user told me they could not find them.  Eventually they said they were looking for the arrow keys on the screen (and remember the mouse wasn't working!!!) to click on.
it_saigeDeveloperCommented:
If I may interject with another way of solving this issue, why not use DateTime objects instead of strings?  Consider the following:
Default.aspx -
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="EE_Q28689782._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
    	<asp:Label ID="Label1" runat="server" Text="Start Time:  "></asp:Label>
	    <asp:DropDownList ID="ddStart" runat="server">
	    </asp:DropDownList>
	    <br />
	    <br />
	    <asp:Label ID="Label2" runat="server" Text="Finish Time:  "></asp:Label>
	    <asp:DropDownList ID="ddFinish" runat="server">
	    </asp:DropDownList>
	    <br />
	    <br />
	    <asp:Button ID="btnCalculate" runat="server" onclick="OnClick" 
		    Text="Calculate" />
	    <br />
	    <br />
	    <asp:Literal ID="litStats" runat="server"></asp:Literal>
    
    </div>
    </form>
</body>
</html>

Open in new window

Default.aspx.cs -
using System;
using System.Collections.Generic;
using System.Linq;

namespace EE_Q28689782
{
	public partial class _Default : System.Web.UI.Page
	{
		private List<DateTime> startTimes = default(List<DateTime>);
		private List<DateTime> finishTimes = default(List<DateTime>);

		protected void Page_Load(object sender, EventArgs e)
		{
			if (!IsPostBack)
			{
				DateTime today = DateTime.Now;
				if (startTimes == null)
					startTimes = (from interval in Enumerable.Range(0, (24 * 60) / 15) let now = new DateTime(today.Year, today.Month, today.Day, 0, 0, 0).AddMinutes(15 * interval) select now).ToList();

				if (finishTimes == null)
					finishTimes = (from interval in Enumerable.Range(0, (24 * 60) / 15) let now = new DateTime(today.Year, today.Month, today.Day, 0, 0, 0).AddMinutes(15 * interval) select now).ToList();

				ddStart.DataSource = startTimes;
				ddStart.DataTextFormatString = "{0:HH:mm}";
				ddStart.DataBind();
				ddFinish.DataSource = finishTimes;
				ddFinish.DataTextFormatString = "{0:HH:mm}";
				ddFinish.DataBind();
			}
		}

		protected void OnClick(object sender, EventArgs e)
		{
			DateTime start = DateTime.MinValue;
			DateTime finish = DateTime.MinValue;
			if (DateTime.TryParse(ddStart.SelectedValue, out start) && DateTime.TryParse(ddFinish.SelectedValue, out finish))
			{
				litStats.Text = string.Format("Start Time = {0:HH:mm}<br />Finish Time = {1:HH:mm}<br />The calculatted difference is: {2} minutes", start, finish, (finish - start).TotalMinutes);
			}
			else
			{
				litStats.Text = "Invalid selections to perform calculations!!!";
			}
		}
	}
}

Open in new window

Which produces the following output -Initial page loadI could choose any time in the interval but I'll select the one you indicate Start 00:00; Finish 22:00Hitting the calculate button calculates the number of minutes between the start and finish time.-saige-
it_saigeDeveloperCommented:
Ofcourse following Andy's logic to it's ultimate conclusion we could do the following:
Default.aspx.cs -
using System;
using System.Collections.Generic;
using System.Linq;

namespace EE_Q28689782
{
	public partial class _Default : System.Web.UI.Page
	{
		private List<DateTime> startTimes = default(List<DateTime>);
		private List<DateTime> finishTimes = default(List<DateTime>);

		protected void Page_Load(object sender, EventArgs e)
		{
			if (!IsPostBack)
			{
				DateTime today = DateTime.Now;
				if (startTimes == null)
					startTimes = (from interval in Enumerable.Range(0, (24 * 60) / 15) let now = new DateTime(today.Year, today.Month, today.Day, 0, 0, 0).AddMinutes(15 * interval) select now).ToList();

				if (finishTimes == null)
					finishTimes = (from interval in Enumerable.Range(1, (24 * 60) / 15) let now = new DateTime(today.Year, today.Month, today.Day, 0, 0, 0).AddMinutes(15 * interval) select now).ToList();

				ddStart.DataSource = startTimes;
				ddStart.DataTextFormatString = "{0:HH:mm}";
				ddStart.DataBind();
				ddFinish.DataSource = finishTimes;
				ddFinish.DataTextFormatString = "{0:HH:mm}";
				ddFinish.DataBind();
			}
		}

		protected void OnClick(object sender, EventArgs e)
		{
			DateTime start = DateTime.MinValue;
			DateTime finish = DateTime.MinValue;
			if (DateTime.TryParse(ddStart.SelectedValue, out start) && DateTime.TryParse(ddFinish.SelectedValue, out finish))
			{
				litStats.Text = string.Format("Start Time = {0:HH:mm}<br />Finish Time = {1:HH:mm}<br />The calculatted difference is: {2} minutes", start, finish, (finish - start).TotalMinutes);
			}
			else
			{
				litStats.Text = "Invalid selections to perform calculations!!!";
			}
		}
	}
}

Open in new window

Which would give us two distinct lists -
Start will begin at 00:00 and end at 23:45 for today's date.
Finish will begin at 00:15 of today's date but end at 00:00 for tomorrow's date.

Proof of concept run -Initial loadHere we see the finish drop down ends with 00:00Here we see that if we select the start and finish of 00:00 that we end up with 1440 minutes (24 Hours)Now if you want to actually show 24:00 in the drop down then that would probably be solved easiest with an intermediary object.  I'll whip up an example of that in a few.

-saige-
forstersAuthor Commented:
hi saige,

Thank you for your comment, I agree that a switch to datetime does seem to offer an alternative solution. I should say though that the example you have given would work with the current code, it is when the start time is 22:00 and the finish 00:00 that the difficulty occurs, but I assume this would work in the example you have given. Thank you for commenting.
it_saigeDeveloperCommented:
Finally, here is an example with an intermediary object:
Default.aspx.cs -
using System;
using System.Collections.Generic;
using System.Linq;

namespace EE_Q28689782
{
	public partial class _Default : System.Web.UI.Page
	{
		private static List<IntervalItem> startTimes = default(List<IntervalItem>);
		private static List<IntervalItem> finishTimes = default(List<IntervalItem>);

		protected void Page_Load(object sender, EventArgs e)
		{
			if (!IsPostBack)
			{
				DateTime today = DateTime.Now;
				if (startTimes == null)
					startTimes = (from interval in Enumerable.Range(0, (24 * 60) / 15) let now = new DateTime(today.Year, today.Month, today.Day, 0, 0, 0).AddMinutes(15 * interval) select new IntervalItem(today, now)).ToList();

				if (finishTimes == null)
					finishTimes = (from interval in Enumerable.Range(1, (24 * 60) / 15) let now = new DateTime(today.Year, today.Month, today.Day, 0, 0, 0).AddMinutes(15 * interval) select new IntervalItem(today, now)).ToList();

				ddStart.DataSource = startTimes;
				ddStart.DataTextField = "Text";
				ddStart.DataTextFormatString = "{0:HH:mm}";
				ddStart.DataValueField = "Value";
				ddStart.DataBind();
				ddFinish.DataSource = finishTimes;
				ddFinish.DataTextField = "Text";
				ddFinish.DataTextFormatString = "{0:HH:mm}";
				ddFinish.DataValueField = "Value";
				ddFinish.DataBind();
			}
		}

		protected void OnClick(object sender, EventArgs e)
		{
			IntervalItem start = default(IntervalItem);
			IntervalItem finish = default(IntervalItem);
			if (ddStart.SelectedIndex == -1 || ddFinish.SelectedIndex == -1)
				litStats.Text = "Invalid selections to perform calculations!!!";
			else
			{
				start = startTimes[ddStart.SelectedIndex];
				finish = finishTimes[ddFinish.SelectedIndex];
				litStats.Text = string.Format("Start Time = {0:HH:mm}<br />Finish Time = {1:HH:mm}<br />The calculatted difference is: {2} minutes", start.Text, finish.Text, (finish.Value - start.Value).TotalMinutes);
			}
		}
	}

	class IntervalItem
	{
		private DateTime _today;

		public string Text 
		{
			get 
			{
				if (!_today.Day.Equals(Value.Day) && Value.Hour.Equals(0) && Value.Minute.Equals(0))
					return "24:00";
				return Value.ToString("HH:mm");
			} 
		}

		public DateTime Value { get; private set; }

		public IntervalItem(DateTime today, DateTime value)
		{
			_today = today;
			Value = value;
		}
	}
}

Open in new window

Which produces the following output -Initial loadHere is our magic 24:00 (which is really just tomorrows 00:00)We've selected a 24H intervalNote: The current logic does not prevent a user from selecting a start interval that starts after a finish interval; e.g. Start = 10:30; Finish = 00:15.

I should also point out that there are most likely other ways of accomplishing this that are more in line with your goals or better overall than what has been outlined herein.

-saige-
it_saigeDeveloperCommented:
Just saw your most recent comment and wanted to show that when Start = 22:00 and Finish = 24:00 (00:00 in the second iteration of the proposed alternatives), that it does calculate 120 minutes (2H).Capture.JPGRemember that this is only working because the date time objects in the second and third alternatives, represent a distinct date/time object (using today as an example):
Start 00:00 = 6/15/2015 00:00:00 AM
Finish 00:00 [or 24:00] = 6/16/2015 00:00:00 AM

-saige-
forstersAuthor Commented:
Thank you for your comments, I can see that your examples work well; I'm wondering whether for clarity from a user perspective the addition of am & pm might be helpful - providing an array of times starting 00:00am and ending 00:00pm then there can be no confusion over which 00:00 or 24:00 we are referring to. I'll make some changes this end and see where I get to thanks all, I'll let you know.
AndyAinscowFreelance programmer / ConsultantCommented:
>>user perspective the addition of am & pm might be helpful

Since when has 23:00am or 01:00pm existed?  (Using am and pm with a 24 hour clock will not make anything clearer)
forstersAuthor Commented:
No quite...fair point
forstersAuthor Commented:
saige,

I'm just trying to replicate your first example but I'm getting an object ref error on this line:

ddStart.DataSource = startTimes;

My code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI.WebControls;
namespace EE_Q28689782
{
       
	public partial class _Default : System.Web.UI.Page
	{
		private List<DateTime> startTimes = default(List<DateTime>);
		private List<DateTime> finishTimes = default(List<DateTime>);
        
        protected void Page_Load(object sender, EventArgs e)
    {
        DropDownList ddStart = FindControl("ddStart") as DropDownList;
        DropDownList ddFinish = FindControl("ddFinish") as DropDownList;
    
        
if (!IsPostBack)
			{
				DateTime today = DateTime.Now;
				if (startTimes == null)
					startTimes = (from interval in Enumerable.Range(0, (24 * 60) / 15) let now = new DateTime(today.Year, today.Month, today.Day, 0, 0, 0).AddMinutes(15 * interval) select now).ToList();

				if (finishTimes == null)
					finishTimes = (from interval in Enumerable.Range(0, (24 * 60) / 15) let now = new DateTime(today.Year, today.Month, today.Day, 0, 0, 0).AddMinutes(15 * interval) select now).ToList();

				ddStart.DataSource = startTimes;
				ddStart.DataTextFormatString = "{0:HH:mm}";
				ddStart.DataBind();
				ddFinish.DataSource = finishTimes;
				ddFinish.DataTextFormatString = "{0:HH:mm}";
				ddFinish.DataBind();
			}
    }
    




		protected void OnClick(object sender, EventArgs e)
		{
            DropDownList ddStart = FindControl("ddStart") as DropDownList;
            DropDownList ddFinish = FindControl("ddFinish") as DropDownList;
            Literal litStats = FindControl("litStats") as Literal;

			DateTime start = DateTime.MinValue;
			DateTime finish = DateTime.MinValue;
			if (DateTime.TryParse(ddStart.SelectedValue, out start) && DateTime.TryParse(ddFinish.SelectedValue, out finish))
			{
				litStats.Text = string.Format("Start Time = {0:HH:mm}<br />Finish Time = {1:HH:mm}<br />The calculatted difference is: {2} minutes", start, finish, (finish - start).TotalMinutes);
			}
			else
			{
				litStats.Text = "Invalid selections to perform calculations!!!";
			}
		}
	}
}

Open in new window



<%@ Page Title="" Language="C#" MasterPageFile="~/FullScreenNew.master" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="EE_Q28689782._Default" %>




<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">

     <section id="overtimeform">
        <header class="bar">
            <h1>Overtime Manager</h1>
        </header>
    
        <div class="arrow-down"></div>
           
            <div class="bgimage">

                <div class="container maincontent">

                    <div class="overtimebox">
                    
                        <asp:UpdatePanel ID="UpdatePanel3" runat="server" UpdateMode="always">
                            <ContentTemplate>
    
    	<asp:Label ID="Label1" runat="server" Text="Start Time:  "></asp:Label>
	    <asp:DropDownList ID="ddStart" runat="server">
	    </asp:DropDownList>
	    <br />
	    <br />
	    <asp:Label ID="Label2" runat="server" Text="Finish Time:  "></asp:Label>
	    <asp:DropDownList ID="ddFinish" runat="server">
	    </asp:DropDownList>
	    <br />
	    <br />
	    <asp:Button ID="btnCalculate" runat="server" onclick="OnClick" 
		    Text="Calculate" />
	    <br />
	    <br />
	    <asp:Literal ID="litStats" runat="server"></asp:Literal>
    </ContentTemplate>
                            </asp:UpdatePanel>
                        </div>
                    </div>

    </div>

    </section>

</asp:Content>

Open in new window

it_saigeDeveloperCommented:
The code in Default.aspx.cs works for me.  I am not using a master page nor the ajax control tool kit.  Let me see about replicating this directly.  Is there anything special in your master page?

-saige-

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
forstersAuthor Commented:
thanks to all for assistance we have since posting the question decided to approach things differently.
AndyAinscowFreelance programmer / ConsultantCommented:
Precisely what I suggested.  :-(
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C#

From novice to tech pro — start learning today.