Skip to content

Commit 56a0ef9

Browse files
authored
[New practice exercise] Swift Scheduling (#498)
* [New practice exercise] Swift Scheduling * sorted config.json
1 parent 510dab0 commit 56a0ef9

9 files changed

Lines changed: 324 additions & 0 deletions

File tree

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,14 @@
972972
"prerequisites": [],
973973
"difficulty": 4
974974
},
975+
{
976+
"slug": "swift-scheduling",
977+
"name": "Swift Scheduling",
978+
"uuid": "c264736e-eb63-431a-8a0b-bdbf26ec75d0",
979+
"practices": [],
980+
"prerequisites": [],
981+
"difficulty": 4
982+
},
975983
{
976984
"slug": "flower-field",
977985
"name": "Flower Field",
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+
"colinleach"
4+
],
5+
"files": {
6+
"solution": [
7+
"swift-scheduling.R"
8+
],
9+
"test": [
10+
"test_swift-scheduling.R"
11+
],
12+
"example": [
13+
".meta/example.R"
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: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
library(lubridate)
2+
library(stringr)
3+
4+
delivery_date <- function(start, description) {
5+
start_dt <- ymd_hms(start)
6+
start_day <- as_date(start_dt)
7+
# we want Monday = 1, wday() returns Sunday = 1 by default
8+
day_of_week <- wday(start_dt, week_start = 1)
9+
10+
if (description == "NOW") {
11+
result <- start_dt + hours(2L)
12+
} else if (description == "ASAP") {
13+
result <- ifelse(start_dt < (start_day + hours(13L)),
14+
start_day + hours(17L),
15+
start_day + days(1) + hours(13L)
16+
)
17+
} else if (description == "EOW") {
18+
result <- ifelse(day_of_week <= 3L,
19+
start_day + days(5 - day_of_week) + hours(17L),
20+
start_day + days(7 - day_of_week) + hours(20L)
21+
)
22+
} else if (str_sub(description, -1) == "M") {
23+
m <- description |>
24+
str_sub(1, -2) |>
25+
as.integer()
26+
y <- ifelse(month(start_dt) >= m, year(start_dt) + 1, year(start_dt))
27+
target <- make_datetime(y, m, 1, 8)
28+
target_wday <- wday(target, week_start = 1)
29+
result <- ifelse(target_wday <= 5, target, target + days(8 - target_wday))
30+
} else if (str_sub(description, 1, 1) == "Q") {
31+
q <- description |>
32+
str_sub(2, -1) |>
33+
as.integer()
34+
current_q <- quarter(start_dt)
35+
m <- (3 * q + 1) %% 12
36+
rollover <- ifelse(current_q > q || q == 4, 1, 0)
37+
38+
due <- make_datetime(year(start_dt) + rollover, m, 1, 8) - days(1L)
39+
due_wday <- wday(due, week_start = 1)
40+
result <- ifelse(due_wday <= 5, due, due - days(due_wday - 5))
41+
} else {
42+
stop("Invalid input")
43+
}
44+
45+
result |>
46+
as_datetime() |>
47+
format_ISO8601()
48+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{%- import "generator_macros.j2" as macros with context -%}
2+
{{ macros.canonical_ref() }}
3+
4+
{{ macros.header() }}
5+
6+
{% for case in cases -%}
7+
test_that("{{ case["description"] }}",{
8+
start <- "{{ case["input"]["meetingStart"] }}"
9+
description <- "{{ case["input"]["description"] }}"
10+
expected <- "{{ case["expected"] }}"
11+
expect_equal({{ case["property"] | to_snake }}(start, description), expected)
12+
})
13+
14+
{% endfor %}
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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
delivery_date <- function(start, description) {
2+
3+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# These tests are auto-generated with test data from:
2+
# https://github.com/exercism/problem-specifications/tree/main/exercises/swift-scheduling/canonical-data.json
3+
# File last updated on 2026-04-20
4+
5+
source("./swift-scheduling.R")
6+
library(testthat)
7+
8+
test_that("NOW translates to two hours later", {
9+
start <- "2012-02-13T09:00:00"
10+
description <- "NOW"
11+
expected <- "2012-02-13T11:00:00"
12+
expect_equal(delivery_date(start, description), expected)
13+
})
14+
15+
test_that("ASAP before one in the afternoon translates to today at five in the afternoon", {
16+
start <- "1999-06-03T09:45:00"
17+
description <- "ASAP"
18+
expected <- "1999-06-03T17:00:00"
19+
expect_equal(delivery_date(start, description), expected)
20+
})
21+
22+
test_that("ASAP at one in the afternoon translates to tomorrow at one in the afternoon", {
23+
start <- "2008-12-21T13:00:00"
24+
description <- "ASAP"
25+
expected <- "2008-12-22T13:00:00"
26+
expect_equal(delivery_date(start, description), expected)
27+
})
28+
29+
test_that("ASAP after one in the afternoon translates to tomorrow at one in the afternoon", {
30+
start <- "2008-12-21T14:50:00"
31+
description <- "ASAP"
32+
expected <- "2008-12-22T13:00:00"
33+
expect_equal(delivery_date(start, description), expected)
34+
})
35+
36+
test_that("EOW on Monday translates to Friday at five in the afternoon", {
37+
start <- "2025-02-03T16:00:00"
38+
description <- "EOW"
39+
expected <- "2025-02-07T17:00:00"
40+
expect_equal(delivery_date(start, description), expected)
41+
})
42+
43+
test_that("EOW on Tuesday translates to Friday at five in the afternoon", {
44+
start <- "1997-04-29T10:50:00"
45+
description <- "EOW"
46+
expected <- "1997-05-02T17:00:00"
47+
expect_equal(delivery_date(start, description), expected)
48+
})
49+
50+
test_that("EOW on Wednesday translates to Friday at five in the afternoon", {
51+
start <- "2005-09-14T11:00:00"
52+
description <- "EOW"
53+
expected <- "2005-09-16T17:00:00"
54+
expect_equal(delivery_date(start, description), expected)
55+
})
56+
57+
test_that("EOW on Thursday translates to Sunday at eight in the evening", {
58+
start <- "2011-05-19T08:30:00"
59+
description <- "EOW"
60+
expected <- "2011-05-22T20:00:00"
61+
expect_equal(delivery_date(start, description), expected)
62+
})
63+
64+
test_that("EOW on Friday translates to Sunday at eight in the evening", {
65+
start <- "2022-08-05T14:00:00"
66+
description <- "EOW"
67+
expected <- "2022-08-07T20:00:00"
68+
expect_equal(delivery_date(start, description), expected)
69+
})
70+
71+
test_that("EOW translates to leap day", {
72+
start <- "2008-02-25T10:30:00"
73+
description <- "EOW"
74+
expected <- "2008-02-29T17:00:00"
75+
expect_equal(delivery_date(start, description), expected)
76+
})
77+
78+
test_that("2M before the second month of this year translates to the first workday of the second month of this year", {
79+
start <- "2007-01-02T14:15:00"
80+
description <- "2M"
81+
expected <- "2007-02-01T08:00:00"
82+
expect_equal(delivery_date(start, description), expected)
83+
})
84+
85+
test_that("11M in the eleventh month translates to the first workday of the eleventh month of next year", {
86+
start <- "2013-11-21T15:30:00"
87+
description <- "11M"
88+
expected <- "2014-11-03T08:00:00"
89+
expect_equal(delivery_date(start, description), expected)
90+
})
91+
92+
test_that("4M in the ninth month translates to the first workday of the fourth month of next year", {
93+
start <- "2019-11-18T15:15:00"
94+
description <- "4M"
95+
expected <- "2020-04-01T08:00:00"
96+
expect_equal(delivery_date(start, description), expected)
97+
})
98+
99+
test_that("Q1 in the first quarter translates to the last workday of the first quarter of this year", {
100+
start <- "2003-01-01T10:45:00"
101+
description <- "Q1"
102+
expected <- "2003-03-31T08:00:00"
103+
expect_equal(delivery_date(start, description), expected)
104+
})
105+
106+
test_that("Q4 in the second quarter translates to the last workday of the fourth quarter of this year", {
107+
start <- "2001-04-09T09:00:00"
108+
description <- "Q4"
109+
expected <- "2001-12-31T08:00:00"
110+
expect_equal(delivery_date(start, description), expected)
111+
})
112+
113+
test_that("Q3 in the fourth quarter translates to the last workday of the third quarter of next year", {
114+
start <- "2022-10-06T11:00:00"
115+
description <- "Q3"
116+
expected <- "2023-09-29T08:00:00"
117+
expect_equal(delivery_date(start, description), expected)
118+
})

0 commit comments

Comments
 (0)