Why does Date.strptime not throw ArgumentError in rails console - ruby-on-rails

In my local rails console passing 9/31/2011 returns 10/1/2011
[1] pry(main)> Date.strptime("09/31/2011", '%m/%d/%Y')
=> Sat, 01 Oct 2011
In heroku console it throws an ArgumentError:
irb(main):002:0> Date.strptime("09/31/2011", '%m/%d/%Y')
ArgumentError: invalid date
from (irb):2:in `strptime'

Double check that your Gemfile dev dependencies don't include something that could mess with Date's strptime function.
For example, the Timecop gem sets an alias for Date.strptime to this method:
https://www.rubydoc.info/gems/timecop/Date.strptime_with_mock_date
Which just ends up calling Time.strptime(str, fmt).to_date.
This behavior looks very similar to what you reported:
irb(main):001:0> Date.strptime("09/31/2011", '%m/%d/%Y')
ArgumentError: invalid date
from (irb):1:in 'strptime'
irb(main):002:0> Time.strptime("09/31/2011", '%m/%d/%Y').to_date
=> Sat, 01 Oct 2011

Related

Error while date conversion in rails application "TypeError: nil can't be coerced into Integer"

I am working on date conversion and trying to find out various dates in a week. In Rails console everything works fine but Web Application fails with error
TypeError: nil can't be coerced into Integer
Rails Version: 5.2.4.1
Here is output of browser web-console
d = Date.new(2021, 10, 11) # or Date.today
=> Mon, 11 Oct 2021
>> d.beginning_of_week # or same issue with d.next_week
TypeError: nil can't be coerced into Integer
from /home/xyz/.rvm/gems/ruby-2.5.5/gems/activesupport-5.2.4.6/lib/active_support/core_ext/date_and_time/calculations.rb:258:in `-'
from /home/xyz/.rvm/gems/ruby-2.5.5/gems/activesupport-5.2.4.6/lib/active_support/core_ext/date_and_time/calculations.rb:258:in `days_to_week_start'
from /home/xyz/.rvm/gems/ruby-2.5.5/gems/activesupport-5.2.4.6/lib/active_support/core_ext/date_and_time/calculations.rb:266:in `beginning_of_week'
from /home/xyz/checkout/my-app/app/helpers/application_helper.rb:109:in `working_time'
Rails console works fine
[1] pry(main)> d = Date.new(2021, 10, 11)
=> Mon, 11 Oct 2021
[2] pry(main)> d.beginning_of_week
=> Mon, 11 Oct 2021

Calculating exact duration time from a DateTime column in Postgres using Rails

I am trying to get a more accurate output than "about 2 hours" for duration time.
Currently, we are using time_ago_in_words
This looks like the below function in .erb
Duration: <%= time_ago_in_words(#sitrep.incident.created_at) %>
# I found the gem `dotiw` which lets me use:
distance_of_time_in_words(#sitrep.incident.created_at)
# However, there is an error and I can't get either to work in irb
This is my console output when attempting both. All help is appreciated
[1] pry(main)> include ActionView::Helpers
=> Object
[2] pry(main)> t = Sitrep.last.incident.created_at
# redacted output
=> Wed, 28 Nov 2018 21:47:45 UTC +00:00
[3] pry(main)> t
=> Wed, 28 Nov 2018 21:47:45 UTC +00:00
[4] pry(main)> time_ago_in_words(t)
=> "<span class=\"translation_missing\" title=\"translation missing: en.weeks\">Weeks</span>, <span class=\"translation_missing\" title=\"translation missing: en.days\">Days</span>, <span class=\"translation_missing\" title=\"translation missing: en.hours\">Hours</span>, and <span class=\"translation_missing\" title=\"translation missing: en.minutes\">Minutes</span>"
[5] pry(main)> distance_of_time_in_words(t)
NoMethodError: undefined method `seconds' for Wed, 28 Nov 2018 21:47:45 UTC +00:00:Time
Did you mean? send
Did you mean? send
from /Users/mmowris/.rbenv/versions/2.3.8/lib/ruby/gems/2.3.0/gems/activesupport-4.2.7.1/lib/active_support/time_with_zone.rb:371:in `method_missing'
[6] pry(main)>
The first method, time_ago_in_words works for our rails app. This .erb file sends an email, and the output would look something like:
Duration: about 2 hours
Any ideas on how to proceed? Why does this work in our rails project, but not irb? Why can't I get dotiw to work with the same input? Why can't i get taiw to work with the same input that works in production?
Thanks!
use the helper instead of including the helpers manually
> helper.time_ago_in_words(2.hours.ago, true)
=> "2 hours"
> helper.time_ago_in_words((2.hours.ago + 5.seconds), true)
=> "1 hour, 59 minutes, and 55 seconds"

Time difference in rspec

I'm writing a simple class to parse strings into relative dates.
module RelativeDate
class InvalidString < StandardError; end
class Parser
REGEX = /([0-9]+)_(day|week|month|year)_(ago|from_now)/
def self.to_time(value)
if captures = REGEX.match(value)
captures[1].to_i.send(captures[2]).send(captures[3])
else
raise InvalidString, "#{value} could not be parsed"
end
end
end
end
The code seems to work fine.
Now when I try my specs I get a time difference only in year and month
require 'spec_helper'
describe RelativeDate::Parser do
describe "#to_time" do
before do
Timecop.freeze
end
['day','week','month','year'].each do |type|
it "should parse #{type} correctly" do
RelativeDate::Parser.to_time("2_#{type}_ago").should == 2.send(type).ago
RelativeDate::Parser.to_time("2_#{type}_from_now").should == 2.send(type).from_now
end
end
after do
Timecop.return
end
end
end
Output
..FF
Failures:
1) RelativeDate::Parser#to_time should parse year correctly
Failure/Error: RelativeDate::Parser.to_time("2_#{type}_ago").should == 2.send(type).ago
expected: Wed, 29 Aug 2012 22:40:14 UTC +00:00
got: Wed, 29 Aug 2012 10:40:14 UTC +00:00 (using ==)
Diff:
## -1,2 +1,2 ##
-Wed, 29 Aug 2012 22:40:14 UTC +00:00
+Wed, 29 Aug 2012 10:40:14 UTC +00:00
# ./spec/lib/relative_date/parser_spec.rb:11:in `(root)'
2) RelativeDate::Parser#to_time should parse month correctly
Failure/Error: RelativeDate::Parser.to_time("2_#{type}_ago").should == 2.send(type).ago
expected: Sun, 29 Jun 2014 22:40:14 UTC +00:00
got: Mon, 30 Jun 2014 22:40:14 UTC +00:00 (using ==)
Diff:
## -1,2 +1,2 ##
-Sun, 29 Jun 2014 22:40:14 UTC +00:00
+Mon, 30 Jun 2014 22:40:14 UTC +00:00
# ./spec/lib/relative_date/parser_spec.rb:11:in `(root)'
Finished in 0.146 seconds
4 examples, 2 failures
Failed examples:
rspec ./spec/lib/relative_date/parser_spec.rb:10 # RelativeDate::Parser#to_time should parse year correctly
rspec ./spec/lib/relative_date/parser_spec.rb:10 # RelativeDate::Parser#to_time should parse month correctly
The first one seems like a time zone issue but the other one is even a day apart? I'm really clueless on this one.
This is a fascinating problem!
First, this has nothing to do with Timecop or RSpec. The problem can be reproduced in the Rails console, as follows:
2.0.0-p247 :001 > 2.months.ago
=> Mon, 30 Jun 2014 20:46:19 UTC +00:00
2.0.0-p247 :002 > 2.months.send(:ago)
DEPRECATION WARNING: Calling #ago or #until on a number (e.g. 5.ago) is deprecated and will be removed in the future, use 5.seconds.ago instead. (called from irb_binding at (irb):2)
=> Wed, 02 Jul 2014 20:46:27 UTC +00:00
[Note: This answer uses the example of months, but the same is true for the alias month as well as year and years.]
Rails adds the month method to the Integer class, returning an ActiveSupport::Duration object, which is a "proxy object" containing a method_missing method which redirects any calls to the method_missing method of the "value" it is serving as a proxy for.
When you call ago directly, it's handled by the ago method in the Duration class itself. When you try to invoke ago via send, however, send is not defined in Duration and is not defined in the BasicObject that all proxy objects inherit from, so the method_missing method of Rails' Duration is invoked which in turn calls send on the integer "value" of the proxy, resulting in the invocation of ago in Numeric. In your case, this results in a change of date equal to 2*30 days.
The only methods you have to work with are those defined by Duration itself and those defined by BasicObject. The latter are as follows:
2.0.0-p247 :023 > BasicObject.instance_methods
=> [:==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
In addition to the instance_eval you discovered, you can use __send__.
Here's the definition of method_missing from duration.rb
def method_missing(method, *args, &block) #:nodoc:
value.send(method, *args, &block)
end
value in this case refers to the number of seconds in the Duration object. If you redefine method_missing to special case ago, you can get your test to pass. Or you can alias send to __send__ as follows:
class ActiveSupport::Duration
alias send __send__
end
Here's another example of how this method_missing method from Duration works:
macbookair1:so1 palfvin$ rails c
Loading development environment (Rails 4.1.1)
irb: warn: can't alias context from irb_context.
2.0.0-p247 :001 > class ActiveSupport::Duration
2.0.0-p247 :002?> def foo
2.0.0-p247 :003?> 'foobar'
2.0.0-p247 :004?> end
2.0.0-p247 :005?> end
=> nil
2.0.0-p247 :006 > 2.months.foo
=> "foobar"
2.0.0-p247 :007 > 2.months.respond_to?(:foo)
=> false
2.0.0-p247 :008 >
You can call the newly defined foo directly, but because BasicObject doesn't implement respond_to?, you can't "test" that the method is defined there. For the same reason, method(:ago) on a Duration object returns #<Method: Fixnum(Numeric)#ago> because that's the ago method defined on value.

Sleep statement in Ruby doesn't accept any rails convertions

I found this very weird. Why am I not able to do this?:
puts Time.now
x=2
puts x
puts x.class
sleep x
puts Time.now
x=x.seconds
puts x
puts x.class
sleep (x)
puts Time.now
The output I get is:
Mon Oct 01 16:14:58 +0530 2012
2
Fixnum
Mon Oct 01 16:15:00 +0530 2012
2
Fixnum
rake aborted!
can't convert ActiveSupport::Duration into time interval
/Users/hariharanganapathiraman/Documents/MigrationScripts/sample/lib/import/boot.rb:23:in `sleep'
Similarly it doesn't work for .minutes or .days.
That's because ActiveSupport::Duration mimics itself as Fixnum class:
ActiveSupport::Duration.new(3600, [[:seconds, 3600]]).class #=> Fixnum
Use sleep(2.seconds.to_i).
The problem is with ActiveSupport::Duration
It's inherited from BasicObject that have only limited number of methods and does not have class method.
If you take a look in ActiveSupport::Duration implementation you'll see that all methods are proxied(via method_missing) to #value, that's Fixnum in your case.
Hence, since ActiveSupport::Duration has no class method, your class call for a x.seconds
goes to Fixnum.

Scope Chaining in Mongoid 2.2 with Rails 3.0.9 and Ruby 1.8.7

Hi I have application running on Ruby 1.8.7 (i am presently not in a position to update this to 1.9.2) and Rails 3.0.9 running mongoid 2.2.2.
I have a couple of named scopes which I have defined as follows
scope :for_pickups, where(:state => "accepted")
scope :confirmed_shipments, where(:state => "confirmed", :created_at.lt => Date.today - 1.day).desc(:created_at).limit(10)
scope :undelivered_shipments, Proc.new{ |start_date_utc, end_date_utc|
start_date_utc = (Date.today - 7.days).to_time.utc if !start_date_utc.present?
end_date_utc = Date.today.to_time.utc if !end_date_utc.present?
any_of({:created_at.gte => start_date_utc, :created_at.lte => end_date_utc},
{:pickup_date.gte => start_date_utc, :pickup_date.lte => end_date_utc},
{:desired_arrival_date.gte => start_date_utc, :desired_arrival_date.lte => end_date_utc}).
where(:state.in => ["accepted"], :state.nin => ["delivered"]).without(:carrier_digest, :carrier_label_image_base64, :carrier_label_html_base64)
}
scope :search, Proc.new{|search_params|
regexp = Regexp.new(/.*#{search_params.strip}.*/i, true)
where(:golfer_name => regexp)
}
This seems to work well and return the expected values when I use them on their own but when I use scope chaining it gets messed up.
For instance when I run Model.undelivered_shipments.search("sid") i get an array which has :ids as the first parameter
[:ids, #[{:created_at=>{"$gte"=>Thu Sep 27 18:30:00 UTC 2012, "$lte"=>Thu Oct 04 18:30:00 UTC 2012}}, {:pickup_date=>{"$gte"=>Thu Sep 27 18:30:00 UTC 2012, "$lte"=>Thu Oct 04 18:30:00 UTC 2012}}, {:desired_arrival_date=>{"$gte"=>Thu Sep 27 18:30:00 UTC 2012, "$lte"=>Thu Oct 04 18:30:00 UTC 2012}}], :_id=>"sid", :state=>{"$nin"=>["delivered"], "$in"=>["accepted"]}},
options: {:fields=>{:carrier_digest=>0, :carrier_label_html_base64=>0, :carrier_label_image_base64=>0}},
class: Shipment,
embedded: false>
]
Not sure why it returns this and why mongoid criteria defines :_id => 'sid' However when i run the search before the undelivered_shipments method it generates the criteria correctly.
It works if run it with other scopes like for_pickups.search etc but not with the undelivered shipments. I understand I am missing something but I've been through the docs and I can't find anything that really helps. I would really appreciate any help on this
Thanks in advance.

Resources