Skip to content
Merged
Show file tree
Hide file tree
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
23 changes: 14 additions & 9 deletions internal/c/libqb/src/datetime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ void Sleep(uint32_t milliseconds) {
}
#endif

static uint64_t millis_since_midnight() {
static uint64_t micros_since_midnight() {
const auto current_time = std::chrono::system_clock::now();

// Gives us the number of milliseconds past the current second
const auto millis_only = std::chrono::duration_cast<std::chrono::milliseconds>(current_time.time_since_epoch()).count() % 1000;
// Gives us the number of microseconds past the current second
const auto micros_only = std::chrono::duration_cast<std::chrono::microseconds>(current_time.time_since_epoch()).count() % 1000000;

// Convert to time_t and then hour/min/sec. localtime() takes the current timezone into account for us.
const auto cur_ttime = std::chrono::system_clock::to_time_t(current_time);
Expand All @@ -40,23 +40,28 @@ static uint64_t millis_since_midnight() {
// Compute current time as number of seconds past midnight
const auto seconds = local->tm_hour * 3600 + local->tm_min * 60 + local->tm_sec;

return static_cast<uint64_t>(seconds * 1000) + static_cast<uint64_t>(millis_only);
return static_cast<uint64_t>(seconds) * 1000000 + static_cast<uint64_t>(micros_only);
}

double func_timer(double accuracy, int32_t passed) {
if (new_error)
return 0;

auto result = millis_since_midnight() / 1000.0;
if (passed && accuracy <= 0.0) {
error(5);
return 0;
}

const auto micros = micros_since_midnight();

// An accuracy finer than 1 ms (e.g. TIMER(.000001)) gets the microsecond count.
// Otherwise TIMER keeps using whole milliseconds, exactly as before.
auto result = (passed && accuracy < 0.001) ? micros / 1000000.0 : (micros / 1000) / 1000.0;

// Default accuracy = 18.2 Hz
if (!passed) {
accuracy = 18.2;
} else {
if (accuracy <= 0.0) {
error(5);
return 0;
}
accuracy = 1.0 / accuracy;
}

Expand Down
33 changes: 33 additions & 0 deletions tests/compile_tests/timer/timer_sub_millisecond.bas
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
$Console:Only

' TIMER with an accuracy finer than 1 ms returns microseconds; .001 and
' coarser keep returning whole milliseconds, as they always have.

Dim As Double t, prev, msPart
Dim As Long i, offMs, backwards, notWholeMs

' TIMER(.001) is always a whole number of milliseconds
For i = 1 To 2000
t = Timer(.001)
msPart = t * 1000 - Int(t * 1000 + .5)
If Abs(msPart) > .000001 Then notWholeMs = notWholeMs + 1
Next
If notWholeMs = 0 Then Print "Timer(.001) whole milliseconds: ok" Else Print "Timer(.001) not whole milliseconds:"; notWholeMs

' TIMER(.000001) has digits below the millisecond, and never runs backwards
prev = Timer(.000001)
For i = 1 To 20000
t = Timer(.000001)
msPart = t * 1000 - Int(t * 1000 + .5)
If Abs(msPart) > .0005 Then offMs = offMs + 1
If t < prev And prev - t < 43200 Then backwards = backwards + 1 ' (ignores the midnight wrap)
prev = t
Next
If offMs > 0 Then Print "Timer(.000001) below a millisecond: ok" Else Print "Timer(.000001) only whole milliseconds"
If backwards = 0 Then Print "Timer(.000001) never backwards: ok" Else Print "Timer(.000001) went backwards:"; backwards

' Both agree to within a couple of milliseconds
t = Abs(Timer(.000001) - Timer(.001))
If t < .002 Or t > 86399 Then Print "Timer(.000001) agrees with Timer(.001): ok" Else Print "Timer(.000001) differs from Timer(.001) by"; t

System
4 changes: 4 additions & 0 deletions tests/compile_tests/timer/timer_sub_millisecond.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Timer(.001) whole milliseconds: ok
Timer(.000001) below a millisecond: ok
Timer(.000001) never backwards: ok
Timer(.000001) agrees with Timer(.001): ok