#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
/*
Compare two dates in C
----------------------
This program demonstrates how to compare two dates using only the C standard library.
It uses a modular design, clear comments, and a full test suite.
Concepts:
- Parsing dates safely (YYYY-MM-DD)
- Representing dates with a struct
- Comparing dates lexicographically (year → month → day)
- Handling invalid formats
- Edge‑case testing
Architecture notes:
- A dedicated function handles parsing.
- Another function performs comparison.
- Main runs multiple predefined test cases.
- No dynamic memory allocation except small automatic buffers.
- No external dependencies.
Performance notes:
- Comparisons are O(1).
- Parsing is fast and predictable.
- Memory usage is minimal.
Pitfalls:
- Invalid date strings must be handled.
- Comparing raw strings is unsafe; always convert to a structured type.
- No timezone logic here; this is pure date comparison.
*/
typedef struct {
int year;
int month;
int day;
} Date;
/*
Safely parse a date string in the format YYYY-MM-DD.
Error handling:
- Returns false if the date is invalid.
- Writes parsed values into the Date struct when valid.
*/
bool parseDate(const char *s, Date *out) {
int y, m, d;
char dash1, dash2;
if (sscanf(s, "%d%c%d%c%d", &y, &dash1, &m, &dash2, &d) != 5) {
return false;
}
if (dash1 != '-' || dash2 != '-') {
return false;
}
if (m < 1 || m > 12) return false;
if (d < 1 || d > 31) return false; /* Simplified; not checking month lengths */
out->year = y;
out->month = m;
out->day = d;
return true;
}
/*
Compare two Date objects.
Returns:
- "earlier"
- "later"
- "equal"
*/
const char* compareDates(const Date *a, const Date *b) {
if (a->year < b->year) return "earlier";
if (a->year > b->year) return "later";
if (a->month < b->month) return "earlier";
if (a->month > b->month) return "later";
if (a->day < b->day) return "earlier";
if (a->day > b->day) return "later";
return "equal";
}
/*
Run a single test case:
- Parse both dates
- Handle invalid input
- Compare if valid
*/
void runTestCase(const char *d1, const char *d2) {
Date a, b;
bool ok1 = parseDate(d1, &a);
bool ok2 = parseDate(d2, &b);
if (!ok1 || !ok2) {
printf("Compare '%s' vs '%s' → invalid date format\n", d1, d2);
return;
}
const char *result = compareDates(&a, &b);
printf("Compare '%s' vs '%s' → %s\n", d1, d2, result);
}
/*
Main test suite:
- Multiple test cases
- Includes edge cases
- Prints results cleanly
*/
int main(void) {
printf("Date comparison tests:\n\n");
const char *tests[][2] = {
{"2024-01-01", "2024-01-02"}, /* earlier */
{"2024-01-02", "2024-01-01"}, /* later */
{"2024-01-01", "2024-01-01"}, /* equal */
{"1999-12-31", "2000-01-01"}, /* millennium boundary */
{"2024-02-29", "2024-03-01"}, /* leap year (not validated strictly) */
{"2024-02-29", "2023-02-28"}, /* leap vs non-leap */
{"2024-13-01", "2024-01-01"}, /* invalid month */
{"2024-00-10", "2024-01-01"}, /* invalid month */
{"2024-01-32", "2024-01-01"}, /* invalid day */
{"abcd-ef-gh", "2024-01-01"}, /* invalid format */
{"2024-01-01", "abcd-ef-gh"}, /* invalid format */
};
size_t count = sizeof(tests) / sizeof(tests[0]);
for (size_t i = 0; i < count; ++i) {
runTestCase(tests[i][0], tests[i][1]);
}
return 0;
}
/*
run:
Date comparison tests:
Compare '2024-01-01' vs '2024-01-02' → earlier
Compare '2024-01-02' vs '2024-01-01' → later
Compare '2024-01-01' vs '2024-01-01' → equal
Compare '1999-12-31' vs '2000-01-01' → earlier
Compare '2024-02-29' vs '2024-03-01' → earlier
Compare '2024-02-29' vs '2023-02-28' → later
Compare '2024-13-01' vs '2024-01-01' → invalid date format
Compare '2024-00-10' vs '2024-01-01' → invalid date format
Compare '2024-01-32' vs '2024-01-01' → invalid date format
Compare 'abcd-ef-gh' vs '2024-01-01' → invalid date format
Compare '2024-01-01' vs 'abcd-ef-gh' → invalid date format
*/