Constraining time fields in form designs

This article accompanies this sample form. Please read the following and test the sample form. Either save a copy of the sample form in your Google Drive or download as an Excel workbook. For this article, read about the format-date-time() and decimal-time() functions in the documentation.

There are often times where you need to use a time type field in your form, and you need to constrain it to only accept certain answers. For example, if someone works from 9:00 to 17:00, and you want to know what time they take their lunch break, you would want to constrain the time field so it only accepts times between 9:00 and 17:00.

In this article, we will be using non-DST (daylight saving time) time zones. For example, even if you are reading this article in the summer, the time zone for Boston is given as UTC-5 instead of UTC-4. Times are given in 24-hour format.

Using the format-date-time() function

The most straightforward way to constrain the time is with the format-date-time() function. You can combine the hour and minute, turn them into a number, and then compare that to the expected time. For example, if you wanted to make sure the time entered is before 9:00, you can use this constraint:

number(format-date-time(., '%h%M')) <= 900

The format-date-time() function would turn 09:00 into 900, and compare it to 900 to make sure the time entered is at or before 9:00.

How web forms are different

The format-date-time() function works well when collecting data in the field in SurveyCTO Collect mobile app (both Android and iOS), since the mobile app uses the time zone of the device. However, in web forms, the time entered is always converted to UTC time, meaning it will need to be adjusted before being used in a constraint expression. For example, if 8:00 were to be entered in Boston EST (UTC-5), and checked against the above constraint, it would not be accepted, since 8:00 EST is 13:00 UTC, and that is not before 9:00. Luckily, there are other methods you can use.

If you would like to check if a form is being completed in web forms, use the expression:
${deviceid} = '(web)'

That expression will only be "true" when the form is completed in a web form.

Using the decimal-time() function

For this section, check out the Constraint example group in the sample form.

The decimal-time() function uses the time entered before it is converted to UTC time, so it is often better to use this function in your constraint instead of format-date-time(). This makes it great for both mobile data collection and web forms. With decimal-time(), times are converted to a decimal number representing time passed in the day, with 0.25 representing 6:00, 0.50 for 12:00 noon, and so on. So, if you wanted to make sure the time entered is after 12:00 in local time in SurveyCTO Collect or web forms, you can use this constraint:

decimal-time(.) >= 0.5

Something to keep in mind is that, even though you do not see it, time type fields store both the current second and milliseconds. Since neither seconds nor milliseconds are entered, the seconds and milliseconds of the current time is used. For example, if you enter 9:00 into a time type field at 15:43:57.652, then the decimal-time of that field will be 0.3756672685185369 instead of just 0.375 (0.375 for 9:00, and 0.0006672685185369 for the 57.652 seconds). This may not seem like much, but 0.3756672685185369 is still greater than 0.375, so decimal-time(.) <= 0.375 will not accept 9:00 as an answer. There are two ways around this:

Method 1: Add 0.001 to the before-time

You can add 0.001 to the constraint time that the entered time is supposed to be before. For example, if the time entered is supposed to be before or at 9:00, you can use the constraint:

decimal-time(.) <= 0.376

Even if the time entered is 9:00, and it is entered at 18:00:59.999, the decimal-time value will be 0.3756944328703963 (0.375 for the 9:00, and 0.0006944328703963 for the 59.999 seconds), which is still less than 0.376, so it will be accepted.

Something to keep in mind is that if someone were to enter 9:01 at 17 seconds or less after the minute, then 9:01 will be saved, even though you wanted a time at or before 9:00. For example, entering 9:01 at 15:43:15 will result in a decimal-time of 0.3758680555555555 (0.3756944444444444 for the 9:01, and 0.0001736111111111 for the 15 seconds), which is technically still less than 0.376, so 9:01 will be saved. This is an unlikely scenario, but it should be noted.

Method 2: Round the decimal-time down

Another method is to use rounding in order to drop the seconds and milliseconds parts of the decimal-time. Here is an example of that, with a constraint checking to make sure the time entered is before 9:00:

(int(int(decimal-time(.)*1440) div 1.44) div 1000) <= 0.375

The expression is complex, involving two round-downs, but it accepts 9:00:59.999, and rejects 9:01:00.000, so there is no worry about seconds or milliseconds. Feel free to copy this constraint to use in your own field constraints, replacing 0.375 with the decimal-time you need.

Note: 1440 is used in that constraint expression because there are 1,440 minutes in one day. One of the int() functions is for dropping the seconds and milliseconds, and the other is for rounding down to the nearest thousandth so long decimal numbers do not have to be used in the constraint.

For a table with the decimal values of hours, minutes, and units, check out this spreadsheet.

Using select_one fields

You can also use select_one fields to collect the time. One field can be integers from 1-24, and the other can be integers from 0-59 (it is a good idea to give these fields the "minimal" appearance). The hour and minute fields can be on the same page using a field list. Keep in mind that these times will not be adjusted during data export, but sometimes, that is what you are looking for.

Displaying the correct time in web forms

For this section, check out the Displaying the time group in the sample form.

Sometimes, you may need to display the time for the respondent (from the above example, "Your lunchtime break is at ${lunchtime}, so what time is X?"). But if you were to do so in a web form, it would show the UTC version of the time, not the local time. If you would like to display the time entered in a web form, you can use the decimal-time() function to calculate the local time. To learn how, check out the Displaying the time group in the sample form.

Retrieve time zone

Sometimes, you may want to record the time zone of the respondent completing a web form. You can ask for the time zone, but in web forms, you can also record it automatically. If you would like to do this, check out this sample form.

Related: Exporting data in different time zones. For more on the functions discussed in this article, refer to the product documentation.

Do you have thoughts on this support article? We'd love to hear them! Feel free to fill out this feedback form.


Please sign in to leave a comment.