mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 09:41:40 -05:00
Stats calculation is now timezone-aware.
This commit is contained in:
parent
9803ccc6a8
commit
bdcfb5eb62
4 changed files with 63 additions and 6 deletions
|
|
@ -37,6 +37,16 @@ class Stat < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
def calculate_daily_distances(monthly_points)
|
def calculate_daily_distances(monthly_points)
|
||||||
Stats::DailyDistanceQuery.new(monthly_points, timespan).call
|
Stats::DailyDistanceQuery.new(monthly_points, timespan, user_timezone).call
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def user_timezone
|
||||||
|
# Future: Once user.timezone column exists, uncomment the line below
|
||||||
|
# user.timezone.presence || Time.zone.name
|
||||||
|
|
||||||
|
# For now, use application timezone
|
||||||
|
Time.zone.name
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Stats::DailyDistanceQuery
|
class Stats::DailyDistanceQuery
|
||||||
def initialize(monthly_points, timespan)
|
def initialize(monthly_points, timespan, user_timezone = nil)
|
||||||
@monthly_points = monthly_points
|
@monthly_points = monthly_points
|
||||||
@timespan = timespan
|
@timespan = timespan
|
||||||
|
@user_timezone = user_timezone || 'UTC'
|
||||||
end
|
end
|
||||||
|
|
||||||
def call
|
def call
|
||||||
|
|
@ -15,22 +16,22 @@ class Stats::DailyDistanceQuery
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
attr_reader :monthly_points, :timespan
|
attr_reader :monthly_points, :timespan, :user_timezone
|
||||||
|
|
||||||
def daily_distances(monthly_points)
|
def daily_distances(monthly_points)
|
||||||
Stat.connection.select_all(<<-SQL.squish)
|
Stat.connection.select_all(<<-SQL.squish)
|
||||||
WITH points_with_distances AS (
|
WITH points_with_distances AS (
|
||||||
SELECT
|
SELECT
|
||||||
EXTRACT(day FROM to_timestamp(timestamp)) as day_of_month,
|
EXTRACT(day FROM (to_timestamp(timestamp) AT TIME ZONE 'UTC' AT TIME ZONE '#{user_timezone}')) as day_of_month,
|
||||||
CASE
|
CASE
|
||||||
WHEN LAG(lonlat) OVER (
|
WHEN LAG(lonlat) OVER (
|
||||||
PARTITION BY EXTRACT(day FROM to_timestamp(timestamp))
|
PARTITION BY EXTRACT(day FROM (to_timestamp(timestamp) AT TIME ZONE 'UTC' AT TIME ZONE '#{user_timezone}'))
|
||||||
ORDER BY timestamp
|
ORDER BY timestamp
|
||||||
) IS NOT NULL THEN
|
) IS NOT NULL THEN
|
||||||
ST_Distance(
|
ST_Distance(
|
||||||
lonlat::geography,
|
lonlat::geography,
|
||||||
LAG(lonlat) OVER (
|
LAG(lonlat) OVER (
|
||||||
PARTITION BY EXTRACT(day FROM to_timestamp(timestamp))
|
PARTITION BY EXTRACT(day FROM (to_timestamp(timestamp) AT TIME ZONE 'UTC' AT TIME ZONE '#{user_timezone}'))
|
||||||
ORDER BY timestamp
|
ORDER BY timestamp
|
||||||
)::geography
|
)::geography
|
||||||
)
|
)
|
||||||
|
|
|
||||||
30
benchmark_stats.rb
Normal file
30
benchmark_stats.rb
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
require 'benchmark'
|
||||||
|
|
||||||
|
# Test the optimized stats calculation
|
||||||
|
data = Benchmark.measure do
|
||||||
|
user_id = 7
|
||||||
|
|
||||||
|
last_calculated_at = DateTime.new(1970, 1, 1)
|
||||||
|
|
||||||
|
time_diff = last_calculated_at.to_i..Time.current.to_i
|
||||||
|
timestamps = Point.where(user_id:, timestamp: time_diff).pluck(:timestamp).uniq
|
||||||
|
|
||||||
|
months = timestamps.group_by do |timestamp|
|
||||||
|
time = Time.zone.at(timestamp)
|
||||||
|
[time.year, time.month]
|
||||||
|
end.keys
|
||||||
|
|
||||||
|
months.each do |year, month|
|
||||||
|
Stats::CalculateMonth.new(user_id, year, month).call
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "Stats calculation benchmark:"
|
||||||
|
puts "User Time: #{data.utime}s"
|
||||||
|
puts "System Time: #{data.stime}s"
|
||||||
|
puts "Total Time: #{data.real}s"
|
||||||
|
|
||||||
|
# @real=28.869485000148416,
|
||||||
|
# @stime=2.4980050000000027,
|
||||||
|
# @total=20.303141999999976,
|
||||||
|
# @utime=17.805136999999974>
|
||||||
16
db/migrate/future_add_timezone_to_users.rb.example
Normal file
16
db/migrate/future_add_timezone_to_users.rb.example
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
# Example migration for adding per-user timezone support
|
||||||
|
# To use: rename this file to remove .example and run rails db:migrate
|
||||||
|
|
||||||
|
class AddTimezoneToUsers < ActiveRecord::Migration[7.1]
|
||||||
|
def change
|
||||||
|
add_column :users, :timezone, :string, default: 'UTC'
|
||||||
|
add_index :users, :timezone
|
||||||
|
|
||||||
|
# Populate existing users with application timezone
|
||||||
|
reversible do |dir|
|
||||||
|
dir.up do
|
||||||
|
User.update_all(timezone: Time.zone.name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in a new issue