VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
DATE (date only), TIME (time only), DATETIME (date + time, no timezone), and TIMESTAMP (date + time, stored in UTC, displayed in session timezone). See Timestamps and Time Zones in MySQL for timezone handling details.
Getting the Current Date and Time
NOW() is evaluated once at the start of a statement — all rows in the same INSERT get the same timestamp. SYSDATE() is evaluated each time it’s called.
Formatting Dates
DATE_FORMAT converts a date or datetime to a string using a format string:
| Specifier | Meaning | Example |
|---|---|---|
%Y | 4-digit year | 2024 |
%y | 2-digit year | 24 |
%m | Month (01–12) | 06 |
%M | Month name | June |
%d | Day (01–31) | 15 |
%H | Hour (00–23) | 14 |
%i | Minute (00–59) | 30 |
%s | Second (00–59) | 00 |
%W | Weekday name | Saturday |
%w | Weekday (0=Sunday) | 6 |
%j | Day of year (001–366) | 167 |
%U | Week number (0–53, week starts Sunday) | 24 |
Parsing Strings to Dates
STR_TO_DATE converts a string to a date using the same format specifiers:
Date Arithmetic
DATE_ADD / DATE_SUB — add or subtract an interval:SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR.
Shorthand with + and - operators:
DATEDIFF only counts days, not time. For time-aware differences, use TIMESTAMPDIFF:
TIMESTAMPDIFF(unit, from, to) — note that from comes before to.
Extracting Date Parts
EXTRACT / YEAR / MONTH / DAY:Truncating to a Period
To group data by month, week, or day, truncate the datetime to the period boundary:Unix Timestamps
Common Patterns
Records from the last 30 days:Frequently Asked Questions
What’s the difference between NOW() and SYSDATE()?
NOW() returns the timestamp when the statement began executing — all rows in a single INSERT or UPDATE get the same value. SYSDATE() returns the actual clock time at the moment it’s called, so rows inserted in a loop get different values. For audit timestamps where consistency within a transaction matters, NOW() is almost always the right choice.
Why does DATE_ADD with INTERVAL 1 MONTH behave oddly at month-end?
MySQL clamps to the last valid day.DATE_ADD('2024-01-31', INTERVAL 1 MONTH) returns 2024-02-29 (leap year) or 2024-02-28. This is expected behavior — there’s no “31st of February.” If you need predictable month arithmetic, truncate to the start of the month first.
Troubleshooting
| Problem | Solution |
|---|---|
STR_TO_DATE returns NULL | Format string doesn’t match the input — verify each format specifier matches its corresponding input character |
DATEDIFF returns 0 for timestamps on the same date | DATEDIFF ignores the time component — two rows on the same calendar date return 0 |
| Date comparison misses rows at end of day | WHERE created_at <= '2024-06-15' stops at midnight — use < '2024-06-16' to include the full day |
TIMESTAMPDIFF returns unexpected negative value | Arguments are in wrong order — TIMESTAMPDIFF(unit, from, to), not (unit, to, from) |
WEEK() returns different numbers than expected | Week numbering mode matters (Sunday vs Monday start) — use YEARWEEK(date, 3) for ISO 8601 week numbers |

