I have a controller:
class StatsController < ApplicationController
require 'time'
def index
#started = "Thu Feb 04 16:12:09 UTC 2010"
#finished = "Thu Feb 04 16:13:44 UTC 2010"
#duration_time = stats_duration(#started, #finished)
end
private
def stats_duration(started, finished)
time_taken = distance_of_time_in_words(Time.parse(started), Time.parse(finished))
time_taken
end
end
It takes in a start and end time and calculates the duration between the times.
When I run this I get the following error:
private method `gsub!' called for Thu
Feb 04 16:12:09 UTC 2010:Time
Why is this happening?
private method gsub! called when using Time.parse usually means that you have called parse with a Time object rather than a String so it sounds like your code is actually trying to parse the time twice.
e.g.
>> t = Time.now
=> Fri Feb 05 13:12:17 +0000 2010
>> Time.parse(t)
NoMethodError: private method `gsub!' called for Fri Feb 05 13:12:17 +0000 2010:Time
from c:/ruby/lib/ruby/1.8/date/format.rb:965:in `_parse'
from c:/ruby/lib/ruby/1.8/time.rb:240:in `parse'
from (irb):6
Related
I extended the Time class in my Rails projects so I can easily get the time in NYC:
/lib/extensions.rb .
class Time
# Get NYC time:
def nyc
self.in_time_zone('Eastern Time (US & Canada)')
end
end
Testing it out, looks good:
time_a = Time.now.utc.nyc
=> Sun, 21 Apr 2019 18:42:12 EDT -04:00
The problem is when I pull timestamps from the DB:
time_b = object.created_at.in_time_zone('Eastern Time (US & Canada)')
=> Sun, 21 Apr 2019 17:22:04 EDT -04:00
time_c = object.created_at.nyc
=> Sun, 21 Apr 2019 17:22:04 UTC +00:00
Super confused. Converting the timestamp to EDT works when I use in_time_zone in the console, but not when I use the extension? Even though my extension method works on Time objects I create in console? What's happening here?
(Note: Time instances in Rails are in fact instances of ActiveSupport::TimeWithZone. "TimeWithZone instances implement the same API as Ruby Time instances, so that Time and TimeWithZone instances are interchangeable." - ActiveSupportTimeWithZone)
you would need to patch ActiveSupport::TimeWithZone instead of Time, e.g.
class ActiveSupport::TimeWithZone
def nyc
in_time_zone('Eastern Time (US & Canada)')
end
end
Time.zone.now.nyc # => Mon, 22 Apr 2019 06:44:41 EDT -04:00
User.last.created_at.nyc # => Sun, 21 Apr 2019 13:34:45 EDT -04:00
https://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html
(edit: I previously said "DateTime" instead of "ActiveSupport::TimeWithZone")
In one Form the user also has to specify a date for example the 21.04.2014:
So when a post request is sent to the rails-application, to save a post there is also provided a created_at data in the request:
post[text]:"First Message"
post[created_at]:21.04.2014
So at the end a message is saved. Now when i try to get the created_at for the message:
Message.find(1).created_at
>> 2014-04-21 00:00:00
But i would like that the time corresponds to the actual time when the message was created, so the ouput must look something like this:
>> 2014-04-21 19:52:07
How do i have to save the message so that it meets my concept? Thanks
Actual i save a message like this:
#user.message.new(message_params)
def diagnosis_params
params[:message].permit(:created_at, :text)
end
You can do something like this:
dt = Date.parse('21.04.2014')
# => Mon, 21 Apr 2014
tm = Time.zone.now
# => Tue, 22 Apr 2014 00:34:07 MSK +04:00
created_at = DateTime.new(dt.year, dt.month, dt.day, tm.hour, tm.min, tm.sec)
# => Mon, 21 Apr 2014 00:34:07 +0000
Not very elegant but you can create some utility method...
I have my User model with the following functions:
def self.chart_data(start = 1.weeks.ago)
total_users = users_by_day(start)
(start.to_date..Date.today).map do |date|
{
created_at: date,
users: total_users[date] || 0
}
end
end
def self.users_by_day(start)
users = where(created_at: start.beginning_of_day..Time.zone.now)
users = users.group("date(created_at), id")
users = users.select("created_at, count(id) as total_users")
users.each_with_object({}) do |user, total_users|
total_users[user.created_at.to_date] = total_users
end
end
And my View has the following line:
<%= content_tag :div, "", id: "users_chart", data: {users: User.chart_data} %>
I get the following error:
ActiveSupport::JSON::Encoding::CircularReferenceError in Static#statistics
Showing statistics.html.erb where line #5 raised:
object references itself
When i i just print the data it looks as the following:
[{:created_at=>Wed, 27 Nov 2013, :users=>0}, {:created_at=>Thu, 28 Nov 2013, :users=>0}, {:created_at=>Fri, 29 Nov 2013, :users=>0}, {:created_at=>Sat, 30 Nov 2013, :users=>0}, {:created_at=>Sun, 01 Dec 2013, :users=>0}, {:created_at=>Mon, 02 Dec 2013, :users=>0}, {:created_at=>Tue, 03 Dec 2013, :users=>{Tue, 03 Dec 2013=>{...}}}, {:created_at=>Wed, 04 Dec 2013, :users=>0}]
The only user is on 03 Dec, if there are no users there is also no error.
As you'll note in the printed data, there is a recursive reference on the 3rd:
{:created_at=>Tue, 03 Dec 2013, :users=>{Tue, 03 Dec 2013=>{...}}}
The origins come from how users_by_day is constructed. The has building references itself, by assigning an object on a given day to itself:
users.each_with_object({}) do |user, total_users|
total_users[user.created_at.to_date] = total_users
end
I think this is just an oversight in variable naming. The aggregate object you are creating is called total_users by the block, and it's the same name you give it inside the query. I believe the correct block would be this:
users.each_with_object({}) do |user, total_users|
total_users[user.created_at.to_date] = user.total_users
end
Since you need to get the total off the user variable.
There are two issues here:
I have this code to publish on users' facebook walls:
def publish_on_facebook
if user.last_published < 1.day.ago
#graph = Koala::Facebook::API.new(user.service.token)
begin
#graph.put_wall_post("some post")
user.last_published = Time.now
user.save
rescue
user.last_published = 1.week.from_now
user.save
end
end
end
It works perfectly:
if the user has authorized me, it publishes and updates the last_published (type datetime) field to now.
If the user has not authorized me to publish stuff in his wall, then it updates the last_published field to 1 week from now.
Now when I run in through my Cucumber, testing, it doesn't work:
When the user has authorized me, the last_published field updates to 1 minute from now, but 2 days ago
expected: > Sun, 03 Mar 2013 16:12:44 UTC +00:00
got: Fri, 01 Mar 2013 16:13:43 UTC +00:00
When the user hasn't authorized me, no change on the last_published field (i set the default value of the field to march 1st)
expected: > Sat, 09 Mar 2013 16:13:47 UTC +00:00
got: Fri, 01 Mar 2013 15:01:11 UTC +00:00
Any ideas?
When updating attributes, the variable #user must be reloaded:
#user.update_attributes(attribute: value)
#user = User.find(#user)
Cucumber was evaluating the values stored in #user, which were not up to date after the method ran.
I am trying to create a page to display a list of links for each month, grouped into years. The months need to be between two dates, Today, and The date of the first entry.
I am at a brick wall, I have no idea how to create this.
Any help would be massively appriciated
Regards
Adam
Just put what you want inside a range loop and use the Date::MONTHNAMES array like so
(date.year..laterdate.year).each do |y|
mo_start = (date.year == y) ? date.month : 1
mo_end = (laterdate.year == y) ? laterdate.month : 12
(mo_start..mo_end).each do |m|
puts Date::MONTHNAMES[m]
end
end
The following code will add a months_between instance method to the Date class
#!/usr/bin/ruby
require 'date'
class Date
def self.months_between(d1, d2)
months = []
start_date = Date.civil(d1.year, d1.month, 1)
end_date = Date.civil(d2.year, d2.month, 1)
raise ArgumentError unless d1 <= d2
while (start_date < end_date)
months << start_date
start_date = start_date >>1
end
months << end_date
end
end
This is VERY lightly tested, however it returns an Array of dates each date being the 1st day in each affected month.
I don't know if I've completely understood your problem, but some of the following might be useful. I've taken advantage of the extensions to Date provided in ActiveSupport:
d1 = Date.parse("20070617") # => Sun, 17 Jun 2007
d2 = Date.parse("20090529") #=> Fri, 29 May 2009
eom = d1.end_of_month #=> Sat, 30 Jun 2007
mth_ends = [eom] #=> [Sat, 30 Jun 2007]
while eom < d2
eom = eom.advance(:days => 1).end_of_month
mth_ends << eom
end
yrs = mth_ends.group_by{|me| me.year}
The final line uses another handy extension: Array#group_by, which does pretty much exactly what it promises.
d1.year.upto(d2.year) do |yr|
puts "#{yrs[yr].min}, #{yrs[yr].max}"
end
2007-06-30, 2007-12-31
2008-01-31, 2008-12-31
2009-01-31, 2009-05-31
I don't know if the start/end points are as desired, but you should be able to figure out what else you might need.
HTH
Use the date_helper gem which adds the months_between method to the Date class similar to Steve's answer.
xmas = Date.parse("2013-12-25")
hksar_establishment_day = Date.parse("2014-07-01")
Date.months_between(xmas,hksar_establishment_day)
=> [Sun, 01 Dec 2013, Wed, 01 Jan 2014, Sat, 01 Feb 2014, Sat, 01 Mar 2014, Tue, 01 Apr 2014, Thu, 01 May 2014, Sun, 01 Jun 2014, Tue, 01 Jul 2014]