user59: I've made a clock using an Arduino, but the time seems to drift.  I am aware of the rollover issue; the clock seems to drift by about 15 minutes over the course of a week.
I'm using a custom PCB with this resonator from Digi-key.  The code reads the millis() function at the beginning of each loop, and works from that value.
My question is:  How can I measure time with an Arduino, accurately enough to make a passable desk clock?

user79: I understand a lot of the spirit with Arduino is being frugal and occasionally trudging through a problem. I use Arduino (and now chipKIT, since it's got 10x the RAM and 10x the clock speed) for my workplace and I need "peripheral functions" to be up to speed and working as quickly as possible.
I use the sparkfun real time clock in one of my projects and am very happy with it. They also have a "Dead on" variant.

user83: If you don't want to use extra hardware like an Real Time Clock (eg. DSDS1307), you can significantly improve timing accuracy by disabling all unused interrupts. By default Arduino sketches come with various interrupt routines enabled and often they are not used for actually your sketch. Quickest way to find out if you can do without it to try and disable them by issuing noInterrupts();

user60: The resonator you specified has a 0.3% stability, where the crystal or crystal oscillator (as mentioned by Ricardo) is 50ppm. Many times more stable. Not to even mention the temperature drift of resonator is horrible. Heating by sunlight will change it. Hence a resonator should not be used for keeping time over long periods. 
Hence using either a crystal or crystal oscillator will get what you want. Either using it on the ATmega and set the fuses respectively or us one connected to an RTC.

user46: Note: although my answer was accepted and has a higher vote score, make sure you read Edgar Bonet's great answer on how to make your Arduino keep time without an RTC.
I've been quite successful in using the DS1307 Real Time Clock. Here's a link to its datasheet.
Below are some of its features:

It uses IC interface for communication with Arduino, making it easy to program using the right libraries (available on the Net).
It is connected to Arduino through the SCL and SDA pins (analog A4 and A5 respectively), thus only using 2 pins.
It requires very little external components to run.
IT can be connected to a coin cell battery so it will keep time even while the Arduino is turned off. In its low power mode, the coin cell battery lasts for years.
It drifts very little (in my case it only drifts a few seconds per week).
It's not very expensive.

If you don't intend to use an RTC, you can replace the crystal that is commonly used to provide clock to arduino for a crystal oscillator module like this one from Farnel or this other one. They come in 4 pin packages like in the images below. They will generate a much more precise clock for your arduino.



Both modules mentioned have tolerances of 50 ppm and operate at 5V.
Again, just to be clear, these crystal oscillator modules are not to be confused with regular 2 pin crystal like this below. Those are part of the circuitry of external clocks for MCUs, for example.


user7508: You do not need an RTC to build a clock: the ATmega chip has all the
hardware needed to perform the duties of the RTC itself. Here is how:

Get a 32768 Hz watch crystal: either buy it or disassemble an
old clock. These crystals, specifically designed for time keeping,
have an extremely small temperature drift. You would also need one
of those if you wanted to use an RTC chip.
Configure the fuses of your ATmega to run off the 8 MHz RC
oscillator. This will make your millis() function horribly
inaccurate, and also free the XTAL1 and XTAL2 pins.
Connect the watch crystal to the TOSC1 and TOSC2 pins. These are the
same pins as XTAL1 and XTAL2 (9 and 10 on the 328P). The different
names are used to mean different functions.
Configure the Timer/Counter 2 for asynchronous operation, normal
counting mode, prescaler set to 128, and enable the timer overflow
interrupt.

Now you will get a TIMER2_OVF interrupt at a very steady rate of once
per second. You only need to advance the clock display by one second in
the ISR. In between the interrupts, you can put the MCU in very deep
sleep (power-save sleep mode: nothing runs but Timer/Counter 2) and run
for years on a couple of AA cells. Unless the display is power-hungry,
obviously.
I did exactly this to build my 24-hour one handed wall
clock.
This link points now to the English translation of the original
documentation in French.
Quartz calibration
If you do not calibrate your quartz, you can expect a significant drift,
typically a few seconds per week. The drift rate depends on the
stray capacitance of the traces that connect the crystal to the MCU. In
principle, it could be removed by adding some extra, finely tuned
capacitance. It is worth noting that you would have the same drift
problem with an RTC.
If you are satisfied with this kind of accuracy, then live with it and
be happy. However, if you care to measure the drift, you will notice
that it is very stable. You can then easily compensate for it in
software, and achieve an accuracy of a few seconds per year.
The algorithm for correcting the drift is very simple. From the measured
drift, you figure out the precise delay between the interrupts, which
should be very close to 109 nanoseconds, then:
#define ONE_SECOND    1000000000  // in nanoseconds
#define ONE_INTERRUPT  999993482  // for example

ISR(TIMER2_OVF_vect)
{
    static uint32_t unaccounted_time;

    unaccounted_time += ONE_INTERRUPT;
    while (unaccounted_time >= ONE_SECOND) {
        advance_display_by_one_second();
        unaccounted_time -= ONE_SECOND;
    }
}

In the above example, the quartz is slightly too fast, and the software
compensates by “missing” a tick every few days. If the quartz was too
slow, the same code would instead double-tick once every few days.
This kind of calibration could also be done for an RTC, but it would be
significantly more complex because the RTC reports the time in a
broken-down form that does not naturally lend itself to arithmetic
operations.

59: <p>I've made a clock using an Arduino, but the time seems to drift.  I am aware of the <a href="https://arduino.stackexchange.com/questions/1/is-an-arduino-capable-of-running-24-7/2#2">rollover</a> issue; the clock seems to drift by about 15 minutes over the course of a week.</p>

<p>I'm using a custom PCB with <a href="http://www.digikey.com/product-search/en/crystals-and-oscillators/resonators/852887?k=x908-nd">this resonator</a> from Digi-key.  The code reads the millis() function at the beginning of each loop, and works from that value.</p>

<p>My question is:  How can I measure time with an Arduino, accurately enough to make a passable desk clock?</p>
 79: <p>I understand a lot of the spirit with Arduino is being frugal and occasionally trudging through a problem. I use Arduino (and now chipKIT, since it's got 10x the RAM and 10x the clock speed) for my workplace and I need "peripheral functions" to be up to speed and working as quickly as possible.</p>

<p>I use the sparkfun real time clock in one of my projects and am very happy with it. They also have a <a href="https://www.sparkfun.com/products/10160" rel="nofollow">"Dead on" variant</a>.</p>
 83: <p>If you don't want to use extra hardware like an Real Time Clock (eg. DSDS1307), you can significantly improve timing accuracy by disabling all unused interrupts. By default Arduino sketches come with various interrupt routines enabled and often they are not used for actually your sketch. Quickest way to find out if you can do without it to try and disable them by issuing <a href="http://arduino.cc/en/Reference/Interrupts" rel="nofollow"><code>noInterrupts();</code></a></p>
 60: <p>The resonator you specified has a 0.3% stability, where the crystal or crystal oscillator (as mentioned by Ricardo) is 50ppm. Many times more stable. Not to even mention the temperature drift of resonator is horrible. Heating by sunlight will change it. Hence a resonator should not be used for keeping time over long periods. </p>

<p>Hence using either a crystal or crystal oscillator will get what you want. Either using it on the ATmega and set the fuses respectively or us one connected to an RTC.</p>
 46: <p><em>Note: although my answer was accepted and has a higher vote score, make sure you read <a href="https://arduino.stackexchange.com/a/9039/46">Edgar Bonet's great answer</a> on how to make your Arduino keep time without an RTC.</em></p>

<p>I've been quite successful in using the DS1307 Real Time Clock. Here's a link to its <a href="http://datasheets.maximintegrated.com/en/ds/DS1307.pdf" rel="nofollow noreferrer">datasheet</a>.</p>

<p>Below are some of its features:</p>

<ul>
<li><p>It uses IC interface for communication with Arduino, making it easy to program using the right libraries (available on the Net).</p></li>
<li><p>It is connected to Arduino through the SCL and SDA pins (analog A4 and A5 respectively), thus only using 2 pins.</p></li>
<li><p>It requires very little external components to run.</p></li>
<li><p>IT can be connected to a coin cell battery so it will keep time even while the Arduino is turned off. In its low power mode, the coin cell battery lasts for years.</p></li>
<li><p>It drifts very little (in my case it only drifts a few seconds per week).</p></li>
<li><p>It's not very expensive.</p></li>
</ul>

<p>If you don't intend to use an RTC, you can replace the crystal that is commonly used to provide clock to arduino for a <strong>crystal oscillator module</strong> like <a href="http://datasheets.maximintegrated.com/en/ds/DS1307.pdf" rel="nofollow noreferrer">this one from Farnel</a> or <a href="http://www.digikey.com/product-detail/en/ECS-2200BX-200/XC1188-ND/827295" rel="nofollow noreferrer">this other one</a>. They come in 4 pin packages like in the images below. They will generate a much more precise clock for your arduino.</p>

<p><img src="https://i.stack.imgur.com/OjaoR.jpg" alt="Crystal oscillator image">
<img src="https://i.stack.imgur.com/aTIAn.jpg" alt="Crystal oscillator image">
<img src="https://i.stack.imgur.com/ay7KD.png" alt="Crystal oscillator image"></p>

<p>Both modules mentioned have tolerances of 50 ppm and operate at 5V.</p>

<p>Again, just to be clear, these crystal oscillator modules are not to be confused with regular 2 pin <strong>crystal</strong> like this below. Those are part of the circuitry of external clocks for MCUs, for example.</p>

<p><img src="https://i.stack.imgur.com/a52VR.png" alt="Crystal oscillator"></p>
 7508: <p>You do not need an RTC to build a clock: the ATmega chip has all the
hardware needed to perform the duties of the RTC itself. Here is how:</p>

<ol>
<li><p>Get a 32768&nbsp;Hz watch crystal: either buy it or disassemble an
old clock. These crystals, specifically designed for time keeping,
have an <em>extremely</em> small temperature drift. You would also need one
of those if you wanted to use an RTC chip.</p></li>
<li><p>Configure the fuses of your ATmega to run off the 8&nbsp;MHz RC
oscillator. This will make your <code>millis()</code> function horribly
inaccurate, and also free the XTAL1 and XTAL2 pins.</p></li>
<li><p>Connect the watch crystal to the TOSC1 and TOSC2 pins. These are the
same pins as XTAL1 and XTAL2 (9 and 10 on the 328P). The different
names are used to mean different functions.</p></li>
<li><p>Configure the Timer/Counter 2 for asynchronous operation, normal
counting mode, prescaler set to 128, and enable the timer overflow
interrupt.</p></li>
</ol>

<p>Now you will get a TIMER2_OVF interrupt at a very steady rate of once
per second. You only need to advance the clock display by one second in
the ISR. In between the interrupts, you can put the MCU in very deep
sleep (power-save sleep mode: nothing runs but Timer/Counter 2) and run
for years on a couple of AA cells. Unless the display is power-hungry,
obviously.</p>

<p>I did exactly this to build my <a href="http://unsecure.logre.eu/wiki/Horloge_analogique_24h/en">24-hour one handed wall
clock</a>.
This link points now to the English translation of the original
documentation in French.</p>

<h2>Quartz calibration</h2>

<p>If you do not calibrate your quartz, you can expect a significant drift,
typically <strong>a few seconds per week</strong>. The drift rate depends on the
stray capacitance of the traces that connect the crystal to the MCU. In
principle, it could be removed by adding some extra, finely tuned
capacitance. It is worth noting that you would have <em>the same drift
problem</em> with an RTC.</p>

<p>If you are satisfied with this kind of accuracy, then live with it and
be happy. However, if you care to measure the drift, you will notice
that it is very stable. You can then easily compensate for it in
software, and achieve an accuracy of <strong>a few seconds per year</strong>.</p>

<p>The algorithm for correcting the drift is very simple. From the measured
drift, you figure out the precise delay between the interrupts, which
should be very close to 10<sup>9</sup>&nbsp;nanoseconds, then:</p>

<pre class="lang-c prettyprint-override"><code>#define ONE_SECOND    1000000000  // in nanoseconds
#define ONE_INTERRUPT  999993482  // for example

ISR(TIMER2_OVF_vect)
{
    static uint32_t unaccounted_time;

    unaccounted_time += ONE_INTERRUPT;
    while (unaccounted_time &gt;= ONE_SECOND) {
        advance_display_by_one_second();
        unaccounted_time -= ONE_SECOND;
    }
}
</code></pre>

<p>In the above example, the quartz is slightly too fast, and the software
compensates by “missing” a tick every few days. If the quartz was too
slow, the same code would instead double-tick once every few days.</p>

<p>This kind of calibration could also be done for an RTC, but it would be
significantly more complex because the RTC reports the time in a
broken-down form that does not naturally lend itself to arithmetic
operations.</p>
