Inserting a Python datetime.datetime object into MySQL
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Inserting a Python datetime.datetime object into MySQL is usually straightforward if you use a proper database driver and parameterized SQL. The driver can convert the Python object into the SQL representation MySQL expects. The real decisions are about column type, timezone handling, and avoiding manual string formatting that creates subtle bugs.
Use Parameterized Queries and Let the Driver Convert the Value
The safest approach is to pass the datetime object as a query parameter rather than formatting it into the SQL string yourself.
With mysql-connector-python, a basic example looks like this:
The important part is the %s placeholders plus the tuple of values. The connector handles the conversion from Python's datetime object to a MySQL-compatible datetime literal.
Choose Between DATETIME and TIMESTAMP
In MySQL, the usual storage choices are DATETIME and TIMESTAMP.
A simple table might be:
The practical difference is:
- '
DATETIMEstores a calendar value as given' - '
TIMESTAMPis more tied to timezone conversion behavior inside MySQL'
If your application works across time zones, decide explicitly whether you want MySQL to perform timezone-aware conversions or whether you want to store normalized UTC values yourself.
Prefer UTC for Cross-Time-Zone Systems
Naive local timestamps become painful once services, jobs, or users span time zones. A common pattern is to generate timezone-aware UTC datetimes in Python and store them consistently.
If your driver and schema are configured sensibly, this makes the meaning of stored values much easier to preserve across systems.
The more distributed the system becomes, the more valuable this discipline becomes.
Avoid Manual String Formatting
A common anti-pattern is building SQL like this:
That is a bad habit for two reasons:
- it gives up the driver's type handling
- it encourages unsafe SQL construction in general
Even if the datetime string seems harmless, parameterized queries are the correct habit because they solve both formatting and SQL-injection concerns consistently.
Reading the Value Back Confirms the Round Trip
It is often useful to verify that the inserted value round-trips correctly.
If you are debugging timezone behavior, do this immediately after inserting a known timestamp so you can compare the Python-side value with the database-side result.
pymysql and Other Drivers Work Similarly
The exact connection API changes by library, but the rule stays the same: pass the datetime as a bound parameter.
A pymysql example is almost identical:
So the key idea is independent of any one driver: use parameters, not string interpolation.
Watch Naive Versus Aware Datetimes
Python distinguishes between naive datetimes, which have no timezone information, and aware datetimes, which do. MySQL does not magically fix ambiguous application logic for you.
If one part of the system writes local naive times and another part assumes UTC, the database will happily store both and the resulting confusion will look like random time shifts later.
That is why a consistent time policy is part of correct insertion logic, not an optional cleanup step.
Common Pitfalls
The most common mistake is formatting the datetime into the SQL string manually instead of passing it as a parameter. That throws away the driver's conversion logic.
Another mistake is mixing DATETIME, TIMESTAMP, local time, and UTC without deciding which semantics the application actually needs.
Developers also forget that Python naive datetimes do not carry timezone meaning, even though the printed value looks complete.
Summary
- Use parameterized queries and pass Python
datetimeobjects directly to the MySQL driver. - Let the connector handle conversion instead of formatting the SQL string manually.
- Choose
DATETIMEorTIMESTAMPdeliberately based on your time-handling needs. - Prefer UTC for systems that cross time zones.
- The hard part is usually timezone semantics, not the insertion syntax itself.

