How can I set the time in postgres in order to test timezone behaviour using RSpec? How can I set the time in postgres in order to test timezone behaviour using RSpec? postgresql postgresql

How can I set the time in postgres in order to test timezone behaviour using RSpec?


Postgres uses the date / time setting of the underlying OS (at least on UNIX-like systems). To stage various timestamps, you would have to set the time of the OS, with the date command.

I would certainly not recommend that on a system that does anything else of importance. cronjobs can run haywire and other unpleasant side effects.

Instead, replace the function now() with a user-defined server-side function like:

CREATE OR REPLACE FUNCTION now_test()  RETURNS timestamptz AS $func$SELECT '2013-12-01 12:34'::timestamptz$func$ LANGUAGE SQL;

(The above cast assumes the current time zone setting of the session. Alternatively, you can provide a time zone or time offset with the literal.)
Then you can test your code with:

Schedule.where('evening_reminder_last_sent_on_local_date !=                              DATE(now_test() AT TIME ZONE time_zone)')

Modify the above SQL function above with various timestamps and you are good to go.


The previous suggestion is indeed very good but as I wanted to easily test my query with Delorean gem, I came up with this workaround:

Schedule.where('evening_reminder_last_sent_on_local_date !=                DATE( ?::timestamp AT TIME ZONE time_zone )', Time.now)

I took the previous example just for the sake, but I had to manipulate times in Postgres with the now() function. I couldn't just inject my ruby time instead without casting it with ::timestamp.

Moreover, in your case, maybe you could use timestamptz.


I had a similar case except instead of modifying the timezones, I wanted to apply an offset. This let me synchronize postgres's responses to NOW() with my appliction's responses to datetime.now() (tampered via libfaketime).

I ended up with one statement that renamed now() to system_now(), but only if system_now() didn't already exist:

DO $$    DECLARE    found_func pg_proc%rowtype;    BEGIN    SELECT * FROM pg_proc WHERE proname = 'system_now' INTO found_func;    IF FOUND THEN        RAISE NOTICE 'DB Already Faked';    ELSE        RAISE NOTICE'Faking DB Time';        ALTER FUNCTION now RENAME TO system_now;    END IF;END $$;

...and another one that redefined NOW() to include the offset:

CREATE OR REPLACE FUNCTION now() RETURNS timestamptzAS $func$    SELECT system_now() + INTERVAL '1225288 seconds';$func$ LANGUAGE SQL;