惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Heimdal Security Blog
小众软件
小众软件
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
罗磊的独立博客
Google DeepMind News
Google DeepMind News
大猫的无限游戏
大猫的无限游戏
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
阮一峰的网络日志
阮一峰的网络日志
A
About on SuperTechFans
宝玉的分享
宝玉的分享
博客园 - 聂微东
月光博客
月光博客
Cyberwarzone
Cyberwarzone
Microsoft Security Blog
Microsoft Security Blog
V
Visual Studio Blog
Project Zero
Project Zero
T
Tor Project blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
L
LINUX DO - 最新话题
博客园 - 叶小钗
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Attack and Defense Labs
Attack and Defense Labs
Spread Privacy
Spread Privacy
Forbes - Security
Forbes - Security
Simon Willison's Weblog
Simon Willison's Weblog
N
Netflix TechBlog - Medium
P
Proofpoint News Feed
Engineering at Meta
Engineering at Meta
Hacker News: Ask HN
Hacker News: Ask HN
I
InfoQ
M
MIT News - Artificial intelligence
AI
AI
博客园 - 三生石上(FineUI控件)
W
WeLiveSecurity
C
Check Point Blog
The Hacker News
The Hacker News
C
Cyber Attacks, Cyber Crime and Cyber Security
Application and Cybersecurity Blog
Application and Cybersecurity Blog
T
Tenable Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
The Cloudflare Blog
Blog — PlanetScale
Blog — PlanetScale
美团技术团队
D
Darknet – Hacking Tools, Hacker News & Cyber Security
GbyAI
GbyAI
Hacker News - Newest:
Hacker News - Newest: "LLM"
腾讯CDC
K
Kaspersky official blog

Blog — PlanetScale

Keeping a Postgres queue healthy — PlanetScale Patterns for Postgres Traffic Control — PlanetScale Graceful degradation in Postgres — PlanetScale High memory usage in Postgres is good, actually — PlanetScale Stripe Projects partnership: Provision PlanetScale Postgres and MySQL databases from the Stripe CLI — PlanetScale Enhanced tagging in Postgres Query Insights — PlanetScale Behind the scenes: How Database Traffic Control works — PlanetScale Introducing Database Traffic Control — PlanetScale Scaling Postgres connections with PgBouncer — PlanetScale Drizzle joins PlanetScale — PlanetScale Video Conferencing with Postgres — PlanetScale Faster PlanetScale Postgres connections with Cloudflare Hyperdrive — PlanetScale Introducing the PlanetScale MCP server — PlanetScale Database Transactions — PlanetScale Automating our changelog with Cursor commands — PlanetScale Postgres 18 is now available — PlanetScale Using MotherDuck with PlanetScale — PlanetScale $50 PlanetScale Metal is GA for Postgres — PlanetScale AI-Powered Postgres index suggestions — PlanetScale $5 PlanetScale is live — PlanetScale Announcing Vitess 23 — PlanetScale $50 PlanetScale Metal — PlanetScale Report on our investigation of the 2025-10-20 incident in AWS us-east-1 — PlanetScale $5 PlanetScale — PlanetScale Benchmarking Postgres 17 vs 18 — PlanetScale Larger than RAM Vector Indexes for Relational Databases — PlanetScale Partnering with Cloudflare to bring you the fastest globally distributed applications — PlanetScale Processes and Threads — PlanetScale PlanetScale for Postgres is now GA — PlanetScale Postgres High Availability with CDC — PlanetScale Announcing Neki — PlanetScale Caching — PlanetScale The principles of extreme fault tolerance — PlanetScale Announcing PlanetScale for Postgres — PlanetScale Benchmarking Postgres — PlanetScale Announcing Vitess 22 — PlanetScale The Real Failure Rate of EBS — PlanetScale IO devices and latency — PlanetScale Announcing PlanetScale Metal — PlanetScale PlanetScale Metal: There’s no replacement for displacement — PlanetScale Upgrading Query Insights to Metal — PlanetScale Automating cherry-picks between OSS and private forks — PlanetScale Database Sharding — PlanetScale Anatomy of a Throttler, part 3 — PlanetScale Introducing sharding on PlanetScale with workflows — PlanetScale Announcing Vitess 21 — PlanetScale Announcing the PlanetScale vectors public beta — PlanetScale Anatomy of a Throttler, part 2 — PlanetScale Instant deploy requests — PlanetScale Anatomy of a Throttler, part 1 — PlanetScale Increase IOPS and throughput with sharding — PlanetScale Tracking index usage with Insights — PlanetScale Faster backups with sharding — PlanetScale Building data pipelines with Vitess — PlanetScale The State of Online Schema Migrations in MySQL — PlanetScale Optimizing aggregation in the Vitess query planner — PlanetScale Dealing with large tables — PlanetScale Announcing Vitess 20 — PlanetScale Self-managed Vitess vs Managed Vitess with PlanetScale — PlanetScale Achieving data consistency with the consistent lookup Vindex — PlanetScale The MySQL adaptive hash index — PlanetScale Introducing global replica credentials — PlanetScale Profiling memory usage in MySQL — PlanetScale Summer 2023: Fuzzing Vitess at PlanetScale — PlanetScale How PlanetScale makes schema changes — PlanetScale Identifying and profiling problematic MySQL queries — PlanetScale The Problem with Using a UUID Primary Key in MySQL — PlanetScale Announcing Vitess 19 — PlanetScale PlanetScale forever — PlanetScale Introducing schema recommendations — PlanetScale Amazon Aurora Pricing: The many surprising costs of running an Aurora database — PlanetScale Three common MySQL database design mistakes — PlanetScale OAuth applications are now available to everyone — PlanetScale Deprecating the Scaler plan — PlanetScale PlanetScale branching vs. Amazon Aurora blue/green deployments — PlanetScale Databases at scale — PlanetScale Considerations for building a database disaster recovery plan — PlanetScale Working with Geospatial Features in MySQL — PlanetScale PlanetScale vs Amazon Aurora replication — PlanetScale Introducing the Vantage and PlanetScale integration — PlanetScale MySQL isolation levels and how they work — PlanetScale Introducing the schemadiff command line tool — PlanetScale $ pscale ping — PlanetScale Announcing foreign key constraints support — PlanetScale The challenges of supporting foreign key constraints — PlanetScale What is HTAP? — PlanetScale Introducing Insights Anomalies — PlanetScale Webhook security: a hands-on guide — PlanetScale MySQL replication: Best practices and considerations — PlanetScale A guide to HTML email with Ruby on Rails and Tailwind CSS — PlanetScale Sharding for cost-effective database management — PlanetScale PlanetScale ranks 188th in Deloitte’s top 500 fastest-growing companies — PlanetScale Announcing the Fivetran integration — PlanetScale Introducing webhooks — PlanetScale What is MySQL replication and when should you use it? — PlanetScale Sync user data between Clerk and a PlanetScale MySQL database — PlanetScale Introducing database reports — PlanetScale Distributed caching systems and MySQL — PlanetScale What is MySQL partitioning? — PlanetScale MySQL High Availability: Connection handling and concurrency — PlanetScale
Datetimes versus timestamps in MySQL — PlanetScale
Aaron Francis · 2023-06-22 · via Blog — PlanetScale

Aaron Francis |

There are several different ways to store dates and times in MySQL, and knowing which one to use requires understanding what you'll be storing and how MySQL handles each type.

There are five column types that you can use to store temporal data in MySQL. They are:

  • DATE
  • DATETIME
  • TIMESTAMP
  • YEAR
  • TIME

Each column type stores slightly different data, has different minimum and maximum values, and requires different amounts of storage.

In the table below, you'll see each column type and their various attributes.

| Column    | Data        | Bytes | Min                 | Max                 |
|-----------|-------------|-------|---------------------|---------------------|
| DATE      | Date only   | 3     | 1000-01-01          | 9999-12-31          |
| DATETIME  | Date + time | 8     | 1000-01-01 00:00:00 | 9999-12-31 23:59:59 |
| TIMESTAMP | Date + time | 4     | 1970-01-01 00:00:00 | 2038-01-19 03:14:17 |
| YEAR      | Year only   | 1     | 1901                | 2155                |
| TIME      | Time only   | 3     | -838:59:59          | 838:59:59           |

Dates, years, and times

Based on this table, the first question you must ask yourself is: "What kind of data do I need to store?"

The DATE column type

If you are storing a date only, with no time information, the choice is easy! You would use the DATE column. This column is helpful for things like birthdays, anniversaries, employee start dates, etc. The DATE column is a no-fuss affair: it stores dates.

It can store a massive range, from the beginning of the year 1000 to the end of the year 9999, in a minimal footprint, only 3 bytes.

The YEAR column type

Likewise, if you're storing a year with no date information, there is a unique column just for that: the YEAR column. This column is not widely used, but it serves its purpose exceedingly well when you need it. The YEAR column is compact at only 1 byte, but the range is not very large, from 1901 to 2155. If you need a wider range, you'd probably migrate to a signed or unsigned small integer, depending on your needs.

The TIME column type

Finally, rounding out the single-purpose column types is the TIME column. The time column stores time only, in the hhh:mm:ss format. The legal range of this column is much wider than 00:00:00 to 23:59:59 because you can use it to store intervals of time and wall-clock time. The valid range spans from -838:59:59 to 838:59:59, approximately 35 days in either direction.

If you are storing a time or duration irrespective of date, the TIME column is made for that. If you are storing a date and time together, you should use either the DATETIME or TIMESTAMP columns to keep it as one logical unit instead of splitting it into two columns.

DATETIMEs and TIMESTAMPs both serve a similar purpose: storing a reference to a specific point in time. If you were tasked with storing a reference to February 14th, 2029, at 8:47am, you could use either type to satisfy that requirement!

Again, the question of whether to use a DATETIME or TIMESTAMP in MySQL depends on what you are trying to do. Neither is inherently bad, and neither is inherently good.

The first difference is that the storage size for a TIMESTAMP is 4 bytes, which is half the size of a DATETIME at 8 bytes. Storage space is cheap, but when designing table schemas, we always want to choose the smallest possible column type that fits the full range of our data. When creating your tables, there is no need to be generous!

Because the storage size of the TIMESTAMP is much smaller than the DATETIME, the range of legal values is likewise much smaller.

The 2038 problem in MySQL

A TIMESTAMP ranges from 1970-01-01 00:00:00 to 2038-01-19 03:14:17. The year 2038 might sound familiar to you! This is one incarnation of the famous Year 2038 Problem. You may have also seen it written as Y2038, Y2K38, or even The Epochalypse, which should be credited for its clever wordplay.

The 2038 issue arises in systems that calculate Unix time, defined as the seconds that have passed since the Unix epoch at 00:00:00 UTC on January 1, 1970. These systems use a signed 32-bit integer to store this time, which can only hold integer values between -2^31 and 2^31 - 1. The maximum timestamp that can be accurately represented corresponds to 2^31 - 1 seconds after the epoch, which is 03:14:07 UTC on January 19, 2038.

For our purposes, this immediately eliminates TIMESTAMP as a contender for storing dates in the far future. If there is even a reasonable chance that you might need to store dates beyond 2038, it's best to use a DATETIME.

For now, there are instances where a TIMESTAMP is perfectly adequate! One such scenario is when you are recording the current time when an action takes place. Because we're still more than a decade away from the year 2038, it's a perfectly reasonable choice to use TIMESTAMP for columns like:

  • updated_at
  • created_at
  • deleted_at
  • archived_at
  • posted_at

These columns are usually populated by your application. As long as these columns record the current time at which an event happened, you don't have to worry about the 2038 problem for a long time. And surely, by then, we'll have a solution for it. (Surely, right?)

When to use DATETIME

Given the relatively narrow range of legal values for a TIMESTAMP column, you should consider a DATETIME for any datetime where you might need to populate a date outside the 1970 to 2038 range. If the field is open to user input, you'll likely want to use a DATETIME or validate that the input falls within the 1970-2038 window for a TIMESTAMP.

Timezone treatment of DATETIME versus TIMESTAMP in MySQL

The storage size and the legal range are the most significant, most obvious differences between the DATETIME and TIMESTAMP columns, but there is one slightly more pernicious difference: timezones. Timezones are the bane of almost every developer's existence, and you're not free from them in MySQL either.

The DATETIME column does absolutely nothing concerning timezones. If you write a value of 2029-02-14 08:47 into the database, you will always and forever receive a value of 2029-02-14 08:47. No matter what your server or connection timezones are set to, you'll always get 2029-02-14 08:47 back.

TIMESTAMP on the other hand, tries to "help you out" by always converting to and from UTC. From the documentation:

MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the current time zone for retrieval. (This does not occur for other types such as DATETIME.) By default, the current time zone for each connection is the server's time.

Let's do a small example to prove this. We will create a table with DATETIME and TIMESTAMP columns and insert some data.

CREATE TABLE timezone_test (
    `timestamp` TIMESTAMP,
    `datetime` DATETIME
);

Now we'll explicitly set our connection timezone to UTC and insert 2029-02-14 08:47:

SET SESSION time_zone = '+00:00';

INSERT INTO timezone_test VALUES ('2029-02-14 08:47', '2029-02-14 08:47');

SELECT * FROM timezone_test;

-- | timestamp           | datetime            |
-- |---------------------|---------------------|
-- | 2029-02-14 08:47:00 | 2029-02-14 08:47:00 |

Looking good so far; the value we inserted is the value we got back! Let's change our session timezone to -05:00 now and see what happens:

SET SESSION time_zone = '-05:00';
SELECT * FROM timezone_test;

-- | timestamp           | datetime            |
-- |---------------------|---------------------|
-- | 2029-02-14 03:47:00 | 2029-02-14 08:47:00 |

You'll notice that the timestamp column has shifted five hours, while the datetime column remains the same. In practice, this shouldn't matter too much, as hopefully your server and connection timezones are always set to UTC, but if they aren't, you might be in for a big surprise when the values you put in the database are not the values you get back out.

Hopefully this helps demystify the differences between all of the columns you can use to store temporal data in MySQL! If you'd like to watch a video on the same topic, you can find that and much more in our free MySQL for Developers course.