{"id":106629,"date":"2025-06-03T07:01:00","date_gmt":"2025-06-03T07:01:00","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=106629"},"modified":"2025-05-07T19:20:35","modified_gmt":"2025-05-07T19:20:35","slug":"mysql-vs-postgresql-date-and-time-data-types","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/mysql\/mysql-vs-postgresql-date-and-time-data-types\/","title":{"rendered":"MySQL vs. PostgreSQL: Date and Time Data Types"},"content":{"rendered":"\n<p>Date and time data types are important because they help track and manage time-based information in databases. This includes things like recording when orders are placed, scheduling events, or calculating the time between two activities. In this article, we will look at differences between how PostgreSQL and MySQL stores and utilizes date and time datatypes.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"1920\" height=\"1080\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106629-1.jpeg\" alt=\"\" class=\"wp-image-106630\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106629-1.jpeg 1920w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106629-1-300x169.jpeg 300w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106629-1-1024x576.jpeg 1024w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106629-1-768x432.jpeg 768w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/word-image-106629-1-1536x864.jpeg 1536w\" sizes=\"auto, (max-width: 1920px) 100vw, 1920px\" \/><\/figure>\n\n\n\n<p>\n  \n<\/p>\n\n\n\n<p>MySQL and PostgreSQL offer several data types that can be used for handling dates and times. These data types provide the tools to store and manage information like dates of a particular event, timestamps, and even time durations. While they both share some similarities on how they handle date and time, there are key differences in how they handle precision, time zones, and date\/time calculations.<\/p>\n\n\n\n<p>Getting date and time data right is key for keeping databases accurate and useful. In this article, we will compare how MySQL and PostgreSQL handle date and time data, their differences, strengths, and which one might work better for your needs. By the end, you\u2019ll have a clearer idea of which database to choose for managing date and time information.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-mysql-date-and-time-data-types\"><a id=\"post-106629-_dd79s1kuyipk\"><\/a>MySQL Date and Time Data Types<\/h2>\n\n\n\n<p>MySQL is quite flexible when it comes to accepting date and time values. It provides five main date and time data types, which are, <code>DATE<\/code>, <code>DATETIME<\/code>, <code>TIMESTAMP<\/code>, <code>TIME<\/code>, and <code>YEAR<\/code>. However, these data types must follow a specific accepted format to ensure the values are correctly stored in the database. Here&#8217;s a breakdown of the format MySQL expects for its following date and time values.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><p><strong>Data Type<\/strong><\/p><\/td><td><p><strong>Expected Format<\/strong><\/p><\/td><td><p><strong>Example Values<\/strong><\/p><\/td><td><p><strong>Storage size<\/strong><\/p><\/td><\/tr><tr><td><p><code>DATE<\/code><\/p><\/td><td><p>YYYY-MM-DD<\/p><\/td><td><p>2025-02-14<\/p><\/td><td><p>3 bytes<\/p><\/td><\/tr><tr><td><p><code>DATETIME<\/code><\/p><\/td><td><p>YYYY-MM-DD HH:MM:SS<\/p><\/td><td><p>2025-02-14 10:30:45<\/p><\/td><td><p>8 bytes<\/p><\/td><\/tr><tr><td><p><code>TIMESTAMP<\/code><\/p><\/td><td><p>YYYY-MM-DD HH:MM:SS<\/p><\/td><td><p>2025-02-14 10:30:45<\/p><\/td><td><p>4 bytes<\/p><\/td><\/tr><tr><td><p><code>TIME<\/code><\/p><\/td><td><p>HH:MM:SS<\/p><\/td><td><p>10:30:45<\/p><\/td><td><p>3 bytes<\/p><\/td><\/tr><tr><td><p><code>YEAR<\/code><\/p><\/td><td><p>YYYY<\/p><\/td><td><p>2025<\/p><\/td><td><p>1 byte<\/p><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>You are also allowed to include fractional seconds (up to 6 digits) into the <code>DATETIME<\/code> and <code>TIMESTAMP<\/code> values. Values are enclosed in quoted strings during insertion. Here is an example of what this would look like:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">CREATE TABLE events (\n    event_id INT AUTO_INCREMENT PRIMARY KEY,\n    event_time DATETIME NOT NULL,  -- Stores exact date and time\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP  -- Auto-stores insert time in UTC\n);<\/pre><\/div>\n\n\n\n<p>Then create a value using an <code>INSERT<\/code> statement:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">INSERT INTO events (event_time) VALUES ('2025-02-14 10:30:45.123456');<\/pre><\/div>\n\n\n\n<p>If you insert a value that doesn\u2019t follow the expected format, MySQL handles it based on the <code>sql_mode<\/code> setting. In the <code>STRICT_TRANS_TABLES<\/code> mode, dates are checked strictly. You can check the setting value using:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">SHOW VARIABLES LIKE 'sql_mode';<\/pre><\/div>\n\n\n\n<p>By default, this will look something like this:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"wrap:true lang:tsql highlight:0 decode:true block\" >'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'<\/pre><\/div>\n\n\n\n<p>And if there is not a value \u2018<code>STRICT_TRANS_TABLES<\/code>\u2019 (which there is in my example) then you can set it for your connection using the following statement (which will preserve all other settings):<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">set sql_mode = CONCAT(@@sql_mode,',STRICT_TRANS_TABLES');<\/pre><\/div>\n\n\n\n<p>Note: Beware that <code>sql_mode<\/code> pertains to more than just date format handling, so check out <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.0\/en\/sql-mode.html\">this article<\/a> in the MySQL docs before using.<\/p>\n\n\n\n<p>When MySQL encounters an invalid date format, it does the following:<\/p>\n\n\n\n<p><strong>Strict Mode (STRICT_TRANS_TABLES):<\/strong> If strict mode is enabled (default in newer MySQL versions), MySQL rejects invalid dates and throws an error. For example:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">INSERT INTO events (event_time) VALUES ('2025-14-02 10:30:45');<\/pre><\/div>\n\n\n\n<p>MySQL will throw the following error: <\/p>\n\n\n\n<p class=\"has-roboto-mono-font-family has-sm-font-size\">SQL Error [1292] [22001]: Data truncation: Incorrect datetime value: &#8216;2025-14-02 10:30:45&#8217; for column &#8216;event_time&#8217; at row 1<\/p>\n\n\n\n<p class=\"has-roboto-mono-font-family has-sm-font-size\">The error occurred because &#8216;2025-14-02&#8217; is an invalid date format. In MySQL, a valid DATE format follows YYYY-MM-DD, and the month (14) exceeds the valid range (1-12).<\/p>\n\n\n\n<p><strong>Non-strict mode<\/strong>: If strict mode is disabled, MySQL does not throw an error for invalid dates. Instead, it stores <code>'0000-00-00<\/code>&#8216; for invalid dates instead of rejecting them. Here&#8217;s an example:<\/p>\n\n\n\n<p><\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:mysql decode:true block\" >-- Remove strict mode setting\nSET sql_mode=(SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES',''));<\/pre><\/div>\n\n\n\n<p>Then execute the statement:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">INSERT INTO events (event_time) VALUES ('2025-14-02'); <\/pre><\/div>\n\n\n\n<p>You should get back no error message and the data is seemingly stored. But let\u2019s run a <code>SELECT<\/code> statement to see how it stored our date value.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">SELECT * FROM events;<\/pre><\/div>\n\n\n\n<p>This will return something like:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">event_id|event_time         |created_at\n--------+-------------------+-------------------+\n       1|2025-02-14 10:30:45|2025-04-29 11:12:31|\n       2|0000-00-00 00:00:00|2025-04-29 11:13:58|<\/pre><\/div>\n\n\n\n<p>The second row is the one where we had strict mode turned off.<\/p>\n\n\n\n<p>Note that MySQL also allows inserting partial or unknown dates by setting the day or month to 00. This is controlled by the <code>NO_ZERO_IN_DATE<\/code> sql mode. (When setting strict mode earlier, you may have seen a warning about a few settings that are going to be a part of strict mode in MySQL. As such, <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.4\/en\/sql-mode.html&quot; \\l &quot;sqlmode_no_zero_in_date\">NO_ZERO_IN_DATE is deprecated<\/a> and will be rolled into strict mode in the future.)<\/p>\n\n\n\n<p>This can be useful for cases where only part of the date is known. Here\u2019s an example of how this works:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">-- REMOVE NO_ZERO_IN_DATE setting\nSET sql_mode=(SELECT REPLACE(@@sql_mode,'NO_ZERO_IN_DATE',''));\n\nINSERT INTO events (event_time) VALUES ('2025-00-15'); -- Month unknown\n\nINSERT INTO events (event_time) VALUES ('2025-02-00'); -- Day unknown\n\nselect * from events;<\/pre><\/div>\n\n\n\n<p>You can see two new rows, each with 00 for a day or month value for <code>event_id<\/code> = 3 and 4:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\"> event_id|event_time         |created_at         |\n--------+-------------------+-------------------+\n       1|2025-02-14 10:30:45|2025-04-29 11:12:31|\n       2|0000-00-00 00:00:00|2025-04-29 11:13:58|\n       3|2025-00-15 00:00:00|2025-04-29 11:17:45|\n       4|2025-02-00 00:00:00|2025-04-29 11:17:48|<\/pre><\/div>\n\n\n\n<p>Some MySQL functions do not work correctly with 0 values. For example, adding an interval to a 0 date can produce unexpected results. For example:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">SELECT DATE_ADD('2025-00-15', INTERVAL 1 MONTH);<\/pre><\/div>\n\n\n\n<p>This returns a <code>NULL<\/code> value. So, it is not advisable to use this instead, you can enforce valid dates and disallow 0 values, by enabling strict mode and <code>NO_ZERO_DATE<\/code> in <code>sql_mode<\/code>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">set sql_mode = CONCAT(@@sql_mode,',STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE');<\/pre><\/div>\n\n\n\n<p>This ensures that MySQL rejects incomplete dates instead of storing them as 0000-00-00 or allowing 0 for days and months and leaves any other settings intact.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-when-to-use-datetime-vs-timestamp\"><a id=\"post-106629-_a814n5v6c906\"><\/a>When to Use DATETIME vs. TIMESTAMP<\/h3>\n\n\n\n<p>The <code>DATETIME<\/code> and <code>TIMESTAMP<\/code> data types in MySQL both store date and time values, however, they have distinct differences in their storage and range of values. The <code>DATETIME<\/code> data type takes 8 bytes to store a value while <code>TIMESTAMP<\/code> uses only 4 bytes, making it more space-efficient.<\/p>\n\n\n\n<p><code>DATETIME<\/code> can store dates from <code>1000-01-01<\/code> to <code>9999-12-31<\/code>, making it suitable for historical records and long-term data while <code>TIMESTAMP<\/code> only works from <code>1970-01-01<\/code> to <code>2038-01-19<\/code>, due to its Unix timestamp limitation. If you need to store dates beyond 2038, use the <code>DATETIME<\/code> data type.<\/p>\n\n\n\n<p style=\"padding-right:0;padding-left:var(--wp--preset--spacing--md)\"><em>Note: 2038 is not that far in the future, and if there will be a simple fix is not obvious (at best, if the TIMESTAMP is redefined to include later dates, you may have to convert all of your data, so it may be advised to use DATETIME in future development, especially where future dates may be needed.)<\/em><\/p>\n\n\n\n<p>Below is a breakdown of the major differences between the <code>DATETIME<\/code> and <code>TIMESTAMP<\/code> data type in MySQL:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><p><strong>Feature<\/strong><\/p><\/td><td><p><strong>DATETIME<\/strong><\/p><\/td><td><p><strong>TIMESTAMP<\/strong><\/p><\/td><\/tr><tr><td><p>Stores Date &amp; Time?<\/p><\/td><td><p>Yes<\/p><\/td><td><p>Yes<\/p><\/td><\/tr><tr><td><p>Time Zone Affected?<\/p><\/td><td><p>No (Stored as-is)<\/p><\/td><td><p>Yes (Stored in UTC, converted to session time zone)<\/p><\/td><\/tr><tr><td><p>Storage size<\/p><\/td><td><p>8 bytes<\/p><\/td><td><p>4 bytes<\/p><\/td><\/tr><tr><td><p>Range<\/p><\/td><td><p>1000-01-01 00:00:00.000000&#8242; to &#8216;9999-12-31 23:59:59.499999<\/p><\/td><td><p>1970-01-01 00:00:01.000000&#8242; to &#8216;2038-01-19 03:14:07.499999<\/p><\/td><\/tr><tr><td><p>Best Use Case<\/p><\/td><td><p>When time zone conversion is not needed<\/p><\/td><td><p>When you need timezone-aware timestamps<\/p><\/td><\/tr><tr><td><p>Fractional Seconds?<\/p><\/td><td><p>Yes (supports up to 6 decimal places)<\/p><\/td><td><p>Yes (supports up to 6 decimal places)<\/p><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Here\u2019s an example with both Data Types:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">CREATE TABLE product (\n    event_id INT AUTO_INCREMENT PRIMARY KEY,\n    event_name VARCHAR(100),\n    event_time DATETIME,   -- Stores exact input\n    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP  -- Adjusts for time zones\n);\n\nINSERT INTO product (event_name, event_time)\nVALUES\n    ('Conference', '2025-02-14 10:30:45'),\n    ('Webinar', '2025-03-10 15:00:00'),\n    ('Product Launch', '2025-04-01 09:45:00');\n\nSELECT * FROM product;<\/pre><\/div>\n\n\n\n<p>This returns:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">event_id|event_name    |event_time         |created_at         |\n--------+--------------+-------------------+-------------------+\n       1|Conference    |2025-02-14 10:30:45|2025-04-29 11:30:34|\n       2|Webinar       |2025-03-10 15:00:00|2025-04-29 11:30:34|\n       3|Product Launch|2025-04-01 09:45:00|2025-04-29 11:30:34|<\/pre><\/div>\n\n\n\n<p>In the output, the <code>event_time<\/code> column shows the exact date and time you entered while the <code>created_at<\/code><strong> <\/strong>column records when the event was added, storing it in UTC and adjusting automatically based on your time zone when retrieved.<\/p>\n\n\n\n<p>So, if you care about time zone conversions, use <code>TIMESTAMP<\/code> and if you want a fixed value across all time zones, use <code>DATETIME<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-handling-2-digits-years-in-mysql\"><a id=\"post-106629-_z5rtdnaemud9\"><\/a>Handling 2 Digits Years in MySQL<\/h3>\n\n\n\n<p>MySQL lets you insert years using just two digits, but it automatically expands them to four digits based on a specific rule:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li> If the value is between 00 and 69, MySQL treats it as 2000\u20132069. <\/li>\n\n\n\n<li> If the value is between 70 and 99, MySQL treats it as 1970\u20131999. <\/li>\n<\/ul>\n<\/div>\n\n\n<p>This automatic conversion may cause confusion, especially with old or future dates. To avoid mistakes, always use four-digit years (YYYY-MM-DD). Here\u2019s a practical example using our <strong>product<\/strong> table created earlier:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">INSERT INTO product (event_time) VALUES ('25-02-14');  \nINSERT INTO product (event_time) VALUES ('89-12-31');\n\nSELECT event_time FROM product;<\/pre><\/div>\n\n\n\n<p>MySQL treated 25-02-14 as &#8216;2025-02-14&#8217; and also 89-12-31 as &#8216;1989-12-31&#8217;<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">event_time         |\n-------------------+\n2025-02-14 00:00:00|\n1989-12-31 00:00:00|<\/pre><\/div>\n\n\n\n<p>So far, we have covered quite a bit about the Date and Time Data Types in MySQL, but definitely could not cover every detail. For more, check the official <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.4\/en\/date-and-time-types.html\">documentation on date and time types in the MySQL Documentation<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-postgresql-date-and-time-data-types\"><a id=\"post-106629-_qa24b7gp1wni\"><\/a>PostgreSQL Date and Time Data Types<\/h2>\n\n\n\n<p>PostgreSQL provides a range of date and time data types for storing simple dates, handling time zones, and managing time intervals. It supports <code>DATE<\/code>, <code>TIME<\/code> (with time zone), <code>TIME<\/code> (without time zone), <code>TIMESTAMP<\/code> (with time zone), <code>TIMESTAMP<\/code> (without time zone) which can include fractional seconds (up to 6 digits), and <code>INTERVAL<\/code>. Here&#8217;s a breakdown of the range, storage size, and expected format of the following date and time values.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><p>DataType<\/p><\/td><td><p>Range<\/p><\/td><td><p>Expected Format<\/p><\/td><td><p>Description<\/p><\/td><td><p>Storage Size<\/p><\/td><\/tr><tr><td><p><code>DATE<\/code><\/p><\/td><td><p>4713 BC to 5874897 AD<\/p><\/td><td><p>YYYY:MM:DD<\/p><\/td><td><p>Stores only the calendar date (year, month, day) without a time component.<\/p><\/td><td><p>4 bytes<\/p><\/td><\/tr><tr><td><p><code>TIME [(p)] WITHOUT TIME ZONE<\/code><\/p><\/td><td><p>00:00:00 to 24:00:00 (24:00:00 is a special case that represents the start of the next day)<\/p><\/td><td><p>HH:MM:SS<\/p><\/td><td><p>Stores only the time of day without any time zone information.<\/p><\/td><td><p>8 bytes<\/p><\/td><\/tr><tr><td><p><code>TIME [(p)] WITH TIME ZONE<\/code><\/p><\/td><td><p>00:00:00+1559 to 24:00:00-1559 (24:00:00 values represent the start of the next day)<\/p><\/td><td><p>&#8216;HH:MI:SS+TZ&#8217;<\/p><\/td><td><p>Stores the time of day with an associated time zone offset.<\/p><\/td><td><p>12 bytes<\/p><\/td><\/tr><tr><td><p><code>TIMESTAMP [(p)] WITHOUT TIME ZONE <\/code><\/p><\/td><td><p>4713 BC to 294276 AD<\/p><\/td><td><p>YYYY-MM-DD HH:MI:SS<\/p><\/td><td><p>Stores both date and time, but does not include time zone information.<\/p><\/td><td><p>8 bytes<\/p><\/td><\/tr><tr><td><p><code>TIMESTAMP [(p)] WITH TIME ZONE <\/code><\/p><\/td><td><p>4713 BC to 294276 AD<\/p><\/td><td><p>YYYY-MM-DD HH:MI:SS+TZ<\/p><\/td><td><p>Stores both date and time, adjusting for time zones automatically based on session settings.<\/p><\/td><td><p>8 bytes<\/p><\/td><\/tr><tr><td><p><code>INTERVAL [(p)]16 bytes\t<\/code><\/p><\/td><td><p>-178 million to +178 million years<\/p><\/td><td><p>quantity unit(e.g., &#8216;2 days&#8217;)<\/p><\/td><td><p>Represents a duration of time, allowing operations like date\/time arithmetic.<\/p><\/td><td><p>16 bytes<\/p><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p style=\"padding-right:0;padding-left:var(--wp--preset--spacing--md)\"><em>Note: In PostgreSQL, you can control how dates are interpreted by setting the `<a href=\"https:\/\/www.postgresql.org\/docs\/current\/runtime-config-client.html&quot; \\l &quot;GUC-DATESTYLE\">DateStyle`<\/a> parameter. The available formats include <\/em><strong><em>MDY<\/em><\/strong><em> (month-day-year), <\/em><strong><em>DMY <\/em><\/strong><em>(day-month-year), and <\/em><strong><em>YMD<\/em><\/strong><em>(year-month-day). This ensures flexibility in handling different regional date formats. <\/em><\/p>\n\n\n\n<p>When inserting date and time values in PostgreSQL, they must be enclosed in single quotes. Here&#8217;s an example on how you can create a table and insert date and time values in PostgreSQL:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:plsql\" highlight=\"true\" decode=\"true\">CREATE TABLE events (\n    event_id SERIAL PRIMARY KEY,\n    event_name VARCHAR(100),\n    event_date DATE,\n    event_time TIME,\n    event_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\nINSERT INTO events (event_name, event_date, event_time)\nVALUES ('Conference', '2025-02-14', '10:30:00');\n\nSELECT * FROM events;<\/pre><\/div>\n\n\n\n<p>The output will be as follows:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">event_id|event_name|event_date|event_time|event_timestamp        |\n--------+----------+----------+----------+-----------------------+\n       1|Conference|2025-02-14|  10:30:00|2025-04-29 15:28:59.103|<\/pre><\/div>\n\n\n\n<p>If you try to insert the date without enclosing it in a single quote, it will throw an error. Let\u2019s try that:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:plsql\" highlight=\"true\" decode=\"true\">INSERT INTO events (event_name, event_date, event_time)  \nVALUES ('Conference', 2025-02-14, '10:30:00' );<\/pre><\/div>\n\n\n\n<p>Then you will get an error like the following:<\/p>\n\n\n\n<p class=\"has-roboto-mono-font-family has-sm-font-size\">SQL Error [42804]: ERROR: column &#8220;event_date&#8221; is of type date but expression is of type integer<br>Hint: You will need to rewrite or cast the expression.<br>Position: 82<\/p>\n\n\n\n<p>This is because the date expression now looks like an integer mathematical expression of 2024-2-14.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-timestamp-with-vs-without-time-zone\"><a id=\"post-106629-_fwj2gaa91p1b\"><\/a>TIMESTAMP WITH vs. WITHOUT TIME ZONE<\/h3>\n\n\n\n<p>One of PostgreSQL&#8217;s strengths is its ability to handle time zones properly. It offers two types of timestamps. <code>TIMESTAMP WITHOUT TIME ZONE<\/code> stores the exact date and time as entered and no automatic time zone conversion, and <code>TIMESTAMP WITH TIME ZONE<\/code> converts the stored value to UTC and adjusts it when retrieved based on the session\u2019s time zone. Here&#8217;s an example of how both timestamps work:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:plsql\" highlight=\"true\" decode=\"true\">CREATE TABLE events (\n    event_id SERIAL PRIMARY KEY,\n    event_name VARCHAR(100),\n  -- Stores exact input with no time zone information\n    event_timestamp TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP,\n  -- Adjusts for time zones\n    event_timestamptz TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP\n);\n\nINSERT INTO events (event_name, event_timestamp, event_timestamptz)\nVALUES ('Webinar', '2025-02-14 10:30:00', '2025-02-14 10:30:00');\n\nSELECT event_name, event_timestamp, event_timestamptz FROM events;<\/pre><\/div>\n\n\n\n<p>The output should look something like the following:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">event_name|event_timestamp        |event_timestamptz            |\n----------+-----------------------+-----------------------------+\nWebinar   |2025-02-14 10:30:00.000|2025-02-14 10:30:00.000 -0500|<\/pre><\/div>\n\n\n\n<p>Note that even though the time entered into the <code>event_timestamptz<\/code> and <code>event_timestamp<\/code> columns looks the same, <code>event_timestamp<\/code> is at 10:30, but <code>event_timestamptz<\/code> adds the time zone information, so it could be interpreted as 10:30 in the executor\u2019s time zone, or at 5:30 UTC.<\/p>\n\n\n\n<p>Every time you run the INSERT query, it automatically sets the time stamp and adjusts it based on the session\u2019s time zone when retrieved. Meanwhile, <code>event_timestamp<\/code> will always stay as the base time 2025-02-14 10:30:00, no matter the session time zone.<\/p>\n\n\n\n<p>If you don\u2019t need time zone adjustments, use <code>TIMESTAMP WITHOUT TIME ZONE<\/code> and if your application handles users in different time zones use <code>TIMESTAMP WITH TIME ZONE<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-special-date-and-time-values\"><a id=\"post-106629-_sd72v98vu98h\"><\/a>Special Date And Time Values<\/h3>\n\n\n\n<p>PostgreSQL provides predefined constants that make working with dates and times easier. These constants help in retrieving system-generated values without requiring manual input. Here are some of the special date and time values:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><p>Special value<\/p><\/td><td><p>Description<\/p><\/td><\/tr><tr><td><p><code>CURRENT_DATE<\/code><\/p><\/td><td><p>Returns only the current date (YYYY-MM-DD).<\/p><\/td><\/tr><tr><td><p><code>CURRENT_TIME<\/code><\/p><\/td><td><p>Returns only the current time<strong> <\/strong>(HH:MI:SS with optional fractional seconds).<\/p><\/td><\/tr><tr><td><p><code>today<\/code><\/p><\/td><td><p>Used in place of a specific date value. Represents the current date (similar to CURRENT_DATE). For example: <br><br>select cast(&#8216;today&#8217; as date);<\/p><\/td><\/tr><tr><td><p><code>tomorrow<\/code><\/p><\/td><td><p>Represents the next day (current date + 1).<\/p><\/td><\/tr><tr><td><p><code>yesterday<\/code><\/p><\/td><td><p>Represents the previous day (current date &#8211; 1).<\/p><\/td><\/tr><tr><td><p><code>allballs<\/code><\/p><\/td><td><p>Represents midnight (00:00:00). Equivalent to &#8217;00:00:00&#8242;::time. <br><br><code>SELECT 'allballs'::time;<\/code><\/p><\/td><\/tr><tr><td><p><code>CURRENT_TIMESTAMP<\/code><\/p><\/td><td><p>Returns the current date and time.<\/p><\/td><\/tr><tr><td><p><code>NOW()<\/code><\/p><\/td><td><p>Works the same as <code>CURRENT_TIMESTAMP<\/code>, returning the current date and time.<\/p><\/td><\/tr><tr><td><p><code>infinity<\/code><\/p><\/td><td><p>Represents a future date that never ends.<\/p><\/td><\/tr><tr><td><p><code>-infinity<\/code><\/p><\/td><td><p>Represents a past date that has no beginning.<\/p><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p style=\"padding-right:0;padding-left:var(--wp--preset--spacing--md)\">Note: The <code>CURRENT_DATE()<\/code>, <code>CURRENT_TIME()<\/code>, <code>CURRENT_TIMESTAMP()<\/code>, and <code>NOW()<\/code> special date and time values are also available in MySQL and work the same way. But, there are no built-in values for <code>today<\/code>, <code>tomorrow<\/code>, <code>yesterday<\/code>, <code>allballs<\/code>, and <code>infinity<\/code> like in PostgreSQL.<\/p>\n\n\n\n<p><em>However, you can work around this by using the largest and smallest possible date values:<\/em><\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li><em>Simulating infinity \u2192 Use &#8216;9999-12-31&#8217;, the highest possible date.<\/em> <\/li>\n\n\n\n<li><em>Simulating -infinity \u2192 Use &#8216;0000-00-00&#8217; (if allowed) or &#8216;1000-01-01&#8217;, the lowest supported date. For relative date calculations:<\/em> <\/li>\n\n\n\n<li><em>Today \u2192 <\/em><code>CURRENT_DATE()<\/code> <\/li>\n\n\n\n<li><em>Tomorrow \u2192 <\/em><code>CURRENT_DATE() + 1<\/code> <\/li>\n\n\n\n<li><em>Yesterday \u2192 <\/em><code>CURRENT_DATE() - 1<\/code> <\/li>\n<\/ul>\n<\/div>\n\n\n<p>Here are some examples on using some of these special date and time values in PostgreSQL:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:plsql\" highlight=\"true\" decode=\"true\">SELECT CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, NOW();<\/pre><\/div>\n\n\n\n<p>This will return something similar to:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"608\" height=\"59\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-video-ai-generated-content-may.png\" alt=\"A screenshot of a video\n\nAI-generated content may be incorrect.\" class=\"wp-image-106631\" srcset=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-video-ai-generated-content-may.png 608w, https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2025\/05\/a-screenshot-of-a-video-ai-generated-content-may-300x29.png 300w\" sizes=\"auto, (max-width: 608px) 100vw, 608px\" \/><\/figure>\n\n\n\n<p>\n   \n  \n<\/p>\n\n\n\n<p style=\"padding-right:0;padding-left:var(--wp--preset--spacing--md)\">Key difference: <code>CURRENT_TIME<\/code> only shows the time, while <code>CURRENT_TIMESTAMP<\/code> and <code>NOW()<\/code> include both date and time.<\/p>\n\n\n\n<p>The infinity values are useful when you don\u2019t know the exact start or end date of an event. Here\u2019s an example:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:plsql\" highlight=\"true\" decode=\"true\">CREATE TABLE subscriptions (\nuser_id SERIAL PRIMARY KEY,\nstart_date DATE DEFAULT CURRENT_DATE,\nend_date DATE DEFAULT 'infinity' -- No expiration by default\n);\nINSERT INTO subscriptions (user_id) VALUES (1);\n\nSELECT * FROM subscriptions;<\/pre><\/div>\n\n\n\n<p>This will return:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">user_id|start_date|end_date|\n-------+----------+--------+\n      1|2025-04-29|infinity|<\/pre><\/div>\n\n\n\n<p>The typical use case for the &#8216;infinity&#8217; and &#8216;-infinity&#8217; are useful for setting lifelong memberships, permanent bans, or open-ended job contracts.<\/p>\n\n\n\n<p>Let\u2019s try out another example:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">CREATE TABLE events (\n    event_id SERIAL PRIMARY KEY,\n    event_name TEXT,\n    event_date DATE\n);\n\nINSERT INTO events (event_name, event_date) VALUES\n('Conference', 'today'),   -- Stores current date\n('Hackathon', 'tomorrow'), -- Stores next day's date\n('Workshop', 'yesterday'); -- Stores previous day's date\n<\/pre><\/div>\n\n\n\n<p>Events on today\u2019s date:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">SELECT * FROM events WHERE event_date = 'today';<\/pre><\/div>\n\n\n\n<p>Which as I am finalizing this article is April 28:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">event_id|event_name|event_date|\n--------+----------+----------+\n       9|Workshop  |2025-04-28|<\/pre><\/div>\n\n\n\n<p>For earlier than today:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:plsql\" highlight=\"true\" decode=\"true\">SELECT * FROM events WHERE event_date &lt; 'today';<\/pre><\/div>\n\n\n\n<p>This returned:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">event_id|event_name|event_date|\n--------+----------+----------+\n      15|Workshop  |2025-04-28|<\/pre><\/div>\n\n\n\n<p>And for events in the future:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">SELECT * FROM events WHERE event_date &gt; 'today';<\/pre><\/div>\n\n\n\n<p>Beyond these common built in intervals, you can use the INTERVAL construct for more flexibility<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:plsql\" highlight=\"true\" decode=\"true\">INSERT INTO events (event_name, event_date) VALUES\n('Meetup', CURRENT_DATE + INTERVAL '1 day'),  -- Equivalent to 'tomorrow'\n('Webinar', CURRENT_DATE - INTERVAL '1 day'), -- Equivalent to 'yesterday'\n('Summit', CURRENT_DATE + INTERVAL '1 month'); -- Adds one month\n\nselect * from events\nwhere event_name in ('Meetup','Webinar','Summit')<\/pre><\/div>\n\n\n\n<p>Knowing this is the twenty ninth of April, you can see the different values from the INSERT statement in the following output:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">event_id|event_name|event_date|\n--------+----------+----------+\n      16|Meetup    |2025-04-30|\n      17|Webinar   |2025-04-28|\n      18|Summit    |2025-05-29|<\/pre><\/div>\n\n\n\n<p>For more information on the date and time data type, please visit the official PostgreSQL <a href=\"https:\/\/www.postgresql.org\/docs\/current\/datatype-datetime.html\">documentation.<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-mysql-vs-postgresql-comparison-of-date-and-time-data-types\"><a id=\"post-106629-_10m9p91bnfum\"><\/a><a id=\"post-106629-_uufrjzwvvp8h\"><\/a>MySQL vs PostgreSQL: Comparison of Date and Time Data Types<\/h2>\n\n\n\n<p>MySQL and PostgreSQL both offer date and time data types, but there are subtle differences in their flexibility and behaviour. While both databases support DATE, TIME, and TIMESTAMP, MySQL has YEAR as a separate data type, while PostgreSQL does not. PostgreSQL also includes INTERVAL for handling time spans, which MySQL lacks. Here\u2019s a detailed comparison of date and time data type in both databases:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><p><strong>Data Type <\/strong><\/p><\/td><td><p><strong>MySQL<\/strong><\/p><\/td><td><p><strong>Range (MySQL)<\/strong><\/p><\/td><td><p><strong>PostgreSQL<\/strong><\/p><\/td><td><p><strong>Range (PostgreSQL)<\/strong><\/p><\/td><td><p><strong>Differences<\/strong><\/p><\/td><\/tr><tr><td><p>Date types<\/p><\/td><td><p><code>\u2018DATE\u2019<\/code><\/p><\/td><td><p>Range: 1000-01-01&#8242; to &#8216;9999-12-31&#8217;<\/p><\/td><td><p><code>\u2018DATE\u2019<\/code><\/p><\/td><td><p>Range:<\/p><p>4713 BC&#8217; to &#8216;5874897 AD&#8217;<\/p><\/td><td><p>Both databases offer <code>DATE<\/code> types for storing dates (year, month, day).<\/p><\/td><\/tr><tr><td><p>Datetime types<\/p><\/td><td><p><code>\u2018DATETIME\u2019<\/code><\/p><p><code>\u2018TIMESTAMP\u2019<\/code><\/p><\/td><td><p>Datetime range: &#8216;1000-01-01 00:00:00&#8217; to &#8216;9999-12-31 23:59:59&#8217;<\/p><p>Timestamp range: \u20181970-01-01 00:00:01&#8242; to &#8216;2038-01-19 03:14:07\u2019<\/p><\/td><td><p><code>\u2018TIMESTAMP\u2019<\/code><\/p><\/td><td><p>Range: &#8216;4713 BC&#8217; to &#8216;294276 AD&#8217;<\/p><\/td><td><p>PostgreSQL&#8217;s <code>TIMESTAMP<\/code> supports a broader range and higher precision than MySQL&#8217;s <code>DATETIME<\/code>.<\/p><\/td><\/tr><tr><td><p>Time types<\/p><\/td><td><p><code>\u2018TIME\u2019<\/code><\/p><\/td><td><p>Range: &#8216;-838:59:59&#8217; to &#8216;838:59:59&#8217;<\/p><\/td><td><p>\u2018<code>TIME\u2019<\/code><\/p><\/td><td><p>Range: &#8217;00:00:00&#8242; to &#8217;24:00:00&#8242;<\/p><\/td><td><p>PostgreSQL&#8217;s TIME type has a more conventional range compared to MySQL&#8217;s.<\/p><\/td><\/tr><tr><td><p>Year types<\/p><\/td><td><p><code> \u2018YEAR\u2019<\/code><\/p><\/td><td><p>Range: &#8216;1901&#8217; to &#8216;2155&#8217;<\/p><\/td><td><p>&#8211;<\/p><\/td><td><p>&#8211;<\/p><\/td><td><p>MySQL offers a YEAR type specifically for storing year values using 1 byte. PostgreSQL does not have this data type.<\/p><\/td><\/tr><tr><td><p>Interval types<\/p><\/td><td><p><code>          -<\/code><\/p><\/td><td><p><code>             -<\/code><\/p><\/td><td><p><code>\u2018INTERVAL\u2019<\/code><\/p><\/td><td><p>Range: Can represent large periods from years to microsecond<\/p><\/td><td><p>PostgreSQL supports <code>INTERVAL<\/code> for storing periods of time, which is not natively available in MySQL.<\/p><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p style=\"padding-right:0;padding-left:var(--wp--preset--spacing--md)\">Note: MySQL has an <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.4\/en\/expressions.html\">interval<\/a> type which is more of an expression\/keyword and not a data type. We will see how this works in a bit.<\/p>\n\n\n\n<p>MySQL allows storing invalid dates like &#8216;0000-00-00&#8217; in non-strict mode, which can lead to unexpected results. But, PostgreSQL enforces strict date validation and does not allow invalid dates. Let\u2019s see this in action:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">CREATE TABLE actions (\n    user_id SERIAL PRIMARY KEY,\n    start_date DATE DEFAULT CURRENT_DATE,\n    end_date DATE DEFAULT 'infinity'  -- No expiration by default\n);\n\nINSERT INTO subscriptions (start_date) VALUES ('0000-00-00');<\/pre><\/div>\n\n\n\n<p>This input will fail since that is not an allowable value for the <code>DATE<\/code> datatype:<\/p>\n\n\n\n<p class=\"has-roboto-mono-font-family has-sm-font-size\">SQL Error [22008]: ERROR: date\/time field value out of range: &#8220;0000-00-00&#8221;<br>Position: 44<br>Error position: line: 8 pos: 43<\/p>\n\n\n\n<p>One of the differences in date and time data types is how each database handles time zone. PostgreSQL provides <code>TIMESTAMP WITH TIME ZONE (TIMESTAMPTZ),<\/code> which automatically converts values to UTC and adjusts them based on the session&#8217;s time zone.<\/p>\n\n\n\n<p>MySQL&#8217;s <code>TIMESTAMP<\/code> also supports automatic time zone conversion, but <code>DATETIME<\/code> does not. Instead, it stores the values as inserted.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-date-and-time-functions-in-mysql-and-postgresql\"><a id=\"post-106629-_h2vsotp6maog\"><\/a>Date and Time Functions in MySQL and PostgreSQL<\/h3>\n\n\n\n<p>Another major difference between both databases is how they handle special dates and time values. Here\u2019s a well detailed table comparing date and time functions in both databases:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><td><p><strong>Special Value <\/strong><\/p><\/td><td><p><strong>MySQL Equivalent <\/strong><\/p><\/td><td><p><strong>PostgreSQL<\/strong><\/p><\/td><\/tr><tr><td><p><code>CURRENT_DATE<\/code><\/p><\/td><td><p><code>\u2705 CURRENT_DATE()<\/code><\/p><\/td><td><p><code>\u2705 CURRENT_DATE<\/code><\/p><\/td><\/tr><tr><td><p><code>CURRENT_TIME<\/code><\/p><\/td><td><p><code>\u2705 CURRENT_TIME()<\/code><\/p><\/td><td><p><code>\u2705 CURRENT_TIME<\/code><\/p><\/td><\/tr><tr><td><p><code>CURRENT_TIMESTAMP\t\t<\/code><\/p><\/td><td><p><code>\u2705 CURRENT_TIMESTAMP()<\/code><\/p><\/td><td><p><code>\u2705 CURRENT_TIMESTAMP<\/code><\/p><\/td><\/tr><tr><td><p><code>'today', 'tomorrow', 'yesterday'<\/code><\/p><\/td><td><p>\u274c No direct equivalent<\/p><\/td><td><p>\u2705 Supported<\/p><\/td><\/tr><tr><td><p><code>'infinity', '-infinity'<\/code><\/p><\/td><td><p>\u274c No direct equivalent<\/p><\/td><td><p>\u2705Used for open-ended ranges<\/p><\/td><\/tr><tr><td><p><code>'allballs' (00:00:00)<\/code><\/p><\/td><td><p>\u274c No equivalent<\/p><\/td><td><p>\u2705 Used as a midnight shorthand<\/p><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>While in some cases there are not specific shorthand methods that work across systems ,there are relatively simple ways to get the job done when needed. For example, if you want to store values like \u2018today\u2019, \u2018tomorrow\u2019, and \u2018yesterday\u2019 in MySQL, you can take advantage of the already supported <code>CURRENT_DATE()<\/code> function. Here\u2019s how to do this in MySQL:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">CREATE TABLE new_events (\n    event_id SERIAL PRIMARY KEY,\n    event_name TEXT,\n    event_date DATE\n);\n\nINSERT INTO new_events (event_name, event_date) VALUES\n('Conference', current_date()),   -- Stores current date\n('Hackathon', current_date() + 1), -- Stores next day's date\n('Workshop', current_date() -1); -- Stores previous day's date<\/pre><\/div>\n\n\n\n<p>And querying the data in this table, you should get a similar result just like PostgreSQL<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">event_id|event_name|event_date|\n--------+----------+----------+\n       1|Conference|2025-04-29|\n       2|Hackathon |2025-04-30|\n       3|Workshop  |2025-04-28|<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-working-with-intervals-postgresql-vs-mysql-alternative\"><a id=\"post-106629-_twlxdkjsx4kj\"><\/a>Working with Intervals (PostgreSQL vs. MySQL alternative)<\/h3>\n\n\n\n<p>PostgreSQL supports <code>INTERVAL<\/code> which adds more flexibility and allows you to perform date\/time arithmetic directly. It Is a data type that can store time spans. You can add or subtract intervals to dates and timestamps easily.<\/p>\n\n\n\n<p>In MySQL, <code>INTERVAL<\/code> is not a data type\u2014it is an expression used for date and time calculations but cannot be stored as a data type. It is used within date arithmetic operations and works with functions like <code>DATE_ADD()<\/code> and <code>DATE_SUB(),<\/code> or in direct arithmetic expressions. It allows specifying time units (e.g., <code>DAY<\/code>, <code>HOUR<\/code>, <code>MONTH<\/code>).<\/p>\n\n\n\n<p>Here\u2019s an example of how the Interval data type works in PostgreSQL and how it can be handled in MySQL:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"h-postgresql\">PostgreSQL<\/h4>\n\n\n\n<p>Using interval, you can add one day to the current timestamp<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:plsql\" highlight=\"true\" decode=\"true\">SELECT NOW() + INTERVAL '1 day' as Result;  -- Adds one day to the current timestamp<\/pre><\/div>\n\n\n\n<p>The output of this will be:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">result                       |\n-----------------------------+\n2025-04-30 15:43:41.765 -0400|<\/pre><\/div>\n\n\n\n<p>You can also subtract 3 hours from the current timestamp<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:plsql\" highlight=\"true\" decode=\"true\">SELECT NOW() - INTERVAL '3 hours' as result;  -- Subtracts three hours<\/pre><\/div>\n\n\n\n<p>Wich will show you 3 hours ago<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">result                       |\n-----------------------------+\n2025-04-29 12:44:14.437 -0400|<\/pre><\/div>\n\n\n\n<p>You can also add 2 weeks to the current timestamp:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:plsql\" highlight=\"true\" decode=\"true\">SELECT NOW() + INTERVAL '2 weeks' as result;  -- Adds two weeks<\/pre><\/div>\n\n\n\n<p>It also allows you to add values to a specific date too<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:plsql\" highlight=\"true\" decode=\"true\">SELECT '2025-02-14'::DATE + INTERVAL '1 month' as result;  \n-- Adds one month to a specific date<\/pre><\/div>\n\n\n\n<p>This, as you can see now gives us 1 month after 2\/14:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">result                 |\n-----------------------+\n2025-03-14 00:00:00.000|<\/pre><\/div>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"h-mysql\">MySQL:<\/h4>\n\n\n\n<p>MySQL does not have a built-in <code>INTERVAL<\/code> type. Instead, it provides the <code>DATE_ADD()<\/code> and <code>DATE_SUB()<\/code> functions to achieve similar results. Here\u2019s how we can do this in MySQL. To add one day to the current timestamp using DATE_ADD():<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">SELECT DATE_ADD(NOW(), INTERVAL 1 DAY);  -- Adds one day<\/pre><\/div>\n\n\n\n<p>This will return the following (again, this is mid afternoon on 4\/29):<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">DATE_ADD(NOW(), INTERVAL 1 DAY)|\n-------------------------------+\n            2025-04-30 15:46:28|<\/pre><\/div>\n\n\n\n<p>To subtract 3 hours from the current timestamp using DATE_SUB():<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">SELECT DATE_SUB(NOW(), INTERVAL 3 HOUR);  -- Subtracts three hours<\/pre><\/div>\n\n\n\n<p>To add two weeks to the current timestamp:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">SELECT DATE_ADD(NOW(), INTERVAL 2 WEEK);  -- Adds two weeks<\/pre><\/div>\n\n\n\n<p>87weaTo add one month to a particular date:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block lang:mysql\" highlight=\"true\" decode=\"true\">SELECT DATE_ADD('2025-02-14', INTERVAL 1 MONTH);  -- Adds one month to a specific date<\/pre><\/div>\n\n\n\n<p>Just like in the last section:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"block\" highlight=\"false\" decode=\"true\">DATE_ADD('2025-02-14', INTERVAL 1 MONTH)|\n----------------------------------------+\n2025-03-14                              |<\/pre><\/div>\n\n\n\n<p>For more detailed information on INTERVAL in MySQL, refer to the <a href=\"https:\/\/dev.mysql.com\/doc\/refman\/8.4\/en\/expressions.html\">MySQL 8.4 Reference Manual on Expression<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-key-takeaway\"><a id=\"post-106629-_m5vld1skl2ri\"><\/a>Key Takeaway<\/h2>\n\n\n\n<p>Both MySQL and PostgreSQL provide similar core data types: <code>DATE<\/code>, TIME, <code>TIMESTAMP<\/code>, and <code>DATETIME<\/code> (MySQL) or <code>TIMESTAMP WITH\/WITHOUT TIME ZONE<\/code> (PostgreSQL).<\/p>\n\n\n\n<p>However, PostgreSQL includes an additional INTERVAL as a data type, allowing direct arithmetic operations for storing time spans, while MySQL uses <code>INTERVAL<\/code> only as an expression inside <code>DATE_ADD()<\/code> and <code>DATE_SUB()<\/code> functions.<\/p>\n\n\n\n<p>PostgreSQL also has built-in time zone support with <code>TIMESTAMP WITH TIME ZONE<\/code>, automatically adjusting for session settings while MySQL lacks true time zone-aware timestamps, its <code>TIMESTAMP<\/code> type stores values in UTC but requires manual conversion when retrieving data.<\/p>\n\n\n\n<p>PostgreSQL supports special values like &#8216;infinity&#8217;, &#8216;-infinity&#8217;, &#8216;today&#8217;, &#8216;tomorrow&#8217;, &#8216;yesterday&#8217;, and &#8216;allballs&#8217; (00:00:00). MySQL does not support the following but can use maximum and minimum date values as a workaround.<\/p>\n\n\n\n<p>If your application relies heavily on time zones and intervals, PostgreSQL is more robust. If you need simpler date-time storage and don&#8217;t require complex time zone logic, MySQL works fine. PostgreSQL is also stricter in enforcing valid date formats, while MySQL allows more flexibility (sometimes at the cost of unexpected behavior).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Date and time data types are important because they help track and manage time-based information in databases. This includes things like recording when orders are placed, scheduling events, or calculating the time between two activities. In this article, we will look at differences between how PostgreSQL and MySQL stores and utilizes date and time datatypes&#8230;.&hellip;<\/p>\n","protected":false},"author":341597,"featured_media":106632,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[53,145792,143534],"tags":[159268,5854,158978],"coauthors":[158988],"class_list":["post-106629","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-featured","category-mysql","category-postgresql","tag-aishabukar_mysql_postgresql","tag-mysql","tag-postgresql"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/106629","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/341597"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=106629"}],"version-history":[{"count":8,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/106629\/revisions"}],"predecessor-version":[{"id":106642,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/106629\/revisions\/106642"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media\/106632"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=106629"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=106629"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=106629"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=106629"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}