Skip to content

Commit

Permalink
Fix for #432. (#433)
Browse files Browse the repository at this point in the history
To work around Boost's msec-precision UTC timer erroneously reporting local time instead of UTC on some systems, we're now also probing the sec-precision UTC timer, which should be more reliable in terms of time zone: The rounded difference between the two should be able to give us the time zone offset (if any) in the msec-precision timer, which we then compensate for accordingly.
  • Loading branch information
c-lipka authored Aug 9, 2021
1 parent 3b43b71 commit 5c8afac
Showing 1 changed file with 35 additions and 1 deletion.
36 changes: 35 additions & 1 deletion source/parser/parser_expressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1115,7 +1115,41 @@ void Parser::Parse_Num_Factor (EXPRESS& Express,int *Terms)
{
static boost::posix_time::ptime y2k(boost::gregorian::date(2000,1,1));
boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time());
Val = (now-y2k).total_microseconds() * (1.0e-6) / (24*60*60);

// Due to a bug in `boost::posix_time::microsec_clock::universal_time()`,
// the value returned may actually be local time rather than UTC. We try to fix this
// by comparing with `boost::posix_time::second_clock::universal_time()`, which is
// less precise but more reliable in terms of time zone behavior.
// (NB: While we could theoretically compute the offset once, and then re-use it every time
// `new` is invoked, this would cause issues when rendering a scene during transition to or
// from daylight savings time, or other events affecting the time zone. The current approach
// is immune to such issues.)
boost::posix_time::ptime lowPrecisionNow(boost::posix_time::second_clock::universal_time());
// The difference between the two timers, rounded to quarters of an hour,
// should correspond to the time zone offset (in seconds in this case).
const auto tzPrecisionInSeconds = 15 * 60;
int_least32_t tzOffset = std::lround(float((now - lowPrecisionNow).total_seconds()) / tzPrecisionInSeconds) * tzPrecisionInSeconds;
// Unless someone paused the code in between the above statements, the resulting difference
// should be our time zone offset in seconds (unless we're running on a system that's not
// subject to the bug, in which case the resulting difference should be zero).
if (tzOffset != 0)
{
if (sceneData->EffectiveLanguageVersion() < 380)
{
WarningOnce(kWarningGeneral, HERE,
"In POV-Ray v3.7, on some platforms 'now' erroneously evaluated to days since "
"2000-01-01 00:00 local time instead of UTC. For backward compatibility, this "
"bug is reproduced in legacy scenes, but the scene may produce different "
"results on other platforms.");
}
else
{
now -= boost::posix_time::time_duration(0, 0, tzOffset);
}
}

const auto daysPerMicrosecond = 1.0e-6 / (24 * 60 * 60);
Val = (now - y2k).total_microseconds() * daysPerMicrosecond;
}
break;
}
Expand Down

0 comments on commit 5c8afac

Please sign in to comment.