How do I push dates into an array by week? - ruby-on-rails

I am writing this code that maps dates by day and pushes them into an array:
rtn_ary = []
(2.weeks.ago.to_date..Date.today).map do |date|
rtn_ary << {period: date}
end
How can I write the code if my expected result is based on weeks instead of days like this?
[[{:period=>Mon, 28 Sep 2015}, {:period=>Tue, 05 Oct 2015}, {:period=>Tue, 12 Oct 2015}]

A simple solution could be to iterate by 7 days instead of 1 day:
rtn_ary = (2.weeks.ago.to_date..Date.today).step(7).map do |date|
{period: date}
end
=> [{:period=>Mon, 28 Sep 2015}, {:period=>Mon, 05 Oct 2015}]
More info about step: http://ruby-doc.org/core-1.9.3/Range.html#method-i-step

To get what you want you'll need an additional step:
(2.weeks.ago.to_date..Date.today).map do |date|
rtn_ary << {period: date.to_formatted_s(:long)}
end
The to_formatted_s() method convert the date into a formatted string and takes a parameter which will define how the date will be formatted into a string.
date.to_formatted_s(:short) # => "10 Nov"
date.to_formatted_s(:number) # => "20071110"
date.to_formatted_s(:long) # => "November 10, 2007"
date.to_formatted_s(:long_ordinal) # => "November 10th, 2007"
date.to_formatted_s(:rfc822) # => "10 Nov 2007"
date.to_formatted_s(:iso8601) # => "2007-11-10"
Take a look at the rails Documentation

Related

How to get all 'specific days' within a date range

How can I get let's say All the dates for Saturday and Sunday from X year to Y year and store them as array? Pseudo code would be
(year_today..next_year).get_all_dates_for_saturday_and_sunday
Or perhaps there are gems that cater to this already?
Try this:
(Date.today..Date.today.next_year).select { |date|
date.sunday? or date.saturday?
}
#=> [Sat, 03 Sep 2016,Sun, 04 Sep 2016,Sat, 10 Sep 2016,Sun, 11 Sep 2016...
(Date.today..(Date.today + 1.year)).select do |date|
date.saturday? || date.sunday?
end # => [Sat, 03 Sep 2016, Sun, 04 Sep 2016, Sat, 10 Sep 2016, ...
This will then give you an array of 104 elements containing every date which is a saturday or a sunday between today and today in a year.
The following approach emphasizes efficiency over brevity, by avoiding the need to determine if every day in a range is a given day (or one of two given days) of the week.
Code
require 'date'
def dates_by_years_and_wday(start_year, end_year, wday)
(first_date_by_year_and_wday(start_year, wday)...
first_date_by_year_and_wday(end_year+1, wday)).step(7).to_a
end
def first_date_by_year_and_wday(year, wday)
d = Date.new(year)
d + (wday >= d.wday ? wday - d.wday : 7 + wday - d.wday)
end
Notice that the range is defined with three dots, meaning the first date in end_year is excluded.
Example
SATURDAY = 6
SUNDAY = 0
start_year, end_year = 2015, 2017
dates_by_years_and_wday(start_year, end_year, SATURDAY)
#=> [#<Date: 2015-01-03 ((2457026j,0s,0n),+0s,2299161j)>,
# #<Date: 2015-01-10 ((2457033j,0s,0n),+0s,2299161j)>,
# ...
# #<Date: 2017-12-30 ((2458118j,0s,0n),+0s,2299161j)>]
dates_by_years_and_wday(start_year, end_year, SATURDAY).size
#=> 157
dates_by_years_and_wday(start_year, end_year, SUNDAY)
#=> [#<Date: 2015-01-04 ((2457027j,0s,0n),+0s,2299161j)>,
# #<Date: 2015-01-11 ((2457034j,0s,0n),+0s,2299161j)>,
# ...
# #<Date: 2017-12-31 ((2458119j,0s,0n),+0s,2299161j)>]
dates_by_years_and_wday(start_year, end_year, SUNDAY).size
#=> 157

Date validation in Ruby

How to check if the date is valid date in ruby. Many of the methods are check only the range. But, I need to check the date with day of
week to check whether the date is valid or not. For Ex:
20 Jul 2016 Wed --> Valid
20 Jul 2016 Mon --> Not-Valid
How to do this in ruby ?
I'm not pretend on the best solution ever, but this should work.
def valid_date?(date)
Date.parse(date).strftime("%d %b %Y %a") == date
end
[55] pry(main)> valid_date?("20 Jul 2016 Wed")
=> true
[56] pry(main)> valid_date?("20 Jul 2016 Mon")
=> false
[57] pry(main)>
If you have many formats you may pass format as a second argument
def valid_date?(date, fmt)
Date.parse(date).strftime(fmt) == date
end
=> :valid_date?
[59] pry(main)> valid_date?("20 Jul 2016 Wed", "%d %b %Y %a")
=> true
Hope this will help.
UPDATE
As I mentioned in comment that method name overlaps with existing method valid_date?
So, you may just rename the custom method
def date_valid?(date, fmt)
Date.parse(date).strftime(fmt) == date
end
[2] pry(main)> date_valid?("20 Jul 2016 Wed", "%d %b %Y %a")
=> true
Just out of curiosity:
dates = ['20 Jul 2016 Wed', '20 Jul 2016 Mon']
dates.map do |date|
Date.parse(date).public_send(
Date.instance_methods.detect do |m|
m.to_s =~ /\A#{date[-3..-1].downcase}.*day\?\z/
end)
end
#⇒ [ true, false ]
require 'date'
dates = ['20 Jul 2016 Wed', '20 Jul 2016 Mon']
dates.select do |s|
d = Date.strptime(s[0,11], "%d %b %Y") rescue nil
d.nil? ? false : (Date::ABBR_DAYNAMES[d.wday] == s[-3,3])
end
#=> ["20 Jul 2016 Wed"]
This reads, "select strings 'dd mmm yyyy' that represent valid dates and whose day-of-week matches the day-of-week given by the last three characters of the string".

How to convert date format in Ruby

Here are some outputs:
Date.today => Mon, 25 Jun 2012
Date.today.to_formatted_s(:long_ordinal) => "June 25th, 2012"
Date.today.strftime('%A %d, %B') => "Monday 25, June"
Now I need output in the format ie:
Monday 25th, June or Thrusday, 1st, October
Problem is to_formatted_s and strftime apply only on date and both or them return string. How can I get the output in the way I need?
You can use Date::DATE_FORMATS to add a new customized format, and Integer.ordinalize to get the day ordinal:
Date::DATE_FORMATS[:month_ordinal] = lambda { |date|
date.strftime("%A #{date.day.ordinalize}, %B")
}
>> Date.today.to_formatted_s(:month_ordinal)
=> "Monday 25th, June"

Ruby expression evaluation: whitespace matters?

Imagine it's Jan 19. This will not be hard if you look at this question today.
Date.today
=> Thu, 19 Jan 2012 # as expected
Date.today + 1
=> Fri, 20 Jan 2012 # as expected
Date.today+1
=> Fri, 20 Jan 2012 # as expected
Date.today +1
=> Thu, 19 Jan 2012 # ?!
What am I missing here?
The difference is that:
Date.today + 1
is an addition of two numerical values and
Date.today +1
is a call to the method today with the parameter sg(day of calendar reform) with value +1
The best way to examine this is to monkey patch the original method with debug output included. See this script as example:
require 'date'
class Date
def self.today(sg=ITALY)
puts "ITALY default("+sg.to_s+")" if sg==ITALY
puts sg unless sg==ITALY
jd = civil_to_jd(*(Time.now.to_a[3..5].reverse << sg))
new0(jd_to_ajd(jd, 0, 0), 0, sg)
end
end
puts "- Addition:"
Date.today + 1
puts "- Parameter:"
Date.today +1
This will print the following console output:
- Addition:
ITALY default(2299161)
- Parameter:
1
Yes, whitespace does matter in Ruby, contrary to popular belief. For example, foo bar is not the same as foobar.
In this particular case,
Date.today + 1
is the same as
Date.today().+(1)
Whereas
Date.today +1
is the same as
Date.today(+1)
which is the same as
Date.today(1.+#())

In Ruby on Rails, how do I format a date with the "th" suffix, as in, "Sun Oct 5th"?

I want to display dates in the format: short day of week, short month, day of month without leading zero but including "th", "st", "nd", or "rd" suffix.
For example, the day this question was asked would display "Thu Oct 2nd".
I'm using Ruby 1.8.7, and Time.strftime just doesn't seem to do this. I'd prefer a standard library if one exists.
Use the ordinalize method from 'active_support'.
>> time = Time.new
=> Fri Oct 03 01:24:48 +0100 2008
>> time.strftime("%a %b #{time.day.ordinalize}")
=> "Fri Oct 3rd"
Note, if you are using IRB with Ruby 2.0, you must first run:
require 'active_support/core_ext/integer/inflections'
You can use active_support's ordinalize helper method on numbers.
>> 3.ordinalize
=> "3rd"
>> 2.ordinalize
=> "2nd"
>> 1.ordinalize
=> "1st"
Taking Patrick McKenzie's answer just a bit further, you could create a new file in your config/initializers directory called date_format.rb (or whatever you want) and put this in it:
Time::DATE_FORMATS.merge!(
my_date: lambda { |time| time.strftime("%a, %b #{time.day.ordinalize}") }
)
Then in your view code you can format any date simply by assigning it your new date format:
My Date: <%= h some_date.to_s(:my_date) %>
It's simple, it works, and is easy to build on. Just add more format lines in the date_format.rb file for each of your different date formats. Here is a more fleshed out example.
Time::DATE_FORMATS.merge!(
datetime_military: '%Y-%m-%d %H:%M',
datetime: '%Y-%m-%d %I:%M%P',
time: '%I:%M%P',
time_military: '%H:%M%P',
datetime_short: '%m/%d %I:%M',
due_date: lambda { |time| time.strftime("%a, %b #{time.day.ordinalize}") }
)
>> require 'activesupport'
=> []
>> t = Time.now
=> Thu Oct 02 17:28:37 -0700 2008
>> formatted = "#{t.strftime("%a %b")} #{t.day.ordinalize}"
=> "Thu Oct 2nd"
Although Jonathan Tran did say he was looking for the abbreviated day of the week first followed by the abbreviated month, I think it might be useful for people who end up here to know that Rails has out-of-the-box support for the more commonly usable long month, ordinalized day integer, followed by the year, as in June 1st, 2018.
It can be easily achieved with:
Time.current.to_date.to_s(:long_ordinal)
=> "January 26th, 2019"
Or:
Date.current.to_s(:long_ordinal)
=> "January 26th, 2019"
You can stick to a time instance if you wish as well:
Time.current.to_s(:long_ordinal)
=> "January 26th, 2019 04:21"
You can find more formats and context on how to create a custom one in the Rails API docs.
Create your own %o format.
Initializer
config/initializers/srtftime.rb
module StrftimeOrdinal
def self.included( base )
base.class_eval do
alias_method :old_strftime, :strftime
def strftime( format )
old_strftime format.gsub( "%o", day.ordinalize )
end
end
end
end
[ Time, Date, DateTime ].each{ |c| c.send :include, StrftimeOrdinal }
Usage
Time.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
You can use this with Date and DateTime as well:
DateTime.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
Date.new( 2018, 10, 2 ).strftime( "%a %b %o" )
=> "Tue Oct 2nd"
I like Bartosz's answer, but hey, since this is Rails we're talking about, let's take it one step up in devious. (Edit: Although I was going to just monkeypatch the following method, turns out there is a cleaner way.)
DateTime instances have a to_formatted_s method supplied by ActiveSupport, which takes a single symbol as a parameter and, if that symbol is recognized as a valid predefined format, returns a String with the appropriate formatting.
Those symbols are defined by Time::DATE_FORMATS, which is a hash of symbols to either strings for the standard formatting function... or procs. Bwahaha.
d = DateTime.now #Examples were executed on October 3rd 2008
Time::DATE_FORMATS[:weekday_month_ordinal] =
lambda { |time| time.strftime("%a %b #{time.day.ordinalize}") }
d.to_formatted_s :weekday_month_ordinal #Fri Oct 3rd
But hey, if you can't resist the opportunity to monkeypatch, you could always give that a cleaner interface:
class DateTime
Time::DATE_FORMATS[:weekday_month_ordinal] =
lambda { |time| time.strftime("%a %b #{time.day.ordinalize}") }
def to_my_special_s
to_formatted_s :weekday_month_ordinal
end
end
DateTime.now.to_my_special_s #Fri Oct 3rd

Resources