I am trying to upgrade from rails 4.2.7 to 4.2.8 and found a case where the DateTime method of rails switches the time zone to local on reload from database which was not seen in rails 4.2.7. On rails 4.2.8, the unit test of my app rely on the DateTime method to get beginning of the year,
DateTime.new(2019,1,1,0,0,0)
Tue, 01 Jan 2019 00:00:00 +0000
This resultant value, is passed as part of an object to,
Class:Machinist::ActiveRecord::Blueprint where the reload happens.
def reload(options = nil)
clear_aggregation_cache
clear_association_cache
self.class.connection.clear_query_cache
fresh_object =
if options && options[:lock]
self.class.unscoped { self.class.lock(options[:lock]).find(id) }
else
self.class.unscoped { self.class.find(id) }
end
#attributes = fresh_object.instance_variable_get('#attributes')
#new_record = false
self
end
The instance_variable_get method at,
#attributes = fresh_object.instance_variable_get('#attributes')
switches the time zone on Rails 4.2.8 to local(Mon, 31st Dec 2018 16:00:00 -0800) but not on 4.2.7 where just the time zone is switched and not the time (Tue, 1st Jan 2019 00:00:00 -0800). A similar method, Time.new() has got no problem with this as the time zone is set to local by default,
Time.new(2019,1,1,0,0,0)
2019-01-01 00:00:00 -0800
Trying to pinpoint what changed on rails 4.2.8 that doesn't let the time zones persist to UTC for the DateTime method on the reload.
Any insights on this are helpful.
Thanks
Related
My rspec test fails on local machine between 6:00pm and 6:59pm, but passes at before 5:59pm and after 7:00pm on the local machine,
It seems to pass on CircleCI and Heroku, but I do not know if CircleCI or Heroku fail at specific times.
I set my local computer time to UTC, and it seems #subscription.current_period_end is incorrect by 1 hour.
I suspect it has something to do with how my local machine handles the time vs CircleCi and Heroku. Any ideas how to address this issue?
Code:
def get_proration_date
Time.zone.now.to_i
end
Application.rb
config.active_record.default_timezone = :utc
config.time_zone = "UTC"
Rspec
it "should create upcoming_invoice with existing plan for the next_month if there are no changes to subscription(Mock Version)", live: false do
create_stripe_elements
stripe_gold_plan
#subscription = payment_gateway.create_subscription(plan: silver_plan, user: user,
coupon_id: #coupon.stripe_id, source_id_or_token: default_card_token)
invoice = payment_gateway.upcoming_invoice_for_update_plan(subscription: #subscription, to_plan: silver_plan,
coupon_id: "", proration_date: get_proration_date)
expect(invoice.lines.total_count).to eql(1)
expect(invoice.amount_due).to eql(silver_plan.amount)
expect(invoice.total).to eql(silver_plan.amount)
expect(Time.zone.at(invoice.next_payment_attempt)).to eql(#subscription.current_period_end)
delete_stripe_elements
end
Error
Failure/Error: expect(Time.zone.at(invoice.next_payment_attempt)).to eql(#subscription.current_period_end)
expected: 2020-09-27 00:20:20.000000000 +0000
got: 2020-09-27 01:20:20.000000000 +0000
(compared using eql?)
Diff:
## -1,2 +1,2 ##
-Sun, 27 Sep 2020 00:20:20 UTC +00:00
+Sun, 27 Sep 2020 01:20:20 UTC +00:00
Most likely you have a bug in time calculations, potentially a time zone-related one.
Fire up pry or byebug on your local machine when the time comparison fails in the test and figure out which time is the correct one. Then figure out why the other time is wrong and fix that.
Suggest that you always store everything as UTC. Log timestamps, payment timestamps, audit dates, whatever. Do all your date and time calculations and intervals using the UTC values. That way you never ever have an issue with figuring out what happened, and the order in which it happened, even when your users are in different time zones, or they check out their shopping cart at 01:59:59 on the morning when you switch out of daylight saving time in the autumn. If you have a requirement to display dates and times to your users, this is a presentation issue and you can always convert the UTC values to their local timezone values for display purposes.
It was a stripe issue. They do not finalize an invoice until 1 hour after invoice is created, hence I needed to add an hour. #subscription.current_period_end+1.hour
I understand how to parse times from strings using Golang.
Currently, I make a request in rails/ruby that is handled by Go, in which I pass in a time parameter.
This is what I'm doing in rails
resp = connection.get "url", {
updated_at: updated_at
}.compact
and updated_at is Time.now - 1.day.
In Go, this is how I'm parsing the time, after getting it out.
updatedAt, err := time.Parse("2006-01-02 15:04:05 -0700 MST", updatedAtVar)
The above works if time looks like
2014-11-17 23:02:03 +0000 UTC
but Ruby spits out a time that looks like
2016-08-10 22:29:51 +0000
which, when parsing results in
0001-01-01 00:00:00 +0000 UTC
What can I pass into my param such that go will parse the time correctly?
The format string provided in the docs contains some redundant information (MST and -0700 in particular convey the same information—a UTC offset in hours*100+minutes).
So, just leave "MST" out of your format string.
I'm new to Ruby and am trying to figure out why the following doesn't work as expected:
2.2.1 :010 > user_date = Date.today
=> Sun, 31 May 2015
2.2.1 :011 > user_date.today?
=> false
I'm using the Rails console and the commands are executed one after the other (with maybe a second between executions). I'm sure there is nuance that I'm not understanding, but shouldn't the second command return true instead of false? If not, why?
Thanks in advance!
Edit #1 - Additional information requested by Arup
2.2.1 :013 > puts user_date.method(:today?).owner
DateAndTime::Calculations
=> nil
Edit #2 - So I had a hunch. I'm on US Eastern time and it was coming up to midnight when I ran into the original issue. I waited for the turn of midnight, and now the following works.
2.2.1 :004 > user_date = Date.today
=> Mon, 01 Jun 2015
2.2.1 :005 > user_date.today?
=> true
Date.today belongs to core Ruby while today? belongs to Rails.
Under the hood, today? calls Date.current(Rails as well) instead of Date.today.
Going a bit further, we find that Date.current takes the current Rails time zone into account if one is configured. That should be the source of your mismatch.
I noticed when PingFederate(PF) sends the date it is off by a day from my Rails app. It appears that the PF date is the one off by a day. For example in the PF SAML response I get:
<saml:Assertion ID="pEaf1kce93SpAxfIpuohOv6QP-T" IssueInstant="2014-05-03T03:15:20.020Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
and
<saml:Conditions NotBefore="2014-05-03T03:10:20.021Z" NotOnOrAfter="2014-05-03T03:20:20.021Z">
whereas in Rails I get
Time.now = 2014-05-02 20:15:19 -0700
which makes me think that I need to set the date in PF. Note that PF is running on the same computer that the Rails app is running on.
Is there a way to set the date in PF?
The time is off as well. Is there a way in PF to set the time too?
SAML assertions are always in UTC. Which is what PingFed is using. Set your Rails application to use UTC as well.
I don't see why you think that the time is off. Your time from Rails is 2015 and -7. That means in UTC, it's tomorrow at 0315 - when it was issued. PingFed is setting an allowance of +/-5 minutes, so the SP should not accept it before 0310 or after 0320.
Your server and PingFed are correct so far...
I currently queue my DelayedJob like so:
Delayed::Job.enqueue MyJob.new, 5, 1.day.from_now
I'm looking for a way to set a different execution time:
Tomorrow morning at 9:30am PST
Does Rails have a helper that can take care of this? Thanks
If your rails server is not running in PST/PDT:
Time.use_zone("Pacific Time (US & Canada)") { 1.day.from_now.beginning_of_day + 9.5.hours }
If it is already running in PST/PDT, you can shorten it to:
1.day.from_now.beginning_of_day + 9.5.hours
Have a look at Time and TimeZone for more info.