Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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