A Classic ASP form can collect year, month and day separately, then validate them on the server before creating a Date value. This prevents ambiguous date strings and rejects impossible dates such as February 31.
<%
Dim yearNo, monthNo, dayNo, candidate, validDate
yearNo = 2024: monthNo = 2: dayNo = 29
validDate = False
If monthNo >= 1 And monthNo <= 12 And dayNo >= 1 And dayNo <= 31 Then
candidate = DateSerial(yearNo, monthNo, dayNo)
validDate = (Year(candidate) = yearNo And Month(candidate) = monthNo And Day(candidate) = dayNo)
End If
Response.Write validDate
%>
Output: True. February 29 exists in 2024. In an actual form, validate that the input contains integers before performing these comparisons.
| Check | Reason |
|---|---|
| Submitted using POST | Only process when the form is submitted |
| Whole-number text | Reject decimals, signs and non-numeric characters |
| Year, month and day ranges | Require year 1000–9999, month 1–12 and day 1–31 |
| DateSerial round-trip | Reject impossible combinations such as February 30 |
| Output encoding | Encode any user-provided text before including it in HTML |
Save this complete example as an .asp page on IIS. It validates user input on the server, then displays the resulting date in a numeric year-month-day format. It uses RegExp to reject non-integer input before converting it.
<%@ Language=VBScript %>
<% Option Explicit %>
<%
Dim submitted, monthText, dayText, yearText
Dim monthNo, dayNo, yearNo, myDate, validDate
Dim digits, yearDigits, m, d
submitted = (Request.Form("todo") = "submit")
validDate = False
If submitted Then
monthText = Trim(Request.Form("month"))
dayText = Trim(Request.Form("day"))
yearText = Trim(Request.Form("year"))
Set digits = New RegExp
digits.Pattern = "^[0-9]{1,2}$"
Set yearDigits = New RegExp
yearDigits.Pattern = "^[0-9]{4}$"
If digits.Test(monthText) And digits.Test(dayText) And yearDigits.Test(yearText) Then
monthNo = CInt(monthText)
dayNo = CInt(dayText)
yearNo = CInt(yearText)
If yearNo >= 1000 And yearNo <= 9999 And _
monthNo >= 1 And monthNo <= 12 And _
dayNo >= 1 And dayNo <= 31 Then
myDate = DateSerial(yearNo, monthNo, dayNo)
validDate = (Year(myDate) = yearNo And _
Month(myDate) = monthNo And Day(myDate) = dayNo)
End If
End If
If validDate Then
Response.Write "<p>Valid date: " & Year(myDate) & "-" & _
Right("0" & Month(myDate), 2) & "-" & _
Right("0" & Day(myDate), 2) & "</p>"
Else
Response.Write "<p>Please enter a valid date.</p>"
End If
End If
%>
<!doctype html>
<html><head><title>Validate a date</title></head><body>
<form method="post" action="">
<input type="hidden" name="todo" value="submit">
<label>Month <select name="month" required>
<% For m = 1 To 12 %>
<option value="<%=m%>"><%=MonthName(m)%></option>
<% Next %>
</select></label>
<label>Day <select name="day" required>
<% For d = 1 To 31 %>
<option value="<%=d%>"><%=d%></option>
<% Next %>
</select></label>
<label>Year <input type="number" name="year" min="1000" max="9999" value="2024" required></label>
<button type="submit">Validate date</button>
</form>
</body></html>
The form purposely uses a full four-digit year, and the server validates every field even though the browser controls also specify ranges. Month and day selections do not imply that the combination is valid.
| Submitted values | Result |
|---|---|
| 2024 / 2 / 29 | Valid — leap day |
| 2023 / 2 / 29 | Invalid — not a leap year |
| 2026 / 4 / 31 | Invalid — April has 30 days |
| 2026 / 13 / 1 | Invalid — month out of range |
| 2026 / 2.5 / 10 | Invalid — not a whole-number month |
| 2026 / 2 / blank | Invalid — missing day |
<%
Dim monthNo, dayNo, yearNo, myDate
monthNo = 2: dayNo = 31: yearNo = 2024
myDate = DateSerial(yearNo, monthNo, dayNo)
Response.Write Month(myDate) & "/" & Day(myDate) & "/" & Year(myDate)
%>
3/2/2024
The function returned March 2 rather than rejecting February 31. Compare the resulting year, month, and day to the submitted numbers to detect the overflow.
IsDate() is designed to check whether a value can be recognized as a date under the current regional settings. It is not an exact validator for three separately submitted numeric components.
Do not rely on HTML min, max or required attributes alone. Attackers can bypass browser checks. Reject malformed input server-side, avoid displaying raw submitted values, and never concatenate unvalidated form values into a SQL query.
An overflow error typically means a value was converted to a numeric type with a smaller range than expected. A type mismatch often indicates that a value was converted before its format was validated. Use fixed numeric input rules before calling CInt or DateSerial().
They avoid ambiguity around how two-digit year values are interpreted.
No. It rolls over into May; the validation must compare its components.
You can add client-side assistance, but always perform authoritative validation on the ASP server.
Specify a format and parse its numeric components explicitly rather than relying on locale-dependent text parsing.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.