aboutsummaryrefslogtreecommitdiffstats
path: root/erts/doc/src/time_correction.xml
diff options
context:
space:
mode:
Diffstat (limited to 'erts/doc/src/time_correction.xml')
-rw-r--r--erts/doc/src/time_correction.xml902
1 files changed, 902 insertions, 0 deletions
diff --git a/erts/doc/src/time_correction.xml b/erts/doc/src/time_correction.xml
new file mode 100644
index 0000000000..236fe679cb
--- /dev/null
+++ b/erts/doc/src/time_correction.xml
@@ -0,0 +1,902 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1999</year><year>2015</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>Time and Time Correction in Erlang</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2013-08-28</date>
+ <rev>PA1</rev>
+ <file>time_correction.xml</file>
+ </header>
+
+ <section>
+ <title>New Extended Time Functionality</title>
+ <note><p>As of OTP 18 (<c>ERTS</c> version 7.0) the time functionality of
+ Erlang has been extended. This includes a
+ <seealso marker="#The_New_Time_API">new API</seealso>
+ for time and
+ <seealso marker="#Time_Warp_Modes">time warp
+ modes</seealso> that alter the system behavior when
+ system time changes.</p>
+
+ <p>The <seealso marker="#No_Time_Warp_Mode">default
+ time warp mode</seealso> has the same behavior as before, and the
+ old API still works. Thus, you are not required to change
+ anything unless you want to. However, <em>you are strongly
+ encouraged to use the new API</em> instead of the old API based
+ on <seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso>.
+ <c>erlang:now/0</c> is deprecated, as it is and
+ will be a scalability bottleneck.</p>
+
+ <p>By using the new API, you
+ automatically get scalability and performance improvements. This
+ also enables you to use the
+ <seealso marker="#Multi_Time_Warp_Mode">multi-time warp mode</seealso>
+ that improves accuracy and precision of time measurements.</p>
+ </note>
+ </section>
+
+ <section>
+ <title>Terminology</title>
+ <p>To make it easier to understand this section, some terms
+ are defined. This is a mix of our own terminology
+ (Erlang/OS system time, Erlang/OS monotonic time, time warp)
+ and globally accepted terminology.</p>
+
+ <marker id="Monotonically_Increasing"/>
+ <section>
+ <title>Monotonically Increasing</title>
+ <p>In a monotonically increasing sequence of values, all values
+ that have a predecessor are either larger than or equal to its
+ predecessor.</p>
+ </section>
+
+ <marker id="Strictly_Monotonically_Increasing"/>
+ <section>
+ <title>Strictly Monotonically Increasing</title>
+ <p>In a strictly monotonically increasing sequence of values,
+ all values that have a predecessor are larger than its
+ predecessor.</p>
+ </section>
+
+ <marker id="UT1"/>
+ <section>
+ <title>UT1</title>
+ <p>Universal Time. UT1 is based on the rotation of the earth
+ and conceptually means solar time at 0° longitude.</p>
+ </section>
+
+ <marker id="UTC"/>
+ <section>
+ <title>UTC</title>
+ <p>Coordinated Universal Time. UTC almost aligns with
+ <seealso marker="#UT1">UT1</seealso>. However, UTC uses the
+ SI definition of a second, which has not exactly the same length
+ as the second used by UT1. This means that UTC slowly drifts from
+ UT1. To keep UTC relatively in sync with UT1, leap seconds
+ are inserted, and potentially also deleted. That is, an UTC day can
+ be 86400, 86401, or 86399 seconds long.</p>
+ </section>
+
+ <marker id="POSIX_Time"/>
+ <section>
+ <title>POSIX Time</title>
+ <p>Time since
+ <url href="http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap03.html#tag_21_03_00_17">Epoch</url>.
+ Epoch is defined to be 00:00:00 <seealso marker="#UTC">UTC</seealso>,
+ 1970-01-01.
+ <url href="http://pubs.opengroup.org/onlinepubs/009604499/basedefs/xbd_chap04.html#tag_04_14">A day in POSIX time</url>
+ is defined to be exactly 86400 seconds long. Strangely enough
+ Epoch is defined to be a time in UTC, and UTC has another
+ definition of how long a day is. Quoting the Open Group
+ <url href="http://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xbd_chap04.html#tag_21_04_15">"POSIX time is therefore not necessarily UTC, despite its appearance"</url>.
+ The effect of this is that when an UTC leap second is
+ inserted, POSIX time either stops for a second, or repeats the
+ last second. If an UTC leap second would be deleted (which has not
+ happened yet), POSIX time would make a one second leap forward.</p>
+ </section>
+
+ <marker id="Time_Resolution"/>
+ <section>
+ <title>Time Resolution</title>
+ <p>The shortest time interval that can be distinguished when
+ reading time values.</p>
+ </section>
+
+ <marker id="Time_Precision"/>
+ <section>
+ <title>Time Precision</title>
+ <p>The shortest time interval that can be distinguished
+ repeatedly and reliably when reading time values. Precision
+ is limited by the
+ <seealso marker="#Time_Resolution">resolution</seealso>, but
+ resolution and precision can differ significantly.</p>
+ </section>
+
+ <marker id="Time_Accuracy"/>
+ <section>
+ <title>Time Accuracy</title>
+ <p>The correctness of time values.</p>
+ </section>
+
+ <marker id="Time_Warp"/>
+ <section>
+ <title>Time Warp</title>
+ <p>A time warp is a leap forwards or backwards in time. That
+ is, the difference of time values taken before and after the
+ time warp does not correspond to the actual elapsed time.</p>
+ </section>
+
+ <marker id="OS_System_Time"/>
+ <section>
+ <title>OS System Time</title>
+ <p>The operating systems view of
+ <seealso marker="#POSIX_Time">POSIX time</seealso>. To
+ retrieve it, call
+ <seealso marker="kernel:os#system_time/0"><c>os:system_time()</c></seealso>.
+ This may or may not be an accurate view of POSIX time. This time
+ may typically be adjusted both backwards and forwards without
+ limitation. That is, <seealso marker="#Time_Warp">time warps</seealso>
+ may be observed.</p>
+
+ <p>To get information about the Erlang runtime
+ system's source of OS system time, call
+ <seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso>.</p>
+ </section>
+
+ <marker id="OS_Monotonic_Time"/>
+ <section>
+ <title>OS Monotonic Time</title>
+ <p>A monotonically increasing time provided by the operating
+ system. This time does not leap and has a relatively steady
+ frequency although not completely correct. However, it is not
+ uncommon that OS monotonic time stops if the system is
+ suspended. This time typically increases since some
+ unspecified point in time that is not connected to
+ <seealso marker="#OS_System_Time">OS system time</seealso>.
+ This type of time is not necessarily provided by all
+ operating systems.</p>
+
+ <p>To get information about the Erlang
+ runtime system's source of OS monotonic time, call
+ <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>.</p>
+ </section>
+
+ <marker id="Erlang_System_Time"/>
+ <section>
+ <title>Erlang System Time</title>
+ <p>The Erlang runtime systems view of
+ <seealso marker="#POSIX_Time">POSIX time</seealso>. To
+ retrieve it, call
+ <seealso marker="erlang#system_time/0"><c>erlang:system_time()</c></seealso>.</p>
+
+ <p>This time may or may not be an accurate view of POSIX time,
+ and may
+ or may not align with <seealso marker="#OS_System_Time">OS system
+ time</seealso>. The runtime system works towards aligning the two
+ system times. Depending on the
+ <seealso marker="#Time_Warp_Modes">time warp mode</seealso> used,
+ this can be achieved by letting Erlang
+ system time perform a <seealso marker="#Time_Warp">time
+ warp</seealso>.</p>
+ </section>
+
+ <marker id="Erlang_Monotonic_Time"/>
+ <section>
+ <title>Erlang Monotonic Time</title>
+ <p>A monotonically increasing time provided by the
+ Erlang runtime system. Erlang monotonic time increases since
+ some unspecified point in time. To retrieve it, call
+ <seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time()</c></seealso>.
+ </p>
+
+ <p>The <seealso marker="#Time_Accuracy">accuracy</seealso> and
+ <seealso marker="#Time_Precision">precision</seealso> of Erlang
+ monotonic time heavily depends on the following:</p>
+
+ <list type="bulleted">
+ <item>Accuracy and precision of
+ <seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso>
+ </item>
+ <item>Accuracy and precision of
+ <seealso marker="#OS_System_Time">OS system time</seealso>
+ </item>
+ <item><seealso marker="#Time_Warp_Modes">time warp mode</seealso> used
+ </item>
+ </list>
+
+ <p>On a system without OS monotonic time, Erlang monotonic
+ time guarantees monotonicity, but cannot give
+ other guarantees. The frequency adjustments made to
+ Erlang monotonic time depend on the time warp mode used.</p>
+
+ <p>Internally in the runtime system, Erlang monotonic
+ time is the "time engine" that is used for more or less
+ everything that has anything to do with time. All timers,
+ regardless of it is a <c>receive ... after</c> timer, BIF timer,
+ or a timer in the <c>timer</c> module, are triggered
+ relative Erlang monotonic time. Even
+ <seealso marker="#Erlang_System_Time">Erlang system
+ time</seealso> is based on Erlang monotonic time.
+ By adding current Erlang monotonic time with current time
+ offset, you get current Erlang system time.</p>
+
+ <p>To retrieve current time offset, call
+ <seealso marker="erlang#time_offset/0"><c>erlang:time_offset/0</c></seealso>.
+ </p>
+ </section>
+
+ </section>
+
+ <section>
+ <title>Introduction</title>
+ <p>Time is vital to an Erlang program and, more importantly, <em>correct</em>
+ time is vital to an Erlang program. As Erlang is a language with
+ soft real-time properties and we can express
+ time in our programs, the Virtual Machine and the language must be
+ careful about what is considered a correct time and in
+ how time functions behave.</p>
+
+ <p>When Erlang was designed, it was assumed that the wall
+ clock time in the system showed a monotonic time moving forward at
+ exactly the same pace as the definition of time. This more or less meant
+ that an atomic clock (or better time source) was expected to be attached
+ to your hardware and that the hardware was then expected to be
+ locked away from any human tinkering forever. While this can be a
+ compelling thought, it is simply never the case.</p>
+
+ <p>A "normal" modern computer cannot keep time, not on itself and
+ not unless you have a chip-level atomic clock wired to it. Time,
+ as perceived by your computer, must normally be corrected. Hence
+ the Network Time Protocol (NTP) protocol, together with the <c>ntpd</c>
+ process, does its best to keep your computer time in sync with
+ the correct time. Between NTP corrections, usually a
+ less potent time-keeper than an atomic clock is used.</p>
+
+ <p>However, NTP is not fail-safe. The NTP server can be unavailable,
+ <c>ntp.conf</c> can be wrongly configured, or your computer may
+ sometimes be disconnected from Internet. Furthermore, you can have a
+ user (or even system administrator) who thinks the correct
+ way to handle Daylight Saving Time is to adjust the clock one
+ hour two times a year (which is the incorrect way to do it).
+ To complicate things further, this user fetched your
+ software from Internet and has not considered what
+ the correct time is as perceived by a computer. The user does
+ not care about keeping the wall clock in sync with the correct
+ time. The user expects your program to have unlimited knowledge
+ about the time.</p>
+
+ <p>Most programmers also expect time to be reliable, at least until
+ they realize that the wall clock time on their workstation is off by
+ a minute. Then they set it to the correct time, but most probably
+ not in a smooth way.</p>
+
+ <p>The number of problems that arise when you always expect the wall clock
+ time on the system to be correct can be immense. Erlang therefore
+ introduced the "corrected estimate of time", or the "time
+ correction", many years ago. The time correction relies on the fact
+ that most operating systems have some kind of monotonic clock,
+ either a real-time extension or some built-in "tick counter" that is
+ independent of the wall clock settings. This counter can have
+ microsecond resolution or much less, but it has a drift that cannot
+ be ignored.</p>
+ </section>
+
+ <section>
+ <marker id="Time_Correction"/>
+ <title>Time Correction</title>
+ <p>If time correction is enabled, the Erlang runtime system
+ makes use of both
+ <seealso marker="#OS_System_Time">OS system time</seealso>
+ and <seealso marker="#OS_Monotonic_Time">OS monotonic time</seealso>,
+ to adjust the frequency of the Erlang
+ monotonic clock. Time correction ensures that
+ <seealso marker="#Erlang_Monotonic_Time">Erlang monotonic time</seealso>
+ does not warp and that the frequency is relatively accurate.
+ The type of frequency adjustments depends on the time warp mode used.
+ Section <seealso marker="#Time_Warp_Modes">Time Warp Modes</seealso>
+ provides more details.</p>
+
+ <p>By default time correction is enabled if support for
+ it exists on the specific platform. Support for it includes
+ both OS monotonic time, provided by the OS, and an
+ implementation in the Erlang runtime system using
+ OS monotonic time. To check if your system has support
+ for OS monotonic time, call
+ <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>.
+ To check if time correction is enabled on your system, call
+ <seealso marker="erlang#system_info_time_correction"><c>erlang:system_info(time_correction)</c></seealso>.</p>
+
+ <p>To enable or disable time correction, pass command-line argument
+ <seealso marker="erl#+c"><c>+c [true|false]</c></seealso>
+ to <c>erl</c>.</p>
+
+ <p>If time correction is disabled, Erlang monotonic time
+ may warp forwards or stop, or even freeze for extended
+ periods of time. There are then no guarantees that the frequency
+ of the Erlang monotonic clock is accurate or stable.</p>
+
+ <p><em>You typically never want to disable time correction</em>.
+ Previously a performance penalty was associated with time
+ correction, but nowadays it is usually the other way around.
+ If time correction is disabled, you probably get bad scalability,
+ bad performance, and bad time measurements.</p>
+ </section>
+
+ <section>
+ <marker id="Time_Warp_Safe_Code"/>
+ <title>Time Warp Safe Code</title>
+ <p>Time warp safe code can handle
+ a <seealso marker="#Time_Warp">time warp</seealso> of
+ <seealso marker="#Erlang_System_Time">Erlang system time</seealso>.</p>
+
+ <p><seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso>
+ behaves bad when Erlang system time warps. When Erlang
+ system time does a time warp backwards, the values returned
+ from <c>erlang:now/0</c> freeze (if you disregard the
+ microsecond increments made because of the actual call) until
+ OS system time reaches the point of the last value returned by
+ <c>erlang:now/0</c>. This freeze can continue for a long time. It
+ can take years, decades, and even longer until the freeze stops.</p>
+
+ <p>All uses of <c>erlang:now/0</c> are not necessarily
+ time warp unsafe. If you do not use it to get time, it
+ is time warp safe. However, <em>all uses of
+ <c>erlang:now/0</c> are suboptimal</em> from a performance
+ and scalability perspective. So you really want to replace
+ the use of it with other functionality. For examples
+ of how to replace the use of <c>erlang:now/0</c>, see Section
+ <seealso marker="#Dos_and_Donts">How to Work with the New
+ API</seealso>.</p>
+ </section>
+
+ <section>
+ <title>Time Warp Modes</title>
+ <marker id="Time_Warp_Modes"/>
+ <p>Current <seealso marker="#Erlang_System_Time">Erlang system
+ time</seealso> is determined by adding current
+ <seealso marker="erlang#monotonic_time/0">Erlang monotonic time</seealso>
+ with current
+ <seealso marker="erlang#time_offset/0">time offset</seealso>. The
+ time offset is managed differently depending on which time
+ warp mode you use.</p>
+
+ <p>To set the time warp mode, pass command-line argument
+ <seealso marker="erl#+C_"><c>+C
+ [no_time_warp|single_time_warp|multi_time_warp]</c></seealso>
+ to <c>erl</c>.</p>
+
+ <marker id="No_Time_Warp_Mode"/>
+ <section>
+ <title>No Time Warp Mode</title>
+ <p>The time offset is determined at runtime system start
+ and does not change later. This is the default behavior, but
+ not because it is the best mode (which it is not). It is
+ default <em>only</em> because this is how the runtime system
+ behaved until <c>ERTS</c> 7.0.
+ Ensure that your Erlang code that may execute during a time
+ warp is <seealso marker="#Time_Warp_Safe_Code">time warp
+ safe</seealso> before enabling other modes.</p>
+
+ <p>As the time offset is not allowed to change, time
+ correction must adjust the frequency of the Erlang
+ monotonic clock to align Erlang system time with OS
+ system time smoothly. A significant downside of this approach
+ is that we on purpose will use a faulty frequency on the
+ Erlang monotonic clock if adjustments are needed. This
+ error can be as large as 1%. This error will show up in all
+ time measurements in the runtime system.</p>
+
+ <p>If time correction is not enabled, Erlang monotonic
+ time freezes when OS system time leaps backwards.
+ The freeze of monotonic time continues until
+ OS system time catches up. The freeze can continue for
+ a long time. When OS system time leaps forwards,
+ Erlang monotonic time also leaps forward.</p>
+ </section>
+
+ <marker id="Single_Time_Warp_Mode"/>
+ <section>
+ <title>Single Time Warp Mode</title>
+ <p>This mode is more or less a backwards compatibility mode
+ as of its introduction.</p>
+
+ <p>On an embedded system it is not uncommon that the system
+ has no power supply, not even a battery, when it is
+ shut off. The system clock on such a system is typically
+ way off when the system boots. If
+ <seealso marker="#No_Time_Warp_Mode">no time warp mode</seealso>
+ is used, and the Erlang runtime system is started before
+ OS system time has been corrected, Erlang system time
+ can be wrong for a long time, centuries or even longer.</p>
+
+ <p>If you need to use Erlang code that is not
+ <seealso marker="#Time_Warp_Safe_Code">time warp safe</seealso>,
+ and you need to start the Erlang runtime system before OS
+ system time has been corrected, you may want to use the single
+ time warp mode.</p>
+
+ <note><p>There are limitations to when you can
+ execute time warp unsafe code using this mode. If it is possible
+ to use time warp safe code only, it is <em>much</em> better
+ to use the <seealso marker="#Multi_Time_Warp_Mode">multi-time
+ warp mode</seealso> instead.</p></note>
+
+ <p>Using the single time warp mode, the time offset is
+ handled in two phases:</p>
+
+ <taglist>
+ <tag>Preliminary Phase</tag>
+ <item>
+ <p>This phase starts when the runtime
+ system starts. A preliminary time offset based on
+ current OS system time is determined. This offset is from
+ now on to be fixed during the whole preliminary phase.</p>
+
+ <p>If time correction is enabled, adjustments to the
+ Erlang monotonic clock are made to keep its
+ frequency as correct as possible. However, <em>no</em>
+ adjustments are made trying to align Erlang system
+ time and OS system time. That is, during the preliminary phase
+ Erlang system time and OS system time can diverge
+ from each other, and no attempt is made to prevent this.</p>
+
+ <p>If time correction is disabled, changes in OS system
+ time affects the monotonic clock the same way as
+ when the <seealso marker="#No_Time_Warp_Mode">no time warp
+ mode</seealso> is used.</p>
+ </item>
+
+ <tag>Final Phase</tag>
+ <item>
+ <p>This phase begins when the user finalizes the time
+ offset by calling
+ <seealso marker="erlang#system_flag_time_offset"><c>erlang:system_flag(time_offset, finalize)</c></seealso>.
+ The finalization can only be performed once.</p>
+
+ <p>During finalization, the time offset is adjusted and
+ fixated so that current Erlang system time aligns with
+ current OS system time. As the time offset can
+ change during the finalization, Erlang system time
+ can do a time warp at this point. The time offset is
+ from now on fixed until the runtime system terminates.
+ If time correction has been enabled, the time
+ correction from now on also makes adjustments
+ to align Erlang system time with OS system
+ time. When the system is in the final phase, it behaves
+ exactly as in the <seealso marker="#No_Time_Warp_Mode">no
+ time warp mode</seealso>.</p>
+ </item>
+ </taglist>
+
+ <p>In order for this to work properly, the user must ensure
+ that the following two requirements are satisfied:</p>
+
+ <taglist>
+ <tag>Forward Time Warp</tag>
+ <item><p>The time warp made when finalizing the time offset
+ can only be done forwards without encountering problems.
+ This implies that the user must ensure that OS
+ system time is set to a time earlier or equal to actual
+ POSIX time before starting the Erlang runtime system.</p>
+
+ <p>If you are not sure that OS system time is correct,
+ set it to a time that is guaranteed to be earlier than
+ actual POSIX time before starting the Erlang runtime
+ system, just to be safe.</p>
+ </item>
+
+ <tag>Finalize Correct OS System Time</tag>
+ <item><p>OS system time must be correct when
+ the user finalizes the time offset.</p>
+ </item>
+ </taglist>
+
+ <p>If these requirements are not fulfilled, the system
+ may behave very bad.</p>
+
+ <p>Assuming that these requirements are fulfilled,
+ time correction is enabled, and that OS system time
+ is adjusted using a time adjustment protocol such as NTP,
+ only small adjustments of Erlang monotonic
+ time are needed to keep system times
+ aligned after finalization. As long as the system is not
+ suspended, the largest adjustments needed are for
+ inserted (or deleted) leap seconds.</p>
+
+ <warning><p>To use this mode, ensure that
+ all Erlang code that will execute in both phases are
+ <seealso marker="#Time_Warp_Safe_Code">time warp
+ safe</seealso>.</p>
+ <p>Code executing only in the final phase does not have
+ to be able to cope with the time warp.</p></warning>
+ </section>
+
+ <marker id="Multi_Time_Warp_Mode"/>
+ <section>
+ <title>Multi-Time Warp Mode</title>
+ <p><em>Multi-time warp mode in combination with time
+ correction is the preferred configuration</em>. This as
+ the Erlang runtime system have better performance, scale
+ better, and behave better on almost all platforms. In
+ addition, the accuracy and precision of time measurements
+ are better. Only Erlang runtime systems executing on
+ ancient platforms benefit from another configuration.</p>
+
+ <p>The time offset may change at any time without limitations.
+ That is, Erlang system time may perform time warps both
+ forwards and backwards at <em>any</em> time. As we align
+ Erlang system time with OS system time by changing
+ the time offset, we can enable a time correction that tries
+ to adjust the frequency of the Erlang monotonic clock to be as
+ correct as possible. This makes time measurements using
+ Erlang monotonic time more accurate and precise.</p>
+
+ <p>If time correction is disabled, Erlang monotonic time
+ leaps forward if OS system time leaps forward. If
+ OS system time leaps backwards, Erlang monotonic time
+ stops briefly, but it does not freeze for extended periods
+ of time. This as the time offset is changed to
+ align Erlang system time with OS system time.</p>
+
+ <warning><p>To use this mode, ensure that all
+ Erlang code that will execute on the runtime system is
+ <seealso marker="#Time_Warp_Safe_Code">time warp
+ safe</seealso>.</p></warning>
+ </section>
+ </section>
+
+ <section>
+ <title>New Time API</title>
+ <marker id="The_New_Time_API"/>
+ <p>The old time API is based on
+ <seealso marker="erlang#now/0"><c>erlang:now/0</c></seealso>.
+ <c>erlang:now/0</c> was intended to be used for many unrelated
+ things. This tied these unrelated operations together and
+ caused issues with performance, scalability, accuracy, and
+ precision for operations that did not need to have
+ such issues. To improve this, the new API spreads different
+ functionality over multiple functions.</p>
+
+ <p>To be backwards compatible, <c>erlang:now/0</c>
+ remains as is, but <em>you are strongly discouraged from using
+ it</em>. Many use cases of <c>erlang:now/0</c>
+ prevents you from using the new
+ <seealso marker="#Multi_Time_Warp_Mode">multi-time warp
+ mode</seealso>, which is an important part of this
+ new time functionality improvement.</p>
+
+ <p>Some of the new BIFs on some systems, perhaps surprisingly,
+ return negative integer values on a newly started runtime
+ system. This is not a bug, but a memory use optimization.</p>
+
+ <p>The new API consists of the following new BIFs:</p>
+
+ <list>
+ <item><p><seealso marker="erlang#convert_time_unit/3"><c>erlang:convert_time_unit/3</c></seealso></p></item>
+ <item><p><seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time/0</c></seealso></p></item>
+ <item><p><seealso marker="erlang#monotonic_time/1"><c>erlang:monotonic_time/1</c></seealso></p></item>
+ <item><p><seealso marker="erlang#system_time/0"><c>erlang:system_time/0</c></seealso></p></item>
+ <item><p><seealso marker="erlang#system_time/1"><c>erlang:system_time/1</c></seealso></p></item>
+ <item><p><seealso marker="erlang#time_offset/0"><c>erlang:time_offset/0</c></seealso></p></item>
+ <item><p><seealso marker="erlang#time_offset/1"><c>erlang:time_offset/1</c></seealso></p></item>
+ <item><p><seealso marker="erlang#timestamp/0"><c>erlang:timestamp/0</c></seealso></p></item>
+ <item><p><seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer/0</c></seealso></p></item>
+ <item><p><seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer/1</c></seealso></p></item>
+ <item><p><seealso marker="kernel:os#system_time/0"><c>os:system_time/0</c></seealso></p></item>
+ <item><p><seealso marker="kernel:os#system_time/1"><c>os:system_time/1</c></seealso></p></item>
+ </list>
+
+ <p>The new API also consists of extensions of the following existing BIFs:</p>
+
+ <list>
+ <item><p><seealso marker="erlang#monitor/2"><c>erlang:monitor(time_offset, clock_service)</c></seealso></p></item>
+ <item><p><seealso marker="erlang#system_flag_time_offset"><c>erlang:system_flag(time_offset, finalize)</c></seealso></p></item>
+ <item><p><seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso></p></item>
+ <item><p><seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso></p></item>
+ <item><p><seealso marker="erlang#system_info_time_offset"><c>erlang:system_info(time_offset)</c></seealso></p></item>
+ <item><p><seealso marker="erlang#system_info_time_warp_mode"><c>erlang:system_info(time_warp_mode)</c></seealso></p></item>
+ <item><p><seealso marker="erlang#system_info_time_correction"><c>erlang:system_info(time_correction)</c></seealso></p></item>
+ <item><p><seealso marker="erlang#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso></p></item>
+ <item><p><seealso marker="erlang#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso></p></item>
+ </list>
+
+ <marker id="The_New_Erlang_Monotonic_Time"/>
+ <section>
+ <title>New Erlang Monotonic Time</title>
+ <p>Erlang monotonic time as such is new as of <c>ERTS</c> 7.0.
+ It is introduced to detach time measurements, such as elapsed
+ time from calendar time. In many use cases there is a need to
+ measure elapsed time or specify a time relative to another point
+ in time without the need to know the involved times in UTC or
+ any other globally defined time scale. By introducing a time
+ scale with a local definition of where it starts, time that do
+ not concern calendar time can be managed on that time
+ scale. Erlang monotonic time uses such a time scale with a
+ locally defined start.</p>
+
+ <p>The introduction of Erlang monotonic time allows
+ us to adjust the two Erlang times (Erlang
+ monotonic time and Erlang system time) separately. By
+ doing this, the accuracy of elapsed time does not have to
+ suffer just because the system time happened to be
+ wrong at some point in time. Separate adjustments
+ of the two times are only performed in the time warp
+ modes, and only fully separated in the
+ <seealso marker="#Multi_Time_Warp_Mode">multi-time
+ warp mode</seealso>. All other modes than the
+ multi-time warp mode are for backwards
+ compatibility reasons. When using these modes, the
+ accuracy of Erlang monotonic time suffer, as
+ the adjustments of Erlang monotonic time in these
+ modes are more or less tied to Erlang system time.</p>
+
+ <p>The adjustment of system time could have been made
+ smother than using a time warp approach, but we think
+ that would be a bad choice. As we can
+ express and measure time that is not connected to
+ calendar time by the use of Erlang monotonic time, it
+ is better to expose the change in Erlang system time
+ immediately. This as the Erlang applications
+ executing on the system can react on the change in
+ system time as soon as possible. This is also more or
+ less exactly how most operating systems handle this
+ (OS monotonic time and OS system time). By adjusting
+ system time smoothly, we would just hide the fact that
+ system time changed and make it harder for the Erlang
+ applications to react to the change in a sensible way.</p>
+
+ <p>To be able to react to a change in Erlang
+ system time, you must be able to detect that it
+ happened. The change in Erlang system time occurs when
+ current time offset is changed. We have therefore
+ introduced the possibility to monitor the time offset using
+ <seealso marker="erlang#monitor/2"><c>erlang:monitor(time_offset, clock_service)</c></seealso>.
+ A process monitoring the time
+ offset is sent a message on the following format
+ when the time offset is changed:</p>
+
+ <code type="none">{'CHANGE', MonitorReference, time_offset, clock_service, NewTimeOffset}</code>
+ </section>
+
+ <marker id="Unique_Values"/>
+ <section>
+ <title>Unique Values</title>
+ <p>Besides reporting time, <c>erlang:now/0</c> also
+ produces unique and strictly monotonically increasing
+ values. To detach this functionality from
+ time measurements, we have introduced
+ <seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer()</c></seealso>.
+ </p>
+ </section>
+
+ <marker id="Dos_and_Donts"/>
+ <section>
+ <title>How to Work with the New API</title>
+ <p>Previously <c>erlang:now/0</c> was the only option for doing
+ many things. This section deals with some things that
+ <c>erlang:now/0</c> can be used for, and how you are to
+ these using the new API.</p>
+
+ <marker id="Dos_and_Donts_Retrieve_Erlang_System_Time"/>
+ <section>
+ <title>Retrieve Erlang System Time</title>
+ <dont>
+ <p>
+ Use <c>erlang:now/0</c> to retrieve current Erlang system time.
+ </p>
+ </dont>
+ <do>
+ <p>
+ Use
+ <seealso marker="erlang#system_time/1"><c>erlang:system_time/1</c></seealso>
+ to retrieve current Erlang system time on the
+ <seealso marker="erlang#type_time_unit">time unit</seealso>
+ of your choice.</p>
+ <p>If you want the same format as returned by <c>erlang:now/0</c>, use
+ <seealso marker="erlang#timestamp/0"><c>erlang:timestamp/0</c></seealso>.
+ </p>
+ </do>
+ </section>
+
+ <marker id="Dos_and_Donts_Measure_Elapsed_Time"/>
+ <section>
+ <title>Measure Elapsed Time</title>
+ <dont>
+ <p>
+ Take timestamps with <c>erlang:now/0</c> and calculate
+ the difference in time with
+ <seealso marker="stdlib:timer#now_diff/2"><c>timer:now_diff/2</c></seealso>.
+ </p>
+ </dont>
+ <do>
+ <p>
+ Take timestamps with
+ <seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time/0</c></seealso>
+ and calculate the time difference using ordinary subtraction.
+ The result will be in <c>native</c>
+ <seealso marker="erlang#type_time_unit">time unit</seealso>.
+ If you want to convert the
+ result to another time unit, you can use
+ <seealso marker="erlang#convert_time_unit/3"><c>erlang:convert_time_unit/3</c></seealso>.
+ </p>
+
+ <p>An easier way to do this is to use
+ <seealso marker="erlang#monotonic_time/1"><c>erlang:monotonic_time/1</c></seealso>
+ with the desired time unit. However, you can then lose accuracy
+ and precision.
+ </p>
+ </do>
+ </section>
+
+ <marker id="Dos_and_Donts_Determine_Order_of_Events"/>
+ <section>
+ <title>Determine Order of Events</title>
+ <dont>
+ <p>
+ Determine the order of events by saving a timestamp
+ with <c>erlang:now/0</c> when the event occurs.
+ </p>
+ </dont>
+ <do>
+ <p>
+ Determine the order of events by saving the integer
+ returned by
+ <seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer([monotonic])</c></seealso>
+ when the event occurs. These integers will be strictly
+ monotonically ordered on current runtime system instance
+ corresponding to creation time.
+ </p>
+ </do>
+ </section>
+
+ <marker id="Dos_and_Donts_Determine_Order_of_Events_With_Time_of_the_Event"/>
+ <section>
+ <title>Determine Order of Events with Time of the Event</title>
+ <dont>
+ <p>
+ Determine the order of events by saving a timestamp
+ with <c>erlang:now/0</c> when the event occurs.
+ </p>
+ </dont>
+ <do>
+ <p>
+ Determine the order of events by saving a tuple containing
+ <seealso marker="erlang#monotonic_time/0">monotonic time</seealso>
+ and a <seealso marker="erlang#unique_integer/1">strictly
+ monotonically increasing integer</seealso> as follows:</p>
+
+ <code type="none">
+Time = erlang:monotonic_time(),
+UMI = erlang:unique_integer([monotonic]),
+EventTag = {Time, UMI}</code>
+
+ <p>These tuples will be strictly monotonically ordered
+ on current runtime system instance according to
+ creation time. It is important that the
+ monotonic time is in the first element (the most
+ significant element when comparing 2-tuples). Using
+ the monotonic time in the tuples, you can calculate time
+ between events.</p>
+
+ <p>If you are interested in Erlang system time at the
+ time when the event occurred, you can also save the time
+ offset before or after saving the events using
+ <seealso marker="erlang#time_offset/0"><c>erlang:time_offset/0</c></seealso>.
+ Erlang monotonic time added with the time
+ offset corresponds to Erlang system time.</p>
+
+ <p>If you are executing in a mode where time offset
+ can change, and you want to get the actual
+ Erlang system time when the event occurred, you can
+ save the time offset as a third element in the tuple
+ (the least significant element when comparing 3-tuples).</p>
+ </do>
+ </section>
+
+ <marker id="Dos_and_Donts_Create_a_Unique_Name"/>
+ <section>
+ <title>Create a Unique Name</title>
+ <dont>
+ <p>
+ Use the values returned from <c>erlang:now/0</c>
+ to create a name unique on the current runtime system instance.
+ </p>
+ </dont>
+ <do>
+ <p>
+ Use the value returned from
+ <seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer/0</c></seealso>
+ to create a name unique on the current runtime system
+ instance. If you only want positive integers, you can use
+ <seealso marker="erlang#unique_integer/1"><c>erlang:unique_integer([positive])</c></seealso>.
+ </p>
+ </do>
+ </section>
+
+ <marker id="Dos_and_Donts_Seed_Random_Number_Generation_With_a_Unique_Value"/>
+ <section>
+ <title>Seed Random Number Generation with a Unique Value</title>
+ <dont>
+ <p>
+ Seed random number generation using <c>erlang:now()</c>.
+ </p>
+ </dont>
+ <do>
+ <p>
+ Seed random number generation using a combination of
+ <seealso marker="erlang#monotonic_time/0"><c>erlang:monotonic_time()</c></seealso>,
+ <seealso marker="erlang#time_offset/0"><c>erlang:time_offset()</c></seealso>,
+ <seealso marker="erlang#unique_integer/0"><c>erlang:unique_integer()</c></seealso>,
+ and other functionality.
+ </p>
+ </do>
+ </section>
+
+ <p>To sum up this section: <em>Do not use <c>erlang:now/0</c>.</em></p>
+ </section>
+ </section>
+
+ <section>
+ <marker id="Supporting_Both_New_and_Old_OTP_Releases"/>
+ <title>Support of Both New and Old OTP Releases</title>
+ <p>It can be required that your code must run on a variety
+ of OTP installations of different OTP releases. If so, you
+ cannot use the new API out of the box, as it will
+ not be available on old pre OTP 18 releases. The solution
+ is <em>not</em> to avoid using the new API, as your
+ code then would not benefit from the scalability
+ and accuracy improvements made. Instead, use the
+ new API when available, and fall back on <c>erlang:now/0</c>
+ when the new API is unavailable.</p>
+
+ <p>Fortunately most of the new API can easily be
+ implemented using existing primitives, except for:</p>
+
+ <list type="bulleted">
+ <item>
+ <seealso marker="erlang#system_info_start_time"><c>erlang:system_info(start_time)</c></seealso>
+ </item>
+ <item>
+ <seealso marker="erlang#system_info_end_time"><c>erlang:system_info(end_time)</c></seealso>
+ </item>
+ <item>
+ <seealso marker="erlang#system_info_os_monotonic_time_source"><c>erlang:system_info(os_monotonic_time_source)</c></seealso>
+ </item>
+ <item>
+ <seealso marker="erlang#system_info_os_system_time_source"><c>erlang:system_info(os_system_time_source)</c></seealso>)
+ </item>
+ </list>
+
+ <p>By wrapping the API with functions that fall back on
+ <c>erlang:now/0</c> when the new API is unavailable,
+ and using these wrappers instead of using the API directly,
+ the problem is solved. These wrappers can, for example,
+ be implemented as in
+ <url href="time_compat.erl">$ERL_TOP/erts/example/time_compat.erl</url>.</p>
+ </section>
+</chapter>