{"id":3361,"date":"2011-05-22T06:11:47","date_gmt":"2011-05-22T04:11:47","guid":{"rendered":"http:\/\/code.openark.org\/blog\/?p=3361"},"modified":"2011-05-26T13:52:08","modified_gmt":"2011-05-26T11:52:08","slug":"timestamp-vs-datetime-which-should-i-be-using","status":"publish","type":"post","link":"https:\/\/code.openark.org\/blog\/mysql\/timestamp-vs-datetime-which-should-i-be-using","title":{"rendered":"TIMESTAMP vs. DATETIME, which should I be using?"},"content":{"rendered":"<p>They both look the same, have roughly the same use. Nevertheless, they differ in many respects. I&#8217;ll note the difference, and note a few pitfalls and peculiarities.<\/p>\n<h4>Range<\/h4>\n<p><strong>TIMESTAMP<\/strong> starts with the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Unix_time\">epoch<\/a>, <strong>&#8216;1970-01-01 00:00:01&#8217;<\/strong> UTC and ends with <strong>&#8216;2038-01-19 03:14:07&#8217;<\/strong> UTC. This is all very nice today, and may actually hold up till our retirement, but the younger readers may yet have to deal with the <strong>Bug2K+38<\/strong>\u2122, certain to arrive.<\/p>\n<p><strong>DATETIME<\/strong> starts with <strong>&#8216;1000-01-01 00:00:00&#8217;<\/strong> and lasts up to <strong>&#8216;9999-12-31 23:59:59&#8217;<\/strong>. More on that later.<\/p>\n<p>In respect of range, your current event logs may well use a <strong>TIMESTAMP<\/strong> value, while your grandfather&#8217;s and granddaughter&#8217;s birth dates may require <strong>DATETIME<\/strong>.<\/p>\n<p>In general I would suggest that anything that relates to <em>now<\/em>, can be a <strong>TIMESTAMP<\/strong>. A new entry is added? It is added <em>now<\/em>. It can be represented by a <strong>TIMESTAMP<\/strong>. Anything has an expiry time of a few minutes, perhaps a few days or a month? You&#8217;ll be safe using it up till late <strong>2037<\/strong>. Anything else had better use a <strong>DATETIME<\/strong>. In particular, dates relating to issues such as birth, insurance, the market etc. fall into this category.<\/p>\n<p><em>History<\/em>, however, does not even hold up with <strong>DATETIME<\/strong>. Rome fell long before <strong>MIN(DATETIME)<\/strong>. You will have to manage your own. Not even <strong>YEAR<\/strong> will help you out.<\/p>\n<h4>Storage<\/h4>\n<p><strong>TIMESTAMP<\/strong> makes for <strong>4<\/strong> bytes. <strong>DATETIME<\/strong> makes for <strong>8<\/strong> bytes. Now that we have this behind us, let&#8217;s see why.<!--more--><\/p>\n<h4>Internal representation<\/h4>\n<p>A <strong>TIMESTAMP<\/strong> is merely the number of elapsed seconds since the <em>epoch<\/em>. It is a number. Not only is this a number, it is an incrementing number, and without gaps. Ever ascending. It actually equals the <strong>UNIX_TIMESTAMP()<\/strong> function.<\/p>\n<p>A <strong>DATETIME<\/strong> is more of an oddity. From the manual:<\/p>\n<blockquote>\n<ul>\n<li><code>DATETIME<\/code>: Eight bytes:\n<div>\n<ul>\n<li>A four-byte integer packed as               <code>YYYY<\/code>\u00d710000 +               <code>MM<\/code>\u00d7100 +               <code>DD<\/code><\/li>\n<li>A four-byte integer packed as               <code>HH<\/code>\u00d710000 +               <code>MM<\/code>\u00d7100 +               <code>SS<\/code><\/li>\n<\/ul>\n<\/div>\n<\/li>\n<\/ul>\n<\/blockquote>\n<p><em>Huh?<\/em><\/p>\n<p>There&#8217;s nothing sequential about a <strong>DATETIME<\/strong>. The value which follows <strong>20110307095159<\/strong> is <strong>20110307095200<\/strong>. It&#8217;s like the string representation without any delimiters. See the following (ignore the fraction, it&#8217;s not really there):<\/p>\n<blockquote>\n<pre>root@mysql-5.1.51&gt; SELECT NOW()+0;\r\n+-----------------------+\r\n| NOW()+0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 |\r\n+-----------------------+\r\n| 20110307095238.000000 |\r\n+-----------------------+\r\n<\/pre>\n<\/blockquote>\n<p>The implication of this internal representation is that conversions must be made back and forth. When you want to add <strong>5<\/strong> seconds to a <strong>DATETIME<\/strong>, MySQL cannot simply add <strong>5<\/strong> to some number, but must make for a more complicated calculation.<\/p>\n<h4>Peculiarities<\/h4>\n<p>Now here&#8217;s a question: why does <strong>DATETIME<\/strong> start with <strong>&#8216;1000-01-01 00:00:00&#8217;<\/strong>? Can you provide with a convincing argument? The only argument I can find is hardly convincing.<\/p>\n<p>Did you ever need to type in a password with your phone? Say, for your Credit Card company, or your Bank? Did you get recorded instructions saying &#8220;<em>You must type six digits. You must not repeat the same digits three successive times<\/em>&#8220;? That&#8217;s somewhat nice, and probably a good advice. Did you ever get told &#8220;<em>The first digit must not be <strong>0<\/strong><\/em>&#8220;? That&#8217;s just <em>stupid<\/em>. This means we&#8217;re giving up on <strong>100,000<\/strong> valid passwords, thereby reducing our search space by <strong>10%<\/strong>!<\/p>\n<p>I suspect in both cases the reasoning is the same: if you start with a <strong>0<\/strong>, and we represent it as a number, it won&#8217;t make up for the same number of digits we intended it to.<\/p>\n<p>In the case of your Credit Card company, there is no excuse. What&#8217;s the problem with padding with zeros till you make those six digits?<\/p>\n<p>In the case of MySQL&#8217;s <strong>DATETIME<\/strong>, I can see a weak reasoning. Read <a href=\"http:\/\/dev.mysql.com\/doc\/refman\/5.1\/en\/datetime.html\">this page on the docs<\/a> to find out that a <strong>DATETIME<\/strong> can be represented in many forms, and can be automatically deduced from a string in many formats. Both strings <strong>&#8216;110307095100&#8217;<\/strong> and <strong>&#8216;20110307095100&#8217;<\/strong> make for the same <strong>DATETIME<\/strong> value. It is based on the number of characters in your text, that the parsing decides how to act.<\/p>\n<p>The fact the first year is <strong>1000<\/strong> makes the number of digits predictable.<\/p>\n<h4>My thoughts?<\/h4>\n<p>I don&#8217;t see why I should care about automatically converting texts of different formats to a <strong>DATETIME<\/strong>. As a programmer, I&#8217;m perfectly content with strict typing. I don&#8217;t mind passing around only texts of the form <strong>&#8216;YYYY-MM-DD HH:MM:SS&#8217;<\/strong> (or, better yet, passing date objects and letting my connector do the translation). Moreover, I prefer it that way! It makes me feel safer, that I haven&#8217;t passed a wrong text by mistake, to be silently accepted.<\/p>\n<p>For this reason I don&#8217;t like the idea of losing the ability to use <strong>DATETIME<\/strong> on <strong>1,000<\/strong> lost years. As far as I can tell, this is a MySQL specific issue; there is no <strong>ANSI SQL<\/strong> for <strong>DATETIME<\/strong>.<\/p>\n<p>[<strong>UPDATE<\/strong>:\u00a0 Sheeri <a href=\"http:\/\/palominodb.com\/blog\/2011\/05\/23\/datetime-vs-timestamp\">notes<\/a> the biggest difference: <strong>DATETIME<\/strong> does not support time zones. A good discussion is also available on <a href=\"http:\/\/bit.ly\/oursql046\">OurSQL<\/a>]<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>They both look the same, have roughly the same use. Nevertheless, they differ in many respects. I&#8217;ll note the difference, and note a few pitfalls and peculiarities. Range TIMESTAMP starts with the epoch, &#8216;1970-01-01 00:00:01&#8217; UTC and ends with &#8216;2038-01-19 03:14:07&#8217; UTC. This is all very nice today, and may actually hold up till our [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"enabled":false},"version":2}},"categories":[5],"tags":[18],"class_list":["post-3361","post","type-post","status-publish","format-standard","hentry","category-mysql","tag-data-types"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2bZZp-Sd","_links":{"self":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/3361","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/comments?post=3361"}],"version-history":[{"count":15,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/3361\/revisions"}],"predecessor-version":[{"id":3665,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/posts\/3361\/revisions\/3665"}],"wp:attachment":[{"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/media?parent=3361"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/categories?post=3361"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code.openark.org\/blog\/wp-json\/wp\/v2\/tags?post=3361"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}