<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>my tech blog &#187; utc</title>
	<atom:link href="http://billauer.se/blog/tag/utc/feed/" rel="self" type="application/rss+xml" />
	<link>https://billauer.se/blog</link>
	<description>Anything I found worthy to write down.</description>
	<lastBuildDate>Thu, 12 Mar 2026 11:36:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<item>
		<title>Why MySQL&#8217;s (SQL) DATETIME can and should be avoided</title>
		<link>https://billauer.se/blog/2009/03/mysql-datetime-epoch-unix-time/</link>
		<comments>https://billauer.se/blog/2009/03/mysql-datetime-epoch-unix-time/#comments</comments>
		<pubDate>Sun, 15 Mar 2009 14:58:24 +0000</pubDate>
		<dc:creator>eli</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[datetime]]></category>
		<category><![CDATA[epoch]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[time]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[utc]]></category>

		<guid isPermaLink="false">https://billauer.se/blog/?p=34</guid>
		<description><![CDATA[I warmly recommend reading the comments at the bottom of this page, many of which go against my point. While I still stand behind every word I said, in particular for web applications (which I believe is the vast majority of MySQL use), the comments below make some valid points, and single out cases where [...]]]></description>
			<content:encoded><![CDATA[<div style="border: 2px solid #9b9; margin: 20px 5px 50px 5px; padding: 15px 5px 0 5px;"><i></p>
<p>I warmly recommend reading the comments at the bottom of this page, many of which go against my point. While I still stand behind every word I said, in particular for web applications (which I believe is the vast majority of MySQL use), the comments below make some valid points, and single out cases where DATETIME actually <b>is</b> the right thing.</p>
<p>
Needless to say, this is a discussion, and we&#8217;re all free to make our own mistakes.</p>
<p></i></div>
<h2>SQL DATETIME sucks</h2>
<p>MySQL, among other databases, has a column type called DATETIME. Its name seems to mislead people into thinking that it&#8217;s suitable for storing time of events. Or suitable for anything.</p>
<p>This is a general SQL thing, by the way, but I&#8217;ll demonstrate it on MySQL.</p>
<p>I often find this column type in other people&#8217;s database schemas, and I wonder if the designer gave it a thought before using it. It&#8217;s true, that in the beginning it looks simple:</p>
<pre>mysql&gt; CREATE TABLE stupid_date ( thedate DATETIME, PRIMARY KEY (thedate) );
Query OK, 0 rows affected (0.04 sec)

mysql&gt; INSERT INTO stupid_date(thedate) VALUES ( NOW() );
Query OK, 1 row affected (0.03 sec)

mysql&gt; SELECT * FROM stupid_date;
+---------------------+
| thedate             |
+---------------------+
| 2009-03-15 14:01:43 |
+---------------------+
1 row in set (0.00 sec)</pre>
<p>That was way too cute, wasn&#8217;t it? We also have the NOW() function, which fits in exactly, and puts the current time! Yay! Yay! And if the timestamp looks old-fashioned to you, I suppose there is a reason for that.</p>
<p>But wait, there are two major problems. The first one is that the time is given in the host&#8217;s local time. That was fair enough before the internet was invented. But today a web server can be a continent away. DATETIME will show you the local time of the server, not yours. There are SQL functions to convert timezones, of course. Are you sure that you want to deal with them? What happens when you want to move your database to a server in another timezone? What about daylight saving time? Local time is one big YUCK.</p>
<p><em>(Update: As commented below, the real stupidity is to use NOW(), and not UTC_TIMESTAMP(). The latter gives the UTC time, as its name implies)</em></p>
<p>Problem number two: Most applications don&#8217;t care what the absolute time is. The current time is commonly used to calculate how much time has elapsed since a certain event. To filter elements according to if they were X seconds before now. Is the user still logged in? Has 24 hours elapsed since the last warning email was sent? And so on.</p>
<p>&#8220;Solution&#8221;: The SQL language supplies a variety of COBOL-like functions to calculate whatever we can ask for. And also an opportunity to get things horribly wrong, because the SQL statement became way too complicated.</p>
<h2>Use POSIX time() instead</h2>
<p>Sorry, didn&#8217;t mean to scare you off. It&#8217;s really simple: Any modern operating system, even Windows, will readily supply you with the number of seconds since January 1, 1970, midnight, UTC (that is, more or less GMT). This is also called &#8220;seconds since the Epoch&#8221; or &#8220;UNIX time&#8221;.</p>
<p>No matter where the computer is, what timezone it uses or what programming language you&#8217;re using, this simple integer representation will show the same number at any given moment.</p>
<p>You can, in fact, obtain this number from MySQL directly:</p>
<pre>mysql&gt; SELECT UNIX_TIMESTAMP(thedate) FROM stupid_date;
+-------------------------+
| UNIX_TIMESTAMP(thedate) |
+-------------------------+
|              1237118503 |
+-------------------------+
1 row in set (0.00 sec)</pre>
<p>This means, that 1237118503 seconds elapsed since the Epoch (which is a global time point) until 14:01:43 in Israeli <span style="text-decoration: underline;">LOCAL time </span>of the day I wrote this post. So now we have an integer number to work with, which is handy for calculations, but things will still get messy if we try to move the database to another server.</p>
<h2>Store the number instead</h2>
<p>If we are interested in working with integers, why not store the integer itself in the database? We could go:</p>
<pre>mysql&gt; CREATE TABLE smart_date ( thedate INTEGER UNSIGNED, PRIMARY KEY (thedate) );
Query OK, 0 rows affected (0.00 sec)

mysql&gt; INSERT INTO smart_date(thedate) VALUES (1237118503);
Query OK, 1 row affected (0.00 sec)

mysql&gt; SELECT * FROM smart_date;
+------------+
| thedate    |
+------------+
| 1237118503 |
+------------+
1 row in set (0.00 sec)</pre>
<p>That wasn&#8217;t very impressive, was it? The first question would be &#8220;OK, how do I get this magic number, now that I don&#8217;t have the NOW() function?&#8221;</p>
<p>The short and not-so-clever answer is that you could always use MySQL&#8217;s UNIX_TIMESTAMP( NOW() ) for this. The better answer is that no matter which scripting or programming language you&#8217;re using, this number is very easy to obtain. I&#8217;ll show examples below.</p>
<p>As for the magnitude of this number, yes, it&#8217;s pretty big. But it will fit a signed 32-bit integer until year 2038. I presume that nobody will use 32-bit integers by then.</p>
<p>And finally, one could argue that DATETIME is convenient when reading from the database directly. True. But for that specific issue we have the FROM_UNIXTIME() function:</p>
<pre>mysql&gt; SELECT FROM_UNIXTIME(thedate) FROM smart_date;
+------------------------+
| FROM_UNIXTIME(thedate) |
+------------------------+
| 2009-03-15 14:01:43    |
+------------------------+
1 row in set (0.00 sec)</pre>
<p>And again, this is given in the computer&#8217;s local time. Which is fine, because it&#8217;s intended to be read by humans. In particular, humans who easily translate time differences between their server and themselves.</p>
<h2>Obtaining Epoch time</h2>
<p>Just to prove that it&#8217;s easy to know what the &#8220;Epoch time&#8221; is in any language, here are a few examples. Wherever it&#8217;s really simple, I&#8217;m showing how to convert this format to human-readable format.</p>
<p>In Perl:</p>
<pre>print time();
print scalar localtime time(); # Local time for humans</pre>
<p>In PHP:</p>
<pre>&lt;?php
echo time();
echo date('r', time() ); // Local time for humans
?&gt;</pre>
<p>In Python:</p>
<pre>from time import time;
print time();</pre>
<p>(note that the time is returned as a float number with higher precision)</p>
<p>In C:</p>
<pre>#include &lt;time.h&gt;
#include &lt;stdio.h&gt;

int main () {
  int now = time(NULL);

  printf("%d seconds since the Epoch\n", now);
  return 0;
}</pre>
<p>In JavaScript:</p>
<pre>&lt;script language="JavaScript" type="text/javascript"&gt;
now = new Date();
alert( now.getTime() / 1000 );
&lt;/script&gt;</pre>
<p>In this case, the time is shown with a fractional resolution.</p>
<p>The JavaScript example is not really useful for a database application, because the time is measured at the computer showing the page. In a website application, this is just anybody&#8217;s computer clock, which may be wrong. But it&#8217;s yet another example of how this time representation is widely available.</p>
<h2>Conclusion</h2>
<p>Drop those DATETIME columns from your tables, and use a simple, robust and handy format to represent time. Don&#8217;t let the database play around with a sensitive issue like time, and don&#8217;t risk getting confused by different functions when calculating time differences. Just because the DATETIME column type exists, it doesn&#8217;t mean there is a reason to use it.</p>
<p>Enjoy the database on what it&#8217;s best at: Storing and collecting information.</p>
]]></content:encoded>
			<wfw:commentRss>https://billauer.se/blog/2009/03/mysql-datetime-epoch-unix-time/feed/</wfw:commentRss>
		<slash:comments>93</slash:comments>
		</item>
	</channel>
</rss>
