Skip to content

Instantly share code, notes, and snippets.

@gouf
Created November 5, 2019 08:54
Show Gist options
  • Save gouf/35dfe2c4f84e0576b8e7327445b9c575 to your computer and use it in GitHub Desktop.
Save gouf/35dfe2c4f84e0576b8e7327445b9c575 to your computer and use it in GitHub Desktop.
Paiza 練習問題 : [翌営業日 - その1](https://paiza.jp/works/mondai/dateset/working_day_1?language_uid=ruby)
require File.join(__dir__, 'lib', 'workdays')
# eg. 10 1 FRI
# => 10月4日
workday = WorkDay.new(*gets.chomp.split)
month, day = workday.next_workday
puts "#{month}月#{day}日"
# frozen_string_literal: true
# 月, 日, 曜日から「翌営業日」を算出
class WorkDay
WEEK = %w[SUN MON TUE WED THU FRI SAT]
WORK_DAY = %w[MON TUE WED THU FRI]
NON_WORK_DAY = %w[SUN SAT]
SHORT_MONTH = [2, 4, 6, 9, 11] # 30日終わりの月 (厳格さは求めないので2月も同じ扱いにする)
LONG_MONTH = [1, 3, 5, 7, 8, 10, 12] # 31日終わりの月
private_constant :WEEK, :SHORT_MONTH, :LONG_MONTH, :WORK_DAY, :NON_WORK_DAY
def initialize(month, day, week)
@month = month.to_i
@day = day.to_i
@wday_index = WEEK.index(week) # WEEK 定数を modulo(WEEK.size) で参照するカウンタ
# 外部からの入力によって設定する値が決まるので インスタンス変数として定義
@last_day_of_month =
if SHORT_MONTH.include?(@month)
30
elsif LONG_MONTH.include?(@month)
31
end
end
def next_workday
# 2月28日の次の日は必ず 3月1日扱いにする
if february_28?
@month = 3
@day = 1
@wday_index += 1
return find_workday!
end
@day += 1
@wday_index += 1
find_workday!
end
private
def february_28?
[@month, @day].eql?([2, 28])
end
def non_workday?
NON_WORK_DAY.include?(wday_index_as_string)
end
def workday?
WORK_DAY.include?(wday_index_as_string)
end
def wday_index_as_string
WEEK.at(@wday_index.modulo(WEEK.size))
end
# 「日」加算時、「3月32日」のような値になってないか検査
def day_out_of_bounce?
@day > @last_day_of_month
end
# 「12月32日」のような値になっていれば「1月1日」と翌月に変換する
def adjust_day_month_bounce!
return [@month, @day] unless day_out_of_bounce?
@month += 1
@day = 1
if @month > 12
@month = 1
end
[@month, @day]
end
# 月日 (@month, @day) が営業日になるまで日を進めて探す
def find_workday!
adjust_day_month_bounce!
loop do
break adjust_day_month_bounce! if workday?
@wday_index += 1
@day += 1
adjust_day_month_bounce!
end
end
end
# frozen_string_literal: true
describe WorkDay do
context '#next_workday' do
subject { WorkDay.new(month, day, week).next_workday }
shared_examples 'next_workday' do
it { is_expected.to eq expected }
end
context '2月28日(水)' do
it_behaves_like 'next_workday' do
let(:month) { 2 }
let(:day) { 28 }
let(:week) { 'WED' }
let(:expected) { [3, 1] }
end
end
context '2月28日(金)' do
it_behaves_like 'next_workday' do
let(:month) { 2 }
let(:day) { 28 }
let(:week) { 'FRI' }
let(:expected) { [3, 3] }
end
end
context '2月28日(土)' do
it_behaves_like 'next_workday' do
let(:month) { 2 }
let(:day) { 28 }
let(:week) { 'SAT' }
let(:expected) { [3, 2] }
end
end
context '3月4日(金)' do
it_behaves_like 'next_workday' do
let(:month) { 3 }
let(:day) { 4 }
let(:week) { 'FRI' }
let(:expected) { [3, 7] }
end
end
context '3月31日(金)' do
it_behaves_like 'next_workday' do
let(:month) { 3 }
let(:day) { 31 }
let(:week) { 'FRI' }
let(:expected) { [4, 3] }
end
end
context '7月7日(土)' do
it_behaves_like 'next_workday' do
let(:month) { 7 }
let(:day) { 7 }
let(:week) { 'SAT' }
let(:expected) { [7, 9] }
end
end
context '8月9日(日)' do
it_behaves_like 'next_workday' do
let(:month) { 8 }
let(:day) { 9 }
let(:week) { 'SUN' }
let(:expected) { [8, 10] }
end
end
context '12月31日(土)' do
it_behaves_like 'next_workday' do
let(:month) { 12 }
let(:day) { 31 }
let(:week) { 'SAT' }
let(:expected) { [1, 2] }
end
end
context '12月31日(日)' do
it_behaves_like 'next_workday' do
let(:month) { 12 }
let(:day) { 31 }
let(:week) { 'SUN' }
let(:expected) { [1, 1] }
end
end
context '12月31日(月)' do
it_behaves_like 'next_workday' do
let(:month) { 12 }
let(:day) { 31 }
let(:week) { 'MON' }
let(:expected) { [1, 1] }
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment