Synopse Open Source - Tag - UTCmORMot MVC / SOA / ORM and friends2024-02-02T17:08:25+00:00urn:md5:cc547126eb580a9adbec2349d7c65274DotclearHandling Cross-Platform Time Zonesurn:md5:8b0cffb08ffe6a4ab1c2ab0b0e6f01eb2015-06-16T17:21:00+02:002020-07-03T09:29:59+02:00AB4327-GANDImORMot FrameworkblogDelphiDocumentationmORMotTimeZonesTSynTimeZoneUserInterfaceUTC<p>One common problem when handling dates and times, is that time is shown and
entered as <em>local</em>, whereas the computer should better use
non-geographic information - especially on a Client-Server architecture, where
both ends may not be on the same physical region.</p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/88/Tz_world_mp-color.svg/400px-Tz_world_mp-color.svg.png" /></p>
<p>A <em>time zone</em> is a region that observes a uniform standard time for
legal, commercial, and social purposes.<br />
Time zones tend to follow the boundaries of countries and their subdivisions
because it is convenient for areas in close commercial or other communication
to keep the same time.<br />
Most of the time zones on land are offset from <em>Coordinated Universal
Time</em> (UTC) by a whole number of hours, or minutes.<br />
Even worse, some countries use daylight saving time for part of the year,
typically by changing clocks by an hour, twice every year.</p>
<p>The main rule is that <strong>any date and time stored should be stored in
UTC</strong>, or with an explicit Zone identifier (i.e. an explicit offset to
the UTC value).<br />
Our framework expects this behavior: every date/time value stored and handled
by the ORM, SOA, or any other part of it, is expected to be UTC-encoded.<br />
At presentation layer (e.g. the User Interface), conversion to/from local times
should take place, so that the end-user is provided with friendly clock-wall
compatible timing.</p>
<p>As you may guess, handling time zones is a complex task, which should be
managed by the Operating System itself.<br />
Since this cultural material is constantly involving, it is updated as part of
the OS.</p>
<p>In practice, current local time could be converted from UTC from the current
system-wide time zone. One of the only parameters you have to set when
installing an Operating System is to pickup the keyboard layout... and the
current time zone to be used. But in a client-server environment, you may have
to manage several time zones on the server side: so you can't rely on this
global setting.</p>
<p>One sad - but predictable - news is that there is no common way of encoding
time zone information.<br />
Under <em>Windows</em>, the registry contains a list of time zones, and the
associated time bias data. Most POSIX systems (including <em>Linux</em> and Mac
OSX) do rely on the IANA database, also called <code>tzdata</code> - you may
have noticed that this particular package is often updated with your
system.<br />
Both zone identifiers do not map, so our framework needed something to be
shared on all systems.</p> <p>The <code>SynCommons.pas</code> unit features the <code>TSynTimeZone</code>
class, which is able to retrieve the information from the <em>Windows</em>
registry into memory via <code>TSynTimeZone.LoadFromRegistry</code>, or into a
compressed file via <code>TSynTimeZone.SaveToFile</code>.<br />
Later on, this file could be reloaded on any system, including any
<em>Linux</em> flavor, via <code>TSynTimeZone.LoadFromFile</code>, and returns
the very same results.<br />
The compressed file is pretty small, thanks to its optimized layout, and use of
our <code>SynLZ</code> compression algorithm: the full information is stored in
a 7 KB file - the same flattened information as JSON is around 130 KB, and you
may compare with the official <a href="http://www.iana.org">http://www.iana.org</a> content, which weighted as a
280KB <code>tar.gz</code>... Of course, <code>tzdata</code> stores potentially
a lot more information than we need.</p>
<p>In practice, you may use <code>TSynTimeZone.Default</code>, which would
return an instance read from the current version of the registry under
<em>Windows</em>, and would attempt to load the information named after the
executable file name (appended as a <code>.tz</code> extension) on other
Operating Systems.<br />
You may therefore write:</p>
<pre>
aLocalTime := TSynTimeZone.<strong>Default</strong>.NowToLocal(aTimeZoneID);
</pre>
<p>Similarly, you may use <code>TSynTimeZone.UtcToLocal</code> or
<code>TSynTimeZone.LocalToUtc</code> methods, with the proper <code>TZ</code>
identifier.</p>
<p>You would have to create the needed <code>.tz</code> compressed file under a
Windows machine, put this file together with any <em>Linux</em> server
executable.<br />
On a cloud-like system, you may store this information in a centralized server,
e.g. via a dedicated service - see <em><a href="http://synopse.info/files/html/Synopse%20mORMot%20Framework%20SAD%201.18.html#SIDE_TITL_63">
Client-Server services via interfaces</a></em> - generated from a single
reference <em>Windows</em> system.<br />
The main benefit is that the time information would stay consistent whatever
system it runs on.</p>
<p>Your User Interface could retrieve the IDs and ready to be displayed text
from <code>TSynTimeZone.Ids</code> and <code>TSynTimeZone.Displays</code>
properties, as plain <code>TStrings</code> instance, which index would follow
the <code>TSynTimeZone.Zone[]</code> internal information.</p>
<p>As a nice side effect, the <code>TSynTimeZone</code> binary internal storage
has been found out to be very efficient, and much faster than a manual reading
of the <em>Windows</em> registry. Complex local time calculation could be done
on the server side, with no fear of breaking down your processing
performances.</p>
<p>Feedback is welcome, as usual, <a href="http://synopse.info/forum/viewtopic.php?id=2645">on our forum</a>; and you
would find out the updated version of this blog article <a href="http://synopse.info/files/html/Synopse%20mORMot%20Framework%20SAD%201.18.html#TITL_176">
within our online documentation</a>!</p>