ruby-on-railstimezonerails-activerecord

How to set timezone for ActiveRecord queries to fetch the accurate figures?


I am building a Rails 7 app that is targetted for the German audience.

My current local German time is Fri Jun 21 12:10:23 CEST 2024 (output from date in terminal). When I log in to my production Ubuntu server and type date, I get the same - Fri Jun 21 12:10:23 CEST 2024.

I run some CRON jobs that start at midnight German time - that's 10pm UTC. Then, I want to run some statistics over the data, but it is inaccurate. After some digging into this issue, it is because on the server, the data is stored in the PostgreSQL database in the UTC time zone, hence the inaccuracy.

On StackOverflow, I found the same question.

I tried to set config.time_zone = 'Berlin', but it had no effect - apparently, I'll need to add config.active_record.default_timezone = :local to make it work.

However, if I do this, what's going to happen with the existing data in my database? Will the existing dates be converted to the :local? Or will only the new dates be set as :local? Are there any consequences changing the database timezone that might cause me trouble in the future?

I have a production database with customer data, so I am trying to evaluate all "dangerous" scenarios when potentially doing this change.

EDIT: Example of statistics:

@data = Model.find_by_sql("SELECT DATE_TRUNC('day', created_at) AS day, 
                                      COUNT(id) as tasks, 
                                      SUM(revenue) AS revenue, 
                                      SUM(tasks_created) AS tasks_created
                                    FROM tasks 
                                    GROUP BY day
                                    ORDER BY day DESC
                                    LIMIT 10")

EDIT2: Data in the UTC format in the database:

1. 2024-06-20 02:15:15.180055
2. 2024-06-20 22:00:04.305209
3. 2024-06-20 22:00:13.77628
4. 2024-06-21 00:00:21.788828

I assumed that if I applied the German timezone, the records #2, #3 and #4 would be picked up. Instead, it's still only picked up the record #4.


Solution

  • What's about change query from

    SELECT DATE_TRUNC('day', created_at) AS day, 
    COUNT(id) as tasks, 
    SUM(revenue) AS revenue, 
    SUM(tasks_created) AS tasks_created
    FROM tasks 
    GROUP BY day
    ORDER BY day DESC
    LIMIT 10;
    

    to

    SELECT DATE_TRUNC('day', created_at AT TIME ZONE 'UTC' AT TIME ZONE 'Europe/Berlin') AS day, 
    COUNT(id) as tasks, 
    SUM(revenue) AS revenue, 
    SUM(tasks_created) AS tasks_created
    FROM tasks 
    GROUP BY day
    ORDER BY day DESC
    LIMIT 10;
    

    Yes, it may bring some inconvenience to such queries, but it doesn't seem to be very strong. At least it won't affect production database in any way