Great work!

XP to next level

BugEater

Restricting Dates: Past or Future?

Learning Objectives

By the end of this lesson you will be able to:

  • Distinguish between server-side and client-side date restriction and explain which is authoritative
  • Test birth date fields that must not accept future dates
  • Test booking date fields that must not accept past dates
  • Identify the off-by-one error that occurs at the boundary between past and future (midnight)
  • Explain the timezone edge case where a "future" date for the client is a "past" date on the server

Two Common Restrictions

Date fields in most applications fall into one of two restriction categories:

Field type Rule Example
Birth date Must not be in the future Cannot be born tomorrow
Booking / appointment Must not be in the past Cannot book yesterday's slot

These sound simple, but they hide several subtle edge cases that trip up even experienced developers.

Server-Side vs Client-Side Enforcement

HTML5 provides min and max attributes for <input type="date">, and JavaScript can add additional client-side validation. However, client-side restrictions are presentational, not authoritative. A user can disable JavaScript, use developer tools to remove the max attribute, or send a raw HTTP request bypassing the UI entirely.

The only reliable validation is server-side. A QA tester must test both layers:

  1. Does the UI prevent obviously invalid dates? (usability)
  2. Does the server reject invalid dates sent directly? (security and correctness)

A critical finding is when the server accepts a future birth date even though the UI blocked it.

The Off-by-One at Midnight

Suppose a booking field requires a date "not in the past". What about today? This is ambiguous — "today" is simultaneously not in the past and not in the future. Most systems intend to accept today, but the implementation matters.

If the server compares the submitted date against LocalDate.now() using strict less-than (<), today is accepted. But if it uses less-than-or-equal (<=), today is rejected. This is a classic off-by-one error at the boundary.

The midnight transition makes this worse. A test that passes at 11:00 AM may fail at 11:59 PM if the server's "today" has moved forward. Always test with fixed dates, not relative ones.

Timezone Edge: "Tomorrow" in UTC+12

Consider a user in New Zealand (UTC+12) submitting a booking for their local "today". In UTC, that same moment may already be yesterday or two days from now depending on the time. From the server's perspective (running in UTC), the user's "today" might be "tomorrow".

This causes false rejections: valid bookings are refused because the server thinks the date is in the future. The fix is for the server to interpret submitted dates in the user's stated timezone before comparing. The test case: a user in UTC+12 submits a date that is "today" in their timezone at 23:00 UTC+12 (11:00 UTC). The server must accept it.

Testing Strategy

For birth date (no future):

Test case Input Expected
Today today's date Accept
Yesterday today − 1 day Accept
Tomorrow today + 1 day Reject
Far past 1900-01-01 Accept (if no min age rule)
Far future 2099-12-31 Reject

For booking date (no past), swap Accept/Reject for past and future rows.

Always use fixed dates in test scripts rather than new Date() to ensure reproducibility. Pin the clock in unit tests and use fixed date strings in API-level tests.

Summary

Past/future date restrictions seem trivial but contain three subtle failure points: the difference between client and server enforcement, the off-by-one error at today's boundary, and timezone disagreement about what "today" actually means. A thorough QA strategy tests all three layers: UI, server API, and timezone-aware edge cases.

Quiz

A user submits a birth date of "tomorrow" directly via an API call, bypassing the UI. Which layer is responsible for catching this?

A booking system displays a date picker that blocks past dates. A tester submits yesterday's date using a raw HTTP request tool. The server accepts it. What is the severity of this finding?

A booking field requires a date "not in the past". The tester submits today's date at 23:58 and it is accepted. The same test submitted at 00:01 the next day is rejected. What is this bug called?

For a birth date field, which test case is the most important boundary value to verify?