Skip to content

Commit 03200da

Browse files
Add swift scheduling exercise (#749)
* Fixes to concept tree * Add Swift Scheduling exercise with instructions, examples, and tests * Apply suggestion from @ryanplusplus --------- Co-authored-by: Ryan Hartlage <2488333+ryanplusplus@users.noreply.github.com>
1 parent 0eb2ad0 commit 03200da

9 files changed

Lines changed: 328 additions & 0 deletions

File tree

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,14 @@
10901090
"prerequisites": [],
10911091
"difficulty": 4
10921092
},
1093+
{
1094+
"slug": "swift-scheduling",
1095+
"name": "Swift Scheduling",
1096+
"uuid": "7f8b5494-1424-488a-a650-e5ceca8ed6f2",
1097+
"practices": [],
1098+
"prerequisites": [],
1099+
"difficulty": 4
1100+
},
10931101
{
10941102
"slug": "grade-school",
10951103
"name": "Grade School",
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Instructions
2+
3+
Your task is to convert delivery date descriptions to _actual_ delivery dates, based on when the meeting started.
4+
5+
There are two types of delivery date descriptions:
6+
7+
1. Fixed: a predefined set of words.
8+
2. Variable: words that have a variable component, but follow a predefined set of patterns.
9+
10+
## Fixed delivery date descriptions
11+
12+
There are three fixed delivery date descriptions:
13+
14+
- `"NOW"`
15+
- `"ASAP"` (As Soon As Possible)
16+
- `"EOW"` (End Of Week)
17+
18+
The following table shows how to translate them:
19+
20+
| Description | Meeting start | Delivery date |
21+
| ----------- | ----------------------------- | ----------------------------------- |
22+
| `"NOW"` | - | Two hours after the meeting started |
23+
| `"ASAP"` | Before 13:00 | Today at 17:00 |
24+
| `"ASAP"` | After or at 13:00 | Tomorrow at 13:00 |
25+
| `"EOW"` | Monday, Tuesday, or Wednesday | Friday at 17:00 |
26+
| `"EOW"` | Thursday or Friday | Sunday at 20:00 |
27+
28+
## Variable delivery date descriptions
29+
30+
There are two variable delivery date description patterns:
31+
32+
- `"<N>M"` (N-th month)
33+
- `"Q<N>"` (N-th quarter)
34+
35+
| Description | Meeting start | Delivery date |
36+
| ----------- | ------------------------- | --------------------------------------------------------- |
37+
| `"<N>M"` | Before N-th month | At 8:00 on the _first_ workday of this year's N-th month |
38+
| `"<N>M"` | After or in N-th month | At 8:00 on the _first_ workday of next year's N-th month |
39+
| `"Q<N>"` | Before or in N-th quarter | At 8:00 on the _last_ workday of this year's N-th quarter |
40+
| `"Q<N>"` | After N-th quarter | At 8:00 on the _last_ workday of next year's N-th quarter |
41+
42+
~~~~exercism/note
43+
A workday is a Monday, Tuesday, Wednesday, Thursday, or Friday.
44+
45+
A year has four quarters, each with three months:
46+
1. January/February/March
47+
2. April/May/June
48+
3. July/August/September
49+
4. October/November/December.
50+
~~~~
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Introduction
2+
3+
This week, it is your turn to take notes in the department's planning meeting.
4+
In this meeting, your boss will set delivery dates for all open work items.
5+
Annoyingly, instead of specifying the _actual_ delivery dates, your boss will only _describe them_ in an abbreviated format.
6+
As many of your colleagues won't be familiar with this corporate lingo, you'll need to convert these delivery date descriptions to actual delivery dates.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"meatball133"
4+
],
5+
"files": {
6+
"solution": [
7+
"src/swift_scheduling.cr"
8+
],
9+
"test": [
10+
"spec/swift_scheduling_spec.cr"
11+
],
12+
"example": [
13+
".meta/src/example.cr"
14+
]
15+
},
16+
"blurb": "Convert delivery date descriptions to actual delivery dates.",
17+
"source": "Erik Schierboom",
18+
"source_url": "https://github.com/exercism/problem-specifications/pull/2536"
19+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
module SwiftScheduling
2+
private def self.first_workday_of_month(year : Int32, month : Int32) : Time
3+
first = Time.utc(year, month, 1, 8, 0, 0)
4+
5+
case first.day_of_week
6+
when Time::DayOfWeek::Saturday
7+
first + 2.days
8+
when Time::DayOfWeek::Sunday
9+
first + 1.day
10+
else
11+
first
12+
end
13+
end
14+
15+
private def self.last_workday_of_month(year : Int32, month : Int32) : Time
16+
next_month = month == 12 ? 1 : month + 1
17+
next_year = month == 12 ? year + 1 : year
18+
19+
last = Time.utc(next_year, next_month, 1, 8, 0, 0) - 1.day
20+
21+
case last.day_of_week
22+
when Time::DayOfWeek::Saturday
23+
last - 1.day
24+
when Time::DayOfWeek::Sunday
25+
last - 2.days
26+
else
27+
last
28+
end
29+
end
30+
31+
def self.delivery_date(meeting_start : Time, description : String) : Time
32+
result = meeting_start
33+
case description
34+
when "NOW"
35+
result = meeting_start + 2.hours
36+
when "ASAP"
37+
if meeting_start.hour < 13
38+
result = Time.utc(meeting_start.year, meeting_start.month, meeting_start.day, 17, 0, 0)
39+
else
40+
tomorrow = meeting_start + 1.day
41+
result = Time.utc(tomorrow.year, tomorrow.month, tomorrow.day, 13, 0, 0)
42+
end
43+
when "EOW"
44+
case meeting_start.day_of_week.to_i
45+
when 1..3 # Monday to Wednesday
46+
friday = meeting_start + (5 - meeting_start.day_of_week.to_i).days
47+
result = Time.utc(friday.year, friday.month, friday.day, 17, 0, 0)
48+
when 4, 5 # Thursday or Friday
49+
sunday = meeting_start + (7 - meeting_start.day_of_week.to_i).days
50+
result = Time.utc(sunday.year, sunday.month, sunday.day, 20, 0, 0)
51+
end
52+
else
53+
# | `"<N>M"` | Before N-th month | At 8:00 on the _first_ workday of this year's N-th month |
54+
# | `"<N>M"` | After or in N-th month | At 8:00 on the _first_ workday of next year's N-th month |
55+
# | `"Q<N>"` | Before or in N-th quarter | At 8:00 on the _last_ workday of this year's N-th quarter |
56+
# | `"Q<N>"` | After N-th quarter | At 8:00 on the _last_ workday of next year's N-th quarter |
57+
if description.includes?("M")
58+
month = description[0..-2].to_i
59+
year = meeting_start.month < month ? meeting_start.year : meeting_start.year + 1
60+
result = first_workday_of_month(year, month)
61+
elsif description.includes?("Q")
62+
quarter = description[1..-1].to_i
63+
start_quarter = ((meeting_start.month - 1) // 3) + 1
64+
year = start_quarter <= quarter ? meeting_start.year : meeting_start.year + 1
65+
result = last_workday_of_month(year, quarter * 3)
66+
end
67+
end
68+
result
69+
end
70+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
require "spec"
2+
require "../src/*"
3+
4+
describe "<%-= to_capitalized(@json["exercise"].to_s) %>" do
5+
<%- @json["cases"].as_a.each do |cases| %>
6+
<%= status()%> "<%-= cases["description"] %>" do
7+
start = Time.parse_utc("<%= cases["input"]["meetingStart"] %>", "%Y-%m-%dT%H:%M:%S")
8+
expected = Time.parse_utc("<%-= cases["expected"] %>", "%Y-%m-%dT%H:%M:%S")
9+
<%-= to_capitalized(@json["exercise"].to_s) %>.<%= cases["property"].to_s.underscore %>(start, <%= cases["input"]["description"].to_s.inspect %>).should eq(expected)
10+
end
11+
<% end %>
12+
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[1d0e6e72-f370-408c-bc64-5dafa9c6da73]
13+
description = "NOW translates to two hours later"
14+
15+
[93325e7b-677d-4d96-b017-2582af879dc2]
16+
description = "ASAP before one in the afternoon translates to today at five in the afternoon"
17+
18+
[cb4252a3-c4c1-41f6-8b8c-e7269733cef8]
19+
description = "ASAP at one in the afternoon translates to tomorrow at one in the afternoon"
20+
21+
[6fddc1ea-2fe9-4c60-81f7-9220d2f45537]
22+
description = "ASAP after one in the afternoon translates to tomorrow at one in the afternoon"
23+
24+
[25f46bf9-6d2a-4e95-8edd-f62dd6bc8a6e]
25+
description = "EOW on Monday translates to Friday at five in the afternoon"
26+
27+
[0b375df5-d198-489e-acee-fd538a768616]
28+
description = "EOW on Tuesday translates to Friday at five in the afternoon"
29+
30+
[4afbb881-0b5c-46be-94e1-992cdc2a8ca4]
31+
description = "EOW on Wednesday translates to Friday at five in the afternoon"
32+
33+
[e1341c2b-5e1b-4702-a95c-a01e8e96e510]
34+
description = "EOW on Thursday translates to Sunday at eight in the evening"
35+
36+
[bbffccf7-97f7-4244-888d-bdd64348fa2e]
37+
description = "EOW on Friday translates to Sunday at eight in the evening"
38+
39+
[d651fcf4-290e-407c-8107-36b9076f39b2]
40+
description = "EOW translates to leap day"
41+
42+
[439bf09f-3a0e-44e7-bad5-b7b6d0c4505a]
43+
description = "2M before the second month of this year translates to the first workday of the second month of this year"
44+
45+
[86d82e83-c481-4fb4-9264-625de7521340]
46+
description = "11M in the eleventh month translates to the first workday of the eleventh month of next year"
47+
48+
[0d0b8f6a-1915-46f5-a630-1ff06af9da08]
49+
description = "4M in the ninth month translates to the first workday of the fourth month of next year"
50+
51+
[06d401e3-8461-438f-afae-8d26aa0289e0]
52+
description = "Q1 in the first quarter translates to the last workday of the first quarter of this year"
53+
54+
[eebd5f32-b16d-4ecd-91a0-584b0364b7ed]
55+
description = "Q4 in the second quarter translates to the last workday of the fourth quarter of this year"
56+
57+
[c920886c-44ad-4d34-a156-dc4176186581]
58+
description = "Q3 in the fourth quarter translates to the last workday of the third quarter of next year"
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
require "spec"
2+
require "../src/*"
3+
4+
describe "SwiftScheduling" do
5+
it "NOW translates to two hours later" do
6+
start = Time.parse_utc("2012-02-13T09:00:00", "%Y-%m-%dT%H:%M:%S")
7+
expected = Time.parse_utc("2012-02-13T11:00:00", "%Y-%m-%dT%H:%M:%S")
8+
SwiftScheduling.delivery_date(start, "NOW").should eq(expected)
9+
end
10+
11+
pending "ASAP before one in the afternoon translates to today at five in the afternoon" do
12+
start = Time.parse_utc("1999-06-03T09:45:00", "%Y-%m-%dT%H:%M:%S")
13+
expected = Time.parse_utc("1999-06-03T17:00:00", "%Y-%m-%dT%H:%M:%S")
14+
SwiftScheduling.delivery_date(start, "ASAP").should eq(expected)
15+
end
16+
17+
pending "ASAP at one in the afternoon translates to tomorrow at one in the afternoon" do
18+
start = Time.parse_utc("2008-12-21T13:00:00", "%Y-%m-%dT%H:%M:%S")
19+
expected = Time.parse_utc("2008-12-22T13:00:00", "%Y-%m-%dT%H:%M:%S")
20+
SwiftScheduling.delivery_date(start, "ASAP").should eq(expected)
21+
end
22+
23+
pending "ASAP after one in the afternoon translates to tomorrow at one in the afternoon" do
24+
start = Time.parse_utc("2008-12-21T14:50:00", "%Y-%m-%dT%H:%M:%S")
25+
expected = Time.parse_utc("2008-12-22T13:00:00", "%Y-%m-%dT%H:%M:%S")
26+
SwiftScheduling.delivery_date(start, "ASAP").should eq(expected)
27+
end
28+
29+
pending "EOW on Monday translates to Friday at five in the afternoon" do
30+
start = Time.parse_utc("2025-02-03T16:00:00", "%Y-%m-%dT%H:%M:%S")
31+
expected = Time.parse_utc("2025-02-07T17:00:00", "%Y-%m-%dT%H:%M:%S")
32+
SwiftScheduling.delivery_date(start, "EOW").should eq(expected)
33+
end
34+
35+
pending "EOW on Tuesday translates to Friday at five in the afternoon" do
36+
start = Time.parse_utc("1997-04-29T10:50:00", "%Y-%m-%dT%H:%M:%S")
37+
expected = Time.parse_utc("1997-05-02T17:00:00", "%Y-%m-%dT%H:%M:%S")
38+
SwiftScheduling.delivery_date(start, "EOW").should eq(expected)
39+
end
40+
41+
pending "EOW on Wednesday translates to Friday at five in the afternoon" do
42+
start = Time.parse_utc("2005-09-14T11:00:00", "%Y-%m-%dT%H:%M:%S")
43+
expected = Time.parse_utc("2005-09-16T17:00:00", "%Y-%m-%dT%H:%M:%S")
44+
SwiftScheduling.delivery_date(start, "EOW").should eq(expected)
45+
end
46+
47+
pending "EOW on Thursday translates to Sunday at eight in the evening" do
48+
start = Time.parse_utc("2011-05-19T08:30:00", "%Y-%m-%dT%H:%M:%S")
49+
expected = Time.parse_utc("2011-05-22T20:00:00", "%Y-%m-%dT%H:%M:%S")
50+
SwiftScheduling.delivery_date(start, "EOW").should eq(expected)
51+
end
52+
53+
pending "EOW on Friday translates to Sunday at eight in the evening" do
54+
start = Time.parse_utc("2022-08-05T14:00:00", "%Y-%m-%dT%H:%M:%S")
55+
expected = Time.parse_utc("2022-08-07T20:00:00", "%Y-%m-%dT%H:%M:%S")
56+
SwiftScheduling.delivery_date(start, "EOW").should eq(expected)
57+
end
58+
59+
pending "EOW translates to leap day" do
60+
start = Time.parse_utc("2008-02-25T10:30:00", "%Y-%m-%dT%H:%M:%S")
61+
expected = Time.parse_utc("2008-02-29T17:00:00", "%Y-%m-%dT%H:%M:%S")
62+
SwiftScheduling.delivery_date(start, "EOW").should eq(expected)
63+
end
64+
65+
pending "2M before the second month of this year translates to the first workday of the second month of this year" do
66+
start = Time.parse_utc("2007-01-02T14:15:00", "%Y-%m-%dT%H:%M:%S")
67+
expected = Time.parse_utc("2007-02-01T08:00:00", "%Y-%m-%dT%H:%M:%S")
68+
SwiftScheduling.delivery_date(start, "2M").should eq(expected)
69+
end
70+
71+
pending "11M in the eleventh month translates to the first workday of the eleventh month of next year" do
72+
start = Time.parse_utc("2013-11-21T15:30:00", "%Y-%m-%dT%H:%M:%S")
73+
expected = Time.parse_utc("2014-11-03T08:00:00", "%Y-%m-%dT%H:%M:%S")
74+
SwiftScheduling.delivery_date(start, "11M").should eq(expected)
75+
end
76+
77+
pending "4M in the ninth month translates to the first workday of the fourth month of next year" do
78+
start = Time.parse_utc("2019-11-18T15:15:00", "%Y-%m-%dT%H:%M:%S")
79+
expected = Time.parse_utc("2020-04-01T08:00:00", "%Y-%m-%dT%H:%M:%S")
80+
SwiftScheduling.delivery_date(start, "4M").should eq(expected)
81+
end
82+
83+
pending "Q1 in the first quarter translates to the last workday of the first quarter of this year" do
84+
start = Time.parse_utc("2003-01-01T10:45:00", "%Y-%m-%dT%H:%M:%S")
85+
expected = Time.parse_utc("2003-03-31T08:00:00", "%Y-%m-%dT%H:%M:%S")
86+
SwiftScheduling.delivery_date(start, "Q1").should eq(expected)
87+
end
88+
89+
pending "Q4 in the second quarter translates to the last workday of the fourth quarter of this year" do
90+
start = Time.parse_utc("2001-04-09T09:00:00", "%Y-%m-%dT%H:%M:%S")
91+
expected = Time.parse_utc("2001-12-31T08:00:00", "%Y-%m-%dT%H:%M:%S")
92+
SwiftScheduling.delivery_date(start, "Q4").should eq(expected)
93+
end
94+
95+
pending "Q3 in the fourth quarter translates to the last workday of the third quarter of next year" do
96+
start = Time.parse_utc("2022-10-06T11:00:00", "%Y-%m-%dT%H:%M:%S")
97+
expected = Time.parse_utc("2023-09-29T08:00:00", "%Y-%m-%dT%H:%M:%S")
98+
SwiftScheduling.delivery_date(start, "Q3").should eq(expected)
99+
end
100+
end
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module SwiftScheduling
2+
def self.delivery_date(meeting_start : Time, description : String) : Time
3+
# Write your code for the 'Swift Scheduling' exercise in this file.
4+
end
5+
end

0 commit comments

Comments
 (0)