mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 01:01:39 -05:00
Adjust calculate_duration_in_minutes to only count continuous presence within cities, excluding long gaps.
This commit is contained in:
parent
348bf96bfe
commit
88ae7c43c6
5 changed files with 86 additions and 12 deletions
|
|
@ -48,7 +48,7 @@ class Users::DigestsController < ApplicationController
|
|||
tracked_years = current_user.stats.select(:year).distinct.pluck(:year)
|
||||
existing_digests = current_user.digests.yearly.pluck(:year)
|
||||
|
||||
(tracked_years - existing_digests).sort.reverse
|
||||
(tracked_years - existing_digests - [Time.current.year]).sort.reverse
|
||||
end
|
||||
|
||||
def valid_year?(year)
|
||||
|
|
|
|||
|
|
@ -49,6 +49,17 @@ class CountriesAndCities
|
|||
end
|
||||
|
||||
def calculate_duration_in_minutes(timestamps)
|
||||
((timestamps.max - timestamps.min).to_i / 60)
|
||||
return 0 if timestamps.size < 2
|
||||
|
||||
sorted = timestamps.sort
|
||||
total_minutes = 0
|
||||
gap_threshold_seconds = ::MIN_MINUTES_SPENT_IN_CITY * 60
|
||||
|
||||
sorted.each_cons(2) do |prev_ts, curr_ts|
|
||||
interval_seconds = curr_ts - prev_ts
|
||||
total_minutes += (interval_seconds / 60) if interval_seconds < gap_threshold_seconds
|
||||
end
|
||||
|
||||
total_minutes
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class Users::ExportData::Points
|
|||
|
||||
output_file.write('[')
|
||||
|
||||
user.points.find_in_batches(batch_size: BATCH_SIZE).with_index do |batch, batch_index|
|
||||
user.points.find_in_batches(batch_size: BATCH_SIZE).with_index do |batch, _batch_index|
|
||||
batch_sql = build_batch_query(batch.map(&:id))
|
||||
result = ActiveRecord::Base.connection.exec_query(batch_sql, 'Points Export Batch')
|
||||
|
||||
|
|
@ -188,13 +188,13 @@ class Users::ExportData::Points
|
|||
}
|
||||
end
|
||||
|
||||
if row['visit_name']
|
||||
point_hash['visit_reference'] = {
|
||||
'name' => row['visit_name'],
|
||||
'started_at' => row['visit_started_at'],
|
||||
'ended_at' => row['visit_ended_at']
|
||||
}
|
||||
end
|
||||
return unless row['visit_name']
|
||||
|
||||
point_hash['visit_reference'] = {
|
||||
'name' => row['visit_name'],
|
||||
'started_at' => row['visit_started_at'],
|
||||
'ended_at' => row['visit_ended_at']
|
||||
}
|
||||
end
|
||||
|
||||
def log_progress(processed, total)
|
||||
|
|
|
|||
|
|
@ -79,6 +79,58 @@ RSpec.describe CountriesAndCities do
|
|||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when points have a gap larger than threshold (passing through)' do
|
||||
let(:points) do
|
||||
[
|
||||
# User in Berlin at 9:00, leaves, returns at 11:00
|
||||
create(:point, city: 'Berlin', country: 'Germany', timestamp:),
|
||||
create(:point, city: 'Berlin', country: 'Germany', timestamp: timestamp + 15.minutes),
|
||||
# 105-minute gap here (user left the city)
|
||||
create(:point, city: 'Berlin', country: 'Germany', timestamp: timestamp + 120.minutes),
|
||||
create(:point, city: 'Berlin', country: 'Germany', timestamp: timestamp + 130.minutes)
|
||||
]
|
||||
end
|
||||
|
||||
it 'only counts time between consecutive points within threshold' do
|
||||
# Old logic would count 130 minutes (span from first to last)
|
||||
# New logic counts: 15 min (0->15) + 10 min (120->130) = 25 minutes
|
||||
# Since 25 < 60, Berlin should be filtered out
|
||||
expect(countries_and_cities).to eq(
|
||||
[
|
||||
CountriesAndCities::CountryData.new(
|
||||
country: 'Germany',
|
||||
cities: []
|
||||
)
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when points span a long time but have continuous presence' do
|
||||
let(:points) do
|
||||
# Points every 30 minutes for 2.5 hours = continuous presence
|
||||
(0..5).map do |i|
|
||||
create(:point, city: 'Berlin', country: 'Germany', timestamp: timestamp + (i * 30).minutes)
|
||||
end
|
||||
end
|
||||
|
||||
it 'counts the full duration when all intervals are within threshold' do
|
||||
# 5 intervals of 30 minutes each = 150 minutes total
|
||||
expect(countries_and_cities).to eq(
|
||||
[
|
||||
CountriesAndCities::CountryData.new(
|
||||
country: 'Germany',
|
||||
cities: [
|
||||
CountriesAndCities::CityData.new(
|
||||
city: 'Berlin', points: 6, timestamp: (timestamp + 150.minutes).to_i, stayed_for: 150
|
||||
)
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -155,10 +155,14 @@ RSpec.describe Stats::CalculateMonth do
|
|||
context 'when user visited multiple cities with mixed durations' do
|
||||
let!(:mixed_points) do
|
||||
[
|
||||
# Berlin: 70 minutes (should be included)
|
||||
# Berlin: 70 minutes with continuous presence (should be included)
|
||||
# Points every 35 minutes: 0, 35, 70 = 70 min total
|
||||
create(:point, user:, import:, timestamp: timestamp_base,
|
||||
city: 'Berlin', country_name: 'Germany',
|
||||
lonlat: 'POINT(13.404954 52.520008)'),
|
||||
create(:point, user:, import:, timestamp: timestamp_base + 35.minutes,
|
||||
city: 'Berlin', country_name: 'Germany',
|
||||
lonlat: 'POINT(13.404954 52.520008)'),
|
||||
create(:point, user:, import:, timestamp: timestamp_base + 70.minutes,
|
||||
city: 'Berlin', country_name: 'Germany',
|
||||
lonlat: 'POINT(13.404954 52.520008)'),
|
||||
|
|
@ -171,10 +175,17 @@ RSpec.describe Stats::CalculateMonth do
|
|||
city: 'Prague', country_name: 'Czech Republic',
|
||||
lonlat: 'POINT(14.4378 50.0755)'),
|
||||
|
||||
# Vienna: 90 minutes (should be included)
|
||||
# Vienna: 90 minutes with continuous presence (should be included)
|
||||
# Points every 30 minutes: 150, 180, 210, 240 = 90 min total
|
||||
create(:point, user:, import:, timestamp: timestamp_base + 150.minutes,
|
||||
city: 'Vienna', country_name: 'Austria',
|
||||
lonlat: 'POINT(16.3738 48.2082)'),
|
||||
create(:point, user:, import:, timestamp: timestamp_base + 180.minutes,
|
||||
city: 'Vienna', country_name: 'Austria',
|
||||
lonlat: 'POINT(16.3738 48.2082)'),
|
||||
create(:point, user:, import:, timestamp: timestamp_base + 210.minutes,
|
||||
city: 'Vienna', country_name: 'Austria',
|
||||
lonlat: 'POINT(16.3738 48.2082)'),
|
||||
create(:point, user:, import:, timestamp: timestamp_base + 240.minutes,
|
||||
city: 'Vienna', country_name: 'Austria',
|
||||
lonlat: 'POINT(16.3738 48.2082)')
|
||||
|
|
|
|||
Loading…
Reference in a new issue