How can I convert a Ruby Date to an integer?
t = Time.now
# => 2010-12-20 11:20:31 -0700
# Seconds since epoch
t.to_i
#=> 1292869231
require 'date'
d = Date.today
#=> #<Date: 2010-12-20 (4911101/2,0,2299161)>
epoch = Date.new(1970,1,1)
#=> #<Date: 1970-01-01 (4881175/2,0,2299161)>
d - epoch
#=> (14963/1)
# Days since epoch
(d - epoch).to_i
#=> 14963
# Seconds since epoch
d.to_time.to_i
#=> 1292828400
Date cannot directly become an integer. Ex:
$ Date.today
=> #<Date: 2017-12-29 ((2458117j,0s,0n),+0s,2299161j)>
$ Date.today.to_i
=> NoMethodError: undefined method 'to_i' for #<Date: 2017-12-29 ((2458117j,0s,0n),+0s,2299161j)>
Your options are either to turn the Date into a time then an Int which will give you the seconds since epoch:
$ Date.today.to_time.to_i
=> 1514523600
Or come up with some other number you want like days since epoch:
$ Date.today.to_time.to_i / (60 * 60 * 24) ### Number of seconds in a day
=> 17529 ### Number of days since epoch
Time.now.to_i
returns seconds since epoch format
Solution for Ruby 1.8 when you have an arbitrary DateTime object:
1.8.7-p374 :001 > require 'date'
=> true
1.8.7-p374 :002 > DateTime.new(2012, 1, 15).strftime('%s')
=> "1326585600"
I had to do it recently and took some time to figure it out but that is how I came across a solution and it may give you some ideas:
require 'date'
today = Date.today
year = today.year
month = today.mon
day = day.mday
year = year.to_s
month = month.to_s
day = day.to_s
if month.length <2
month = "0" + month
end
if day.length <2
day = "0" + day
end
today = year + month + day
today = today.to_i
puts today
At the date of this post, It will put 20191205.
In case the month or day is less than 2 digits it will add a 0 on the left.
I did like this because I had to compare the current date whit some data that came from a DB in this format and as an integer. I hope it helps you.
Related
I know this is basic but I've been struggling for a few hours now and I can't seem to apply one of the many ways there are to convert a string to datetime so I can save it in the database in this format 2018-03-16 00:12:17.555372. Thanks ahead
This is the string output in the console.
params[:event][:start_date]
"03/28/2018 1:46 AM"
[EDIT] Following some leads I've come up with smething really dirty maybe someone can help refactor I'm supressing AM or PM because I don't know how to parse that I know it's awfull any help is appreciated!
if !params[:event][:start_date].empty?
start_date = params[:event][:start_date]
start_date = start_date.gsub(/[AMP]/, '').squish
a = start_date.split('/')
tmp = a[0]
a[0] = a[1]
a[1] = tmp
a = a.split(',').join('/')
start_date = Time.parse(a)
end
if !params[:event][:end_date].empty?
end_date = params[:event][:end_date]
end_date = end_date.gsub(/[AMP]/, '').squish
a = end_date.split('/')
tmp = a[0]
a[0] = a[1]
a[1] = tmp
a = a.split(',').join('/')
end_date = Time.parse(a)
end
You can use DateTime to parse the date from a specific format.
if the format you are looking to parse is "03/28/2018 1:46 AM" then you can do this.
date = DateTime.strptime('03/28/2018 1:46 AM', '%m/%d/%Y %I:%M %p')
# date to ISO 8601
puts date.to_time
# output: 2018-03-28 07:16:00 +0530
puts date.strftime("%m/%d/%Y")
# output: 03/28/2018
Date formats:
Date (Year, Month, Day):
%Y - Year with century (can be negative, 4 digits at least)
-0001, 0000, 1995, 2009, 14292, etc.
%m - Month of the year, zero-padded (01..12)
%_m blank-padded ( 1..12)
%-m no-padded (1..12)
%d - Day of the month, zero-padded (01..31)
%-d no-padded (1..31)
Time (Hour, Minute, Second, Subsecond):
%H - Hour of the day, 24-hour clock, zero-padded (00..23)
%k - Hour of the day, 24-hour clock, blank-padded ( 0..23)
%I - Hour of the day, 12-hour clock, zero-padded (01..12)
%l - Hour of the day, 12-hour clock, blank-padded ( 1..12)
%P - Meridian indicator, lowercase (``am'' or ``pm'')
%p - Meridian indicator, uppercase (``AM'' or ``PM'')
%M - Minute of the hour (00..59)
You can refer to all formats here.
You can parse it like so in ruby:
Parses the given representation of date and time, and creates a DateTime object. This method does not function as a validator.
DateTime.parse('2001-02-03T04:05:06+07:00')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.parse('20010203T040506+0700')
#=> #<DateTime: 2001-02-03T04:05:06+07:00 ...>
DateTime.parse('3rd Feb 2001 04:05:06 PM')
#=> #<DateTime: 2001-02-03T16:05:06+00:00 ...>
Not entirely sure if the string you supplied can be parsed, here is the link to the ruby docs on datetimes Docs
Say I want the difference between tomorrow and now (in hours).
What I've tried:
t = (DateTime.tomorrow - DateTime.now)
(t / 3600).to_i
=> 0
Why does it give 0?
What am I doing wrong?
This is because DateTime.tomorrow does not have any time value. Here:
DateTime.tomorrow
# => Wed, 22 Apr 2015
If you go through official document for DateTime you can see there is no method tomorrow. Its basically Date#tomorrow.
You can use .to_time to get default localtime 00:00:00
DateTime.tomorrow.to_time
# => 2015-04-22 00:00:00 +0530
(DateTime.tomorrow.to_time - DateTime.now) / 1.hours
# => 9.008116581638655
To get exact hour difference between dates:
(DateTime.tomorrow.to_time - Date.today.to_time) / 1.hours
# => 24.0
Try this
t = (DateTime.tomorrow.to_time - Date.today.to_time)
t = (t / 3600).to_i
It returns rational number. You can take days number if you'll use round method:
>> (DateTime.tomorrow - DateTime.now).round
1
Or if you want to take value in hours from now, use Time class:
>> (Date.tomorrow.to_time - Time.now) / 1.hour
11.119436663611111
if you have two dates like
start_time = Time.new(2015,1, 22, 35, 0)
end_time = Time.new(2015,2, 22, 55, 0)
Try Time Difference gem for Ruby at https://rubygems.org/gems/time_difference
def timediff(start, end)
TimeDifference.between(start, end).in_hours
end
and call it like:
timediff(start_time, end_time)
It will work.
Cheers!
There's DateTime#seconds_until_end_of_day:
seconds = DateTime.now.seconds_until_end_of_day
#=> 41133
seconds / 3600
#=> 11
distance_of_time_in_words(seconds)
=> "about 11 hours"
I am using Rails 4, Ruby 2.1 with PostgreSQL.
I have a database field called duration which is an interval data type.
When pulling out the data in this column it returns in the format of hh:mm:ss, e.g. 01:30:00.
I am trying to figure out a way to display this as 1 hour, 30 minutes.
Other examples:
02:00:00 to 2 hours
02:15:00 to 2 hours, 15 minutes
02:01:00 to 2 hours, 1 minute
Just use duration + inspect
seconds = 86400 + 3600 + 15
ActiveSupport::Duration.build(seconds).inspect
=> "1 day, 1 hour, and 15.0 seconds"
Or a it can be a little be customized
ActiveSupport::Duration.build(seconds).parts.map do |key, value|
[value.to_i, key].join
end.join(' ')
=> "1days 1hours 15seconds"
P.S.
You can get seconds with
1.day.to_i
=> 86400
Time can be parsed only in ISO8601 format
ActiveSupport::Duration.parse("PT2H15M").inspect
=> "2 hours and 15 minutes"
I would start with something like this:
def duration_of_interval_in_words(interval)
hours, minutes, seconds = interval.split(':').map(&:to_i)
[].tap do |parts|
parts << "#{hours} hour".pluralize(hours) unless hours.zero?
parts << "#{minutes} minute".pluralize(minutes) unless minutes.zero?
parts << "#{seconds} hour".pluralize(seconds) unless seconds.zero?
end.join(', ')
end
duration_of_interval_in_words('02:00:00')
# => '2 hours'
duration_of_interval_in_words('02:01:00')
# => '2 hours, 1 minute'
duration_of_interval_in_words('02:15:00')
# => '2 hours, 15 minutes'
See also
ActionView::Helpers::DateHelper distance_of_time_in_words (and related)
e.g.
0 <-> 29 secs # => less than a minute
30 secs <-> 1 min, 29 secs # => 1 minute
1 min, 30 secs <-> 44 mins, 29 secs # => [2..44] minutes
... etc
https://apidock.com/rails/ActionView/Helpers/DateHelper/distance_of_time_in_words
Perhaps not appropriate to include in a model validation error? (which is my use case)
You can try following method to display such as:
minutes_to_human(45) # 45 minutes
minutes_to_human(120) # 2 hours
minutes_to_human(75) # 2.5 hours
minutes_to_human(75) # 1.15 hours
def minutes_to_human(minutes)
result = {}
hours = minutes / 60
result[:hours] = hours if hours.positive?
result[:minutes] = ((minutes * 60) - (hours * 60 * 60)) / 60 if minutes % 60 != 0
result[:minutes] /= 60.0 if result.key?(:hours) && result.key?(:minutes)
return I18n.t('helper.minutes_to_human.hours_minutes', time: (result[:hours] + result[:minutes]).round(2)) if result.key?(:hours) && result.key?(:minutes)
return I18n.t('helper.minutes_to_human.hours', count: result[:hours]) if result.key?(:hours)
return I18n.t('helper.minutes_to_human.minutes', count: result[:minutes].round) if result.key?(:minutes)
''
end
Translations:
en:
helper:
minutes_to_human:
minutes:
zero: '%{count} minute'
one: '%{count} minute'
other: '%{count} minutes'
hours:
one: '%{count} hour'
other: '%{count} hours'
hours_minutes: '%{time} hours'
This worked for me:
irb(main):030:0> def humanized_duration(seconds)
irb(main):031:1> ActiveSupport::Duration.build(seconds).parts.except(:seconds).reduce("") do |output, (key, val)|
irb(main):032:2* output+= "#{val}#{key.to_s.first} "
irb(main):033:2> end.strip
irb(main):034:1> end
=> :humanized_duration
irb(main):035:0> humanized_duration(920)
=> "15m"
irb(main):036:0> humanized_duration(3920)
=> "1h 5m"
irb(main):037:0> humanized_duration(6920)
=> "1h 55m"
irb(main):038:0> humanized_duration(10800)
=> "3h"
You can change the format you want the resulting string to be inside the reduce. I like the 'h' and 'm' for hours and minutes. And I excluded the seconds from the duration parts since that wasn't important for my usage of it.
Here is a locale-aware helper method which builds upon MasonMc's answer.
# app/helpers/date_time_helper.rb
module DateTimeHelper
def humanized_duration(duration)
ActiveSupport::Duration.build(duration).parts.except(:seconds).collect do |key, val|
t(:"datetime.distance_in_words.x_#{key}", count: val)
end.join(', ')
end
end
You can also replace join(', ') with to_sentence if it reads better, or get fancy and allow passing a locale, like distance_of_time_in_words.
Gotcha
Rather counter-intuitively, x_hours is absent from Rails' default locale file because distance_of_time_in_words doesn't use it.
You'll need to add it yourself, even if using the rails-i18n gem.
# config/locales/en.datetime.yml
en:
datetime:
distance_in_words:
x_hours:
one: "one hour"
other: "%{count} hours"
Here's the output:
humanized_duration(100)
# => '1 minute'
humanized_duration(12.34.hours)
# => '12 hours, 20 minutes'
humanized_duration(42.hours)
# => '1 day, 18 hours, 25 minutes'
I find that duration.inspect serve the purpose pretty well.
> 10.years.inspect
=> "10 years"
I need to get three dates in variables
Today Since Midnight which I have as
t = Time.now.strftime("%Y-%m-%d 00:00:01") # 2012-11-19 00:00:01
Yesterday Since Midnight (i.e. 00:00:00 to 23:59:59)
y1 = 2012-11-18 00:00:01
y2 = 2012-11-19 23:59:59
it is specifically the y1 & y2 variables I need to create as strings for use in a gem. being new to ruby I am a little confused as Time.yesterday doesn't seem to do what I need
EDIT
For this be sure to include
require 'active_support/all'
and ensure the gem is bundled for your application.
Used:
#current = (Time.now).beginning_of_day.utc.strftime("%Y-%m-%d")
#yesterday = (Time.now - 1.day).beginning_of_day.utc.strftime("%Y-%m-%d")
#everything = (Time.now - 2.day).end_of_day.utc.strftime("%Y-%m-%d")
You can do,
t=Time.now
y1=t-1.day
y2=t+1.day
t = Time.now
t - 1.day # => yesterday
t + 1.day # => tomorrow
convert t to date first,
t = t.to_date
t - 1.day # => yesterday
t + 1.day # => tomorrow
Since you are running Rails there's help to get from ActiveSupport
1.day.ago.midnight
Time.new.beginning_of_day
You should also consider not using 2012-11-19 00:00:01 or 2012-11-19 23:59:59.
Instead you could use 00:00:00 and compare with >= or < depending on what you want to achieve. If you always round to seconds then 2012-11-19 00:00:00 to 2012-11-19 23:59:59 would work.
For example today is 28/07/2011
How do i get the weeks first day the monday which is 25/07/2011 in ruby
>> Date.today.beginning_of_week.strftime('%d/%m/%Y')
#=> 25/07/2011
See the Time and Date classes under Rails for more info, and strftime for information on the formatting options.
Without Rails/ActiveSupport:
phrogz$ irb
> require 'date'
> now = Date.today
#=> #<Date: 2011-07-28 (4911541/2,0,2299161)>
> sunday = now - now.wday
#=> #<Date: 2011-07-24 (4911533/2,0,2299161)>
> monday = now - (now.wday - 1) % 7
#=> #<Date: 2011-07-25 (4911535/2,0,2299161)>
> monday.iso8601
#=> "2011-07-25"
> monday.strftime('%d/%m/%Y')
#=> "25/07/2011"
For more, see the Date class in the Standard Library.
Wrapped up as a method:
require 'date'
# For weekdays to start on Monday use 1 for the offset; for Tuesday use 2, etc.
def week_start( date, offset_from_sunday=0 )
date - (date.wday - offset_from_sunday)%7
end
sun = Date.parse '2011-07-24'
week_start(sun,0).strftime('%a, %b-%d') #=> "Sun, Jul-24"
week_start(sun,1).strftime('%a, %b-%d') #=> "Mon, Jul-18"