Skip to content

Instantly share code, notes, and snippets.

@tatsuosakurai
Last active May 16, 2019 09:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tatsuosakurai/9452f6aa675e1e78007691a73fd95f31 to your computer and use it in GitHub Desktop.
Save tatsuosakurai/9452f6aa675e1e78007691a73fd95f31 to your computer and use it in GitHub Desktop.
誕生日の前後一週間かどうかを判定したい!
# 準備
# `gem i activesupport`
# `gem i rspec`
# 実行
# `rspec birthday_test.rb`
# 実装
require 'active_support'
require 'active_support/core_ext'
# require 'byebug'
class BirthDay
def self.around_a_week?(birthday)
# 元の実装
# today = Date.today
# current_year_birthday = "#{today.year}-#{birthday.strftime("%m-%d")}".to_date
# birthday_prev_week = current_year_birthday - 7
# birthday_next_week = current_year_birthday + 7
# today.between?(birthday_prev_week, birthday_next_week) || \
# today.prev_year.between?(birthday_prev_week, birthday_next_week) || \
# today.next_year.between?(birthday_prev_week, birthday_next_week)
# tatsuosakurai案
# today = Date.today.to_time
# age = (today.strftime('%Y%m%d').to_i - birthday.strftime('%Y%m%d').to_i) / 10000
# age += 1 if (birthday + age.year + 7.days) < today
# from_date = birthday.ago(1.week) + age.year
# to_date = birthday.since(1.week) + age.year
# today.between?(from_date, to_date)
# nay案
# today = Date.today
# [ Date.new(today.year-1, birthday.month, birthday.day),
# Date.new(today.year, birthday.month, birthday.day),
# Date.new(today.year+1, birthday.month, birthday.day)
# ].map { |d| (d.jd - today.jd).abs }.any? { |v| v <= 7 }
# suginoy with tatsuosakurai案
# today = Date.today
# [ Date.new(today.year - 1, birthday.month, birthday.day),
# Date.new(today.year, birthday.month, birthday.day),
# Date.new(today.year + 1, birthday.month, birthday.day)
# ].select { |d| ((today - 1.week)..(today + 1.week)).cover?(d) }.present?
# sinsoku案
# now = Time.current
# (now.year + 1).downto(birthday.year).any? do |year|
# diff = now - birthday.change(year: year)
# diff.negative? ? -1.week <= diff : diff < 8.days
# end
# sinsoku案2
# now = Time.current
# (now.year + 1).downto(birthday.year).any? do |year|
# current_birthday = birthday.change(year: year)
# from = current_birthday.ago(1.week).beginning_of_day
# to = current_birthday.since(1.week).end_of_day
# (from..to).cover?(now)
# end
# hmsk案
# diff = (Time.now.yday - Time.new(Time.now.year, birthday.month, birthday.day).yday).abs
# diff <= 7 || diff >= Time.new(Time.now.year, 12, 31).yday - 7
# hanachin_案 https://twitter.com/hanachin_/status/1128844645025247232
# today = Date.today
# (-7..7).any? do |n|
# date = birthday + n.days
# date.month == today.month && date.day == today.day
# end
# nay案2
# dates = (Date.today - 7)..(Date.today + 7)
# dates.any? { |d| d.month == birthday.month && d.day == birthday.day }
end
end
# spec_helper
require 'rspec'
require 'active_support/testing/time_helpers'
RSpec.configure do |config|
config.include ActiveSupport::Testing::TimeHelpers
end
# spec
RSpec.describe BirthDay do
describe 'around_a_week?' do
subject(:around_a_week?) { travel_to(today.to_time) { BirthDay.around_a_week?(birthday) } }
context '年をまたがない場合' do
let!(:birthday){ '1985-05-26 0:00'.to_time }
context '7日前' do
let!(:today) { '2019-5-19 00:00' }
it { expect(around_a_week?).to eq true }
end
context '8日前' do
let!(:today) { '2019-5-18 23:59' }
it { expect(around_a_week?).to eq false }
end
context '7日後' do
let!(:today) { '2019-6-2 23:59' }
it { expect(around_a_week?).to eq true }
end
context '8日後' do
let!(:today) { '2019-6-3 00:00' }
it { expect(around_a_week?).to eq false }
end
end
context '年をまたぐ場合' do
context '年末の場合' do
let(:birthday){ '1985-12-27 0:00'.to_time }
context '7日前' do
let!(:today) { '2019-12-20 00:00' }
it { expect(around_a_week?).to eq true }
end
context '8日前' do
let!(:today) { '2019-12-19 23:59' }
it { expect(around_a_week?).to eq false }
end
context '7日後' do
let!(:today) { '2020-1-3 23:59' }
it { expect(around_a_week?).to eq true }
end
context '8日後' do
let!(:today) { '2020-1-4 00:00' }
it { expect(around_a_week?).to eq false }
end
end
context '年始の場合' do
let(:birthday){ '1985-01-03 0:00'.to_time }
context '7日前' do
let!(:today) { '2019-12-27 00:00' }
it { expect(around_a_week?).to eq true }
end
context '8日前' do
let!(:today) { '2019-12-26 23:59' }
it { expect(around_a_week?).to eq false }
end
context '7日後' do
let!(:today) { '2020-1-10 23:59' }
it { expect(around_a_week?).to eq true }
end
context '8日後' do
let!(:today) { '2020-1-11 00:00' }
it { expect(around_a_week?).to eq false }
end
end
end
end
end
@tatsuosakurai
Copy link
Author

もっといい実装にできないかなあ

@sinsoku
Copy link

sinsoku commented May 15, 2019

思っていたより難しかった...

now = Time.current
(now.year + 1).downto(birthday.year).any? do |year|
  diff = now - birthday.change(year: year)
  diff.negative? ? -1.week <= diff : diff < 8.days
end

@sinsoku
Copy link

sinsoku commented May 15, 2019

こっちの方が読みやすいですね。

now = Time.current
(now.year + 1).downto(birthday.year).any? do |year|
  current_birthday = birthday.change(year: year)
  from = current_birthday.ago(1.week).beginning_of_day
  to = current_birthday.since(1.week).end_of_day

  (from..to).cover?(now)
end

@tatsuosakurai
Copy link
Author

あざまっす!ここまで反映させました(テストが通ることも念の為確認済み:))

@hmsk
Copy link

hmsk commented May 15, 2019

diff = (Time.now.yday - Time.new(Time.now.year, birthday.month, birthday.day).yday).abs
diff <= 7 || diff >= Time.new(Time.now.year, 12, 31).yday - 7

AS無しで。現状のテストケースは通るものの、うるう年に絡むと通らないケースがいくつかありますが時間切れ〜

@tatsuosakurai
Copy link
Author

あざまっす!
うるう年、そういえば〜〜〜><

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment