Boost C++ Libraries: Ticket #9584: date_time::difference produces incorrect values https://svn.boost.org/trac10/ticket/9584 <p> The program below attempts to compute the local timezone's GMT offset for a given timestamp. The idea is simple. First, get the year-month-day-hour-minute-second representation of the timestamp in the local timezone. Then, create a UTC date_time with exactly the same components. The difference between those times is exactly the UTC offset. The program gives this: </p> <pre class="wiki">g++ -std=c++11 c.cpp -o c -l boost_locale ; ./c 1383469199 ; ./c 0; -25199 -28799 </pre><p> The expected output is 28800 (8 hours) both times, since my computer's local timezone is America/Los_Angeles (or Pacific Time). </p> <div class="wiki-code"><div class="code"><pre><span class="cp">#include</span> <span class="cpf">&lt;boost/locale.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"></span> <span class="kt">int</span> <span class="nf">compute_utc_offset_seconds</span><span class="p">(</span><span class="kt">time_t</span> <span class="n">time_since_utc_epoch</span><span class="p">)</span> <span class="p">{</span> <span class="k">using</span> <span class="k">namespace</span> <span class="n">boost</span><span class="o">::</span><span class="n">locale</span><span class="p">;</span> <span class="n">std</span><span class="o">::</span><span class="n">locale</span> <span class="n">loc</span> <span class="o">=</span> <span class="n">generator</span><span class="p">()(</span><span class="s">&quot;&quot;</span><span class="p">);</span> <span class="c1">// Get the local time coordinates for the given timestamp</span> <span class="n">date_time</span> <span class="n">local_dt</span><span class="p">{(</span><span class="kt">double</span><span class="p">)</span><span class="n">time_since_utc_epoch</span><span class="p">,</span> <span class="n">calendar</span><span class="p">(</span><span class="n">loc</span><span class="p">)};</span> <span class="c1">// Copy the date_time coordinates into a UTC value</span> <span class="n">date_time</span> <span class="n">utc_dt</span><span class="p">{</span><span class="n">calendar</span><span class="p">(</span><span class="n">loc</span><span class="p">,</span> <span class="s">&quot;UTC&quot;</span><span class="p">)};</span> <span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="nl">p</span> <span class="p">:</span> <span class="p">{</span> <span class="n">period</span><span class="o">::</span><span class="n">year</span><span class="p">(),</span> <span class="n">period</span><span class="o">::</span><span class="n">month</span><span class="p">(),</span> <span class="n">period</span><span class="o">::</span><span class="n">day</span><span class="p">(),</span> <span class="n">period</span><span class="o">::</span><span class="n">hour</span><span class="p">(),</span> <span class="n">period</span><span class="o">::</span><span class="n">minute</span><span class="p">(),</span> <span class="n">period</span><span class="o">::</span><span class="n">second</span><span class="p">()</span> <span class="p">})</span> <span class="p">{</span> <span class="n">utc_dt</span><span class="p">.</span><span class="n">set</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="n">local_dt</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">p</span><span class="p">));</span> <span class="p">}</span> <span class="k">return</span> <span class="n">local_dt</span><span class="p">.</span><span class="n">difference</span><span class="p">(</span><span class="n">utc_dt</span><span class="p">,</span> <span class="n">period</span><span class="o">::</span><span class="n">second</span><span class="p">());</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">argc</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">compute_utc_offset_seconds</span><span class="p">(</span><span class="n">atoi</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div></div> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/9584 Trac 1.4.3 Alexey Spiridonov <bstbg.20.lesha@…> Fri, 17 Jan 2014 10:18:46 GMT <link>https://svn.boost.org/trac10/ticket/9584#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9584#comment:1</guid> <description> <p> FWIW, the obvious workaround is to return utc_dt.time() - local_dt.time(), but that doesn't make the difference() method any less broken. </p> </description> <category>Ticket</category> </item> <item> <dc:creator>anonymous</dc:creator> <pubDate>Fri, 17 Jan 2014 10:41:23 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9584#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9584#comment:2</guid> <description> <p> Sorry, my "expected output" was wrong. I'm going to assume that the sign is correct because the docs for ::difference() are unclear (is it subtracting this from other?). </p> <p> Then, I expect to see -25200 and -28800 (because the first timestamp is in daylight savings time, while the latter is not). </p> <p> The off-by-one error with difference() is pretty systematic, so maybe it's by design? </p> <p> Also, I tried to use that function to compute the difference in seconds across 40 years, and it returned garbage, so something probably overflowed. </p> <p> My current guess is that one should always prefer to subtract the results of calling the ::time() method instead of relying on ::difference(). </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Artyom Beilis</dc:creator> <pubDate>Mon, 20 Jan 2014 08:31:55 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9584#comment:3 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9584#comment:3</guid> <description> <p> You incorrectly assume that for an object date_time, setting 6 parameters Y-M-D-H-M-S one afte another is the same as setting them all together. </p> <p> Additionally, if you open a bug ticked you need to provide an information about the backend you are using. Also it is hard to check anything if you refer to a current time. </p> <pre class="wiki"> date_time utc_dt{calendar(loc, "UTC")} </pre><p> Is the time in current time. </p> <p> So unless you provide some more valid information I can't help. </p> </description> <category>Ticket</category> </item> <item> <author>Alexey Spiridonov <bstbg.20.lesha@…></author> <pubDate>Mon, 20 Jan 2014 20:03:28 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9584#comment:4 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9584#comment:4</guid> <description> <p> What does my *original* code print for you? </p> <p> a) I'm clearly not intending to use the current time, since I'm overwriting all of YMDHMS with the values from a fixed timestamp. The current time should have no effect on this code. </p> <p> b) How do you want me to be setting YMDHMS? The documentation does not suggest a better way to set all of YMDHMS together, and in any case, why is this incorrect? How can the results be different? If they can be, such an API is extremely unsafe to use (and the documentation again provides no warning). </p> <p> c) I found no method that reveals the current back-end name. Can you suggest one? This is Ubuntu 13.10 with a full install of Boost, and ICU is installed also, so I assume that it's using ICU. </p> <p> d) The off-by-one-second error I originally reported is not so good (it might be due to rounding errors in the way I construct local_dt above), and I'd encourage you to actually try my original code to see if you can reproduce it. However, this seems even worse: </p> <div class="wiki-code"><div class="code"><pre><span class="cp">#include</span> <span class="cpf">&lt;boost/locale.hpp&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp"></span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">argc</span> <span class="o">&lt;</span> <span class="mi">4</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="k">using</span> <span class="k">namespace</span> <span class="n">boost</span><span class="o">::</span><span class="n">locale</span><span class="p">;</span> <span class="n">locale</span> <span class="n">loc</span> <span class="o">=</span> <span class="n">generator</span><span class="p">{}(</span><span class="s">&quot;&quot;</span><span class="p">);</span> <span class="k">auto</span> <span class="n">cal</span> <span class="o">=</span> <span class="p">(</span><span class="n">strlen</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">3</span><span class="p">])</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="o">?</span> <span class="n">calendar</span><span class="p">(</span><span class="n">loc</span><span class="p">)</span> <span class="o">:</span> <span class="n">calendar</span><span class="p">(</span><span class="n">loc</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="mi">3</span><span class="p">]);</span> <span class="n">date_time</span> <span class="n">a</span><span class="p">((</span><span class="kt">double</span><span class="p">)</span><span class="n">atoi</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]),</span> <span class="n">cal</span><span class="p">);</span> <span class="n">date_time</span> <span class="n">b</span><span class="p">((</span><span class="kt">double</span><span class="p">)</span><span class="n">atoi</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]),</span> <span class="n">cal</span><span class="p">);</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">a</span> <span class="o">&lt;&lt;</span> <span class="s">&quot; - &quot;</span> <span class="o">&lt;&lt;</span> <span class="n">b</span> <span class="o">&lt;&lt;</span> <span class="s">&quot; = &quot;</span> <span class="o">&lt;&lt;</span> <span class="n">a</span><span class="p">.</span><span class="n">difference</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">period</span><span class="o">::</span><span class="n">second</span><span class="p">())</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span> <span class="o">&lt;&lt;</span> <span class="n">b</span> <span class="o">&lt;&lt;</span> <span class="s">&quot; - &quot;</span> <span class="o">&lt;&lt;</span> <span class="n">a</span> <span class="o">&lt;&lt;</span> <span class="s">&quot; = &quot;</span> <span class="o">&lt;&lt;</span> <span class="n">b</span><span class="p">.</span><span class="n">difference</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">period</span><span class="o">::</span><span class="n">second</span><span class="p">())</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </pre></div></div><p> Neither of its outputs is even remotely correct. If the library cannot handle a 40-year difference, it should probably throw rather than make up numbers... </p> <pre class="wiki">g++ -std=c++11 bug.cpp -o bug -lboost_locale; ./bug 0 1390247464 '' 0 - 1.39025e+09 = 0 1.39025e+09 - 0 = 536870912 </pre> </description> <category>Ticket</category> </item> <item> <author>maksqwe1@…</author> <pubDate>Mon, 23 Feb 2015 08:54:22 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9584#comment:5 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9584#comment:5</guid> <description> <p> Fix: </p> <p> github com/boostorg/locale/pull/6 </p> </description> <category>Ticket</category> </item> <item> <author>bstbg.20.lesha@…</author> <pubDate>Tue, 24 Feb 2015 04:54:18 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9584#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9584#comment:6</guid> <description> <p> Thank you! </p> </description> <category>Ticket</category> </item> <item> <author>bstbg.20.lesha@…</author> <pubDate>Tue, 24 Feb 2015 04:56:23 GMT</pubDate> <title/> <link>https://svn.boost.org/trac10/ticket/9584#comment:6 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/9584#comment:6</guid> <description> <p> Thank you! </p> </description> <category>Ticket</category> </item> <item> <dc:creator>Artyom Beilis</dc:creator> <pubDate>Thu, 13 Jul 2017 14:53:34 GMT</pubDate> <title>status changed; resolution set https://svn.boost.org/trac10/ticket/9584#comment:7 https://svn.boost.org/trac10/ticket/9584#comment:7 <ul> <li><strong>status</strong> <span class="trac-field-old">new</span> → <span class="trac-field-new">closed</span> </li> <li><strong>resolution</strong> → <span class="trac-field-new">fixed</span> </li> </ul> Ticket