Store seconds in the database - Rails - ruby-on-rails

I have a Timekeeper model in my app. It keeps track of started_at time and finished_at time. I want to take the difference between these two datetimes and pull out the seconds and store that value in the database as an integer. Here is what I'm currently working with.
Method:
((timekeeper.started_at - Time.current) * 24 * 60 * 60).to_i
This returns a value that looks like this : -2336036
The two times above are only 12 seconds apart and I get that value. I'm not sure what it is saying.
The takeaway from my question is: How can I store seconds in the database, between two datetimes that looks similar to what I'm doing currently?

If you want to find the difference between the 2 times you just need to do the subtraction as the difference is returned in seconds.
time.started_at - Time.current
if you dont want the fraction of a second
(time.started_at - Time.current).to_i
and the absolute value
((time.started_at - Time.current).to_i).abs
try the above in a rails console

Related

Rails 5 how to save difference in hour and minutes between two datatime in postgres?

my table has 3 columns: data type timestamp,
|created_At | final_time| duracion(difference between created at and final_time)
| | |
the column difference should save the difference in hours and minutes, in this format HH:MM
this is my controller:
def horario
horario.update(duracion: params[:duracion]) // this params is "00:59"
end
but in the table Horarios, in column duracion i have this:
2017-12-24 03:59:00
so i want to save 00:59 (59 minutes) but postgres save all current date and add 3 hours more.
i want to save so in the future i will be able tu sum column duracion. Or should i change data type for this column? In this case which datatype you recomend me for rails to save HH:MM??
thanks.
Rails 5 supports PostgreSQL's interval type to some extent. You can create interval columns in the usual way and they will be properly represented in db/schema.rb. You can also assign them values in the usual way so you can say things like:
model.some_interval = '6 hours'
and get 06:00:00 inside the database. However, there is nothing in Ruby or Rails that properly represents a time interval (we only have various timestamp and date classes) so when that interval comes out of the database, you'll have a string on your hands, i.e:
> model = Model.find(some_id)
> model.some_interval.class
=> String
so you might end up having to manually parse some strings in Ruby. For simple intervals like '6 hours', this will be easy but it won't be so easy with more complicated intervals like '6 years 23 days 11 hours'.
If you'll only be working with your time intervals inside the database then interval would be natural and easy, you can say things like:
select some_timestamp + some_interval
and
where some_timestamp + some_interval < some_other_timestamp
and everything will work nicely.
However, if you need to work with the intervals back in Ruby then you'd probably be better off storing the interval as a number of seconds in an integer column (or whatever resolution you need). Then you could say things like:
where some_timestamp + (some_interval_in_seconds || 'seconds')::interval < some_other_timestamp
inside the database and
some_time + model.some_interval_in_seconds
back in Ruby.
In any case, strings are probably the wrong approach unless you really like parsing strings everywhere all the time.
As others already pointed out, Rails handles the Postgres Interval type as a string. A string that, unfortunately, is not easy to parse.
If you do this:
u = Users.select('edited_at - created_at as time_dif')
puts u.first['time_dif']
You can get something like 168 days 12:51:20.851115. Ugly right?
Well, using Ruby to convert this string into an useful number is not easy, but you can use Postgres to do the job for you. You will need to do a plain SQL query though, but it's the best method I've found so far:
query = ActiveRecord::Base.connection.execute("
SELECT EXTRACT(epoch FROM time_dif)/3600 as hours_dif
FROM
(
SELECT (edited_at - created_at) as time_dif
FROM users
) AS MainQuery
")
In this example, Postgres' EXTRACT function will convert the Interval type into a number which represents the total seconds of the interval. If you divide this number by 3600 you will get the different in hours as in the example above.
Then, if you want to iterate over the results:
query.each do |r|
puts r['hours_dif']
end
You could save duracion as a float type, where duracion would equal something like final_time - created_at and this value would be the difference in seconds. You can then perform arithmetic with these values and always convert back to minutes, hours, or whatever you need.

Rails timestamps, See how much time passed since last time

In my app I want to print out the duration of time I spent from I made the model until I updated it.
So if I have the value
:created_at set to 2016-04-13 14:00:49 UTC
and
:updated_at set to 2016-04-13 15:05:49 UTC
I want to print out that it took 1hour and 5minutes. (or just 01.05).
How do I do this?
I'm not sure why this was downvoted, though a little googling would probably have gotten you to the right answer fairly quickly.
What you're looking for is called time_ago_in_words
Here is the doc http://apidock.com/rails/ActionView/Helpers/DateHelper/time_ago_in_words
And usage is:
time_ago_in_words #object.created_at
time_ago_in_words #object.updated_at
If you want to use it the console to play with it, make sure you preface it with helper so it's loaded into console
e.g.
helper.time_ago_in_words #object.created_at
update
For checking between 2 dates, not just one date from right now, then you can use distance_of_time_in_words
distance_of_time_in_words(#object.created_at, #object.updated_at)
That gives words like
12 days ago
If you're ONLY looking for hours, and nothing else then you can use basic subtraction and division
#object.updated_at.to_i - #object.created_at.to_i) / 60 / 60
You can try this
diff =#object.updated_at.to_time.to_i - #object.created_at.to_time.to_i
hour = "#{diff / 3600}:#{(diff % 3600) / 60}"

Possible to use field in ActiveRecord query?

I have a DateTime in my at field and a number of minutes duration in my minutes field. I want to get all the records where the current time falls within at and at + minutes. Something like:
SpecialEvent.where(at: (DateTime.now - 120.minutes)..DateTime.now)
Except I'm guessing the 120.minutes duration. The exact number of minutes duration for each SpecialEvent is in a minutes field. But I don't know how to use that minutes field within the query...
Some databases (including MySQL) support functions in SQL to perform calculations with dates. This is required to efficiently calculate the timestamp based on data inside the database. Thus, you need to generate correct SQL for your specific database flavour. The example below should work for MySQL. If you use another database, you probably need to adapt this to the available date functions.
SpecialEvent.where(['at >= :now - INTERVAL minutes MINUTE AND at <= :now', now: DateTime.now])
This effectively generates the following SQL query (although with a literal date value instead of NOW():
SELECT * FROM special_events WHERE at >= NOW() - INTERVAL minutes MINUTE AND at <= NOW();
You can format your query like:
SpecialEvent.where(at: (DateTime.now - 120.minutes)..DateTime.now, minutes: '<your search value>')

What is a good way to record time periods in Rails application, so that I can easily use them for calculations?

I have time periods like:
2 years
1 month
4 days
I would like to add them to existing records in my DB in a way that I could easily use them for calculations? The type of calculations I would need would be [time_period] - (Time.now - [datetime]) in order to see how much of the time period is left.
Since my periods are quite standard, I was thinking to save the time periods as strings "2-years", "1-month", "4-days" etc. and split them on use. For example "4-days" could become something like this:
4.send("days".to_sym)
What do you think about this method? Any better ideas?
Okay i have a better solution.
Here is the Class TimeDuration
five_minutes = TimeDuration.new("5 min")
five_minutes + Time.now
Time.now
# => 2013-09-13 02:50:06 +0200
five_minutes + Time.now
# => 2013-09-13 02:55:13 +0200
It would be best to store them all in a standardized format; like seconds, so that you can easily do calculations without having to first convert things. If you also stored some sort of units field (i.e. years, days, minutes, seconds), you could then easily convert the seconds back to their appropriate units for display - sort of like what you have above.
stored_value_in_minutes = stored_value.seconds / 1.minutes

RoR Time into Seconds Question

Let's say I want to find out the difference in seconds between two times. One of the times is the created_at attribute of the element, and the other time is a random fixed time in the past. How would I find the difference between the two, and transform it into seconds?
Lucky for you the - operator in ruby returns you an float which is the difference in seconds.
difference_in_seconds = x.created_at - random_time_in_past
It should be as simple as:
time = Time.now
offset = time - record.created_at
offset will now be a Float which is the difference in seconds between the two compared Time objects.

Resources