I have a starts_at attribute that is a standard DateTime data type. I want to take that time and the current Time to come up with 3 days remaining until event. This is my current method
def days_remaining
(Date.parse(starts_at) - Date.current).to_i
end
but this is giving me this error no implicit conversion of ActiveSupport::TimeWithZone into String
This seems pretty straight forward but I can't seem to figure it out.
Date.parse is expecting String argument, but starts_at is DateTime.
to_date method will convert datetime to date.
def days_remaining
(starts_at.to_date - Date.current).to_i
end
Though, I don't think this is 100% correct way to find remaining days.
Rails has distance_of_time_in_words method that can be used for this kind of thing. There's also the dotiw gem that offers more customisation of the output:
distance_of_time_in_words(Time.now, 2.weeks.from_now, only: :days)
def days_remaining
(starts_at.to_date...Date.current).to_a.count
end
This might be what you need. Creates a range of dates, convert to array, each entry is a day, then count those
Related
I am creating a time object, which I use to gather all info from the past 24 hours, I have no issue creating the object displaying the current time. But I am unsure as to how to set it exactly 24 hours in the past, without having the timezone attached.
def set_time
#past_time = Time.now.to_s(:db) - 1.days
end
Expected Output Format :
"2021-11-29 09:15:17"
Result:
undefined method `-' for "2021-11-29 10:19:46":String
You are subtracting the time from the string object as you converted Time.now into the string using to_s.
Instead of you can do this
(Time.new - 1.days).to_s(:db)
Note: You will get multiple ways to accomplish these rails. You can improve the code readability and understanding of code by doing this.
Example:
DateTime.now.days_ago(1)
The easiest I can think of would be:
24.hours.ago.to_s(:db)
Note that the returned time would default to UTC in this case.
You can use DateTime#advance from ActiveSupport:
Time.current.advance(hours: -24)
# or
Time.current.advance(days: -1)
Note that in timezones that use DST a day is not always 24 hours so the two are not actually equivilent. You can also use the methods that ActiveSupport::Duration monkeypatches onto Integer:
24.hours.ago
1.day.ago
This always uses your default timezone though.
Using Rails 6.
I have an ElectricityUsage model, with a Date field, date. I want to extract all the values for amount only for the current month. How would I accomplish this?
What I immediately attempted was the following:
ElectricityUsage.where(habitat: current_user.reservations[0].room.habitat).where(date.month: Date.today.month)
But that obviously doesn't work, and it wouldn't even account for the year, either. My DB is running on PostgreSQL, if that makes a difference.
You can use where with Date.current.all_month, which basically is just translated into a query using BETWEEN where the start date is the first day of the month and end date is the last one:
ElectricityUsage.where(habitat: current_user.reservations[0].room.habitat, date: Date.current.all_month)
This should work for you
ElectricityUsage.where(habitat: current_user.reservations[0].room.habitat).where("EXTRACT(MONTH FROM date) = ?", Date.current.month)
PostgreSQL Date/Time Functions and Operators
Might be a delayed response but you can use date_queries gem
model ElectricityUsage < ActiveRecord::Base
date_queries_for :date
end
Then you can simply use ElectricityUsage.dates_in_this_month to find all the records that false in current month
I have a date of birth column on my user table that takes a DATE. As this datatype appears as YYYY-MM-DD, I assume that when inputting a date to the database it must have the format, for example: 2013-12-26.
I have seen methods on StackOverflow for creating a random DateTime in Ruby, such as here. However, after much searching I can't find a way to generate a random date without the time, for example in the past 100 years, and have it properly formatted for the DATE datatype. In Rails, what is the best way to generate a random date without the time?
This seems to work:
def rand_date(days)
date = Date.today-rand(days)
date.to_s(:db)
end
But is there a more elegant solution that comes with Rails? I am new to Rails and programming, so any assistance would be most helpful!
Your method is correct. If you are using Rails, there are some trivial improvements such as
def rand_date(days)
rand(days).days.ago(Date.today)
end
which is mostly equivalent to
def rand_date(days)
rand(days).days.ago.to_date
end
The second version is less efficient because it creates more Date/Time objects during the internal conversions.
Apply to_s(:db) if you need the Date to be formatted as String.
A different approach would require you to construct a date passing the result of a rand to Date.new.
This is in core ruby:
1 #!usr/bin/ruby
2
3 require 'date'.
4
5 10.times do |t|
6 random_year = Random.new.rand(2000..2014) # custom range for years
7 random_month =Random.new.rand(1..12)
8 random_day = Random.new.rand(1..30)
9 puts "#{Date.new(random_year,random_month,random_day)}"
10 end
2014-11-29
2010-10-20
2006-02-23
2009-09-17
2006-01-14
2009-01-06
2002-07-06
2005-11-05
2013-06-20
2005-12-02
Here is something I used to generate random birth dates when populating a customer database. It works on days, and in this example, gives random dates between 1967-01-09 and 1993-01-12 by using the Date#jd method:
Date.jd(2439500 + rand(9500))
You can twiddle the dates generated by setting the base (in this case 2439500, which is 1967-01-09) and the random number to increase or decrease the range of dates produced.
Example:
irb(main):043:0> 10.times { puts Date.jd(2439500 + rand(9500)) }
1973-06-07
1973-11-09
1983-07-27
1990-11-03
1967-06-18
1967-06-20
1970-07-28
1990-05-13
1986-11-26
1989-02-15
I have a class that has two params: start_date and end_date.
Those are formatted like - 2012-07-12 and 2012-07-24.
I was to subtract end_date from start_date.
Previous Googling has left me high and dry. Should I convert these to something else to do subtraction?
Convert them into dates and subtract them:
require 'date'
start_date = Date.parse('2012-07-12')
end_date = Date.parse('2012-07-24')
(start_date - end_date).to_i
=> -12
If you want the number of days (end_date-start_date).days should work fine. You'll probably get a Rational number of days, in which case you can just use to_i
If i am not miskaten, the params come in form of a String, so you have to convert it to a Date, DateTime, or Time to do math operations with them.
You can refer to this question to more details.
How can I find the number of days between two Date objects in Ruby?
You can just substract two DateTime objects
Using 1.9
require 'date'
DateTime.parse(end_date) - DateTime.parse(start_date)
I'm having a lot of trouble with a query. I don't really know how to explain this well, but I'm going to try.
Basically, we have several objects with a 'posted_at' field that keeps the date and time something was posted, with the time zone, in a datetime field. I need to query and get a range by date with those objects.
Previously, I was converting that to Date and comparing it to another Date object. The query was something like this:
Date(posted_at) >= :start_date AND Date(posted_at) <= :end_date
However, when Postgre converted it to Date, it lost the timezone info which caused innacurate results to the query.
So, I changed to this:
if start_date then
start_time = Time.zone.parse("#{start_date.year}-#{start_date.month}-#{start_date.day}")
conditions << "posted_at >= :start"
hash[:start] = start_time
end
if end_date then
end_time = Time.zone.parse("#{end_date.year}-#{end_date.month}-#{end_date.day}").end_of_day
conditions << "posted_at <= :end"
hash[:end] = end_time
end
While this gets me the accurate results, it also has horrible performance and is causing some timeouts in my application.
I couldn't find any other way to do this query and still keep the accurate results. Would anyone have some advice or ideas?
Thank you in advance.
You never want to store timezone information in your database.
Here's a read that discusses some of the pitfalls:
http://derickrethans.nl/storing-date-time-in-database.html
You'll get better results as tadman suggests: add a new field with your timestamp at time zone 'utc', and index it. You'll then be able to grab stuff using posted_at between ? and ?.
You may have more luck converting your start and end times to UTC which would render the time-zone mostly irrelevant when making the query itself. This is done easily enough:
start_date.to_time.to_datetime.beginning_of_day.utc
end_date.to_time.to_datetime.end_of_day.utc
You can also adjust your query to be:
posted_at BETWEEN :start AND :end
Be sure to have an index on the fields you're searching, too, or you will get horrible performance.