From 709a441ba663b43a3c1bcd991560ed7d13ae1d30 Mon Sep 17 00:00:00 2001 From: BadIdeaException <7235795+BadIdeaException@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:26:42 +0200 Subject: [PATCH 1/8] fix: correct implementation of `createAppointment` Makes the suggested implementation of `createAppointment` correctly handle appointment creations that cross timezones - e.g. due to Daylight Savings Time. re: https://forum.exercism.org/t/tests-and-suggested-implementation-for-appointment-time-are-wrong/ --- exercises/concept/appointment-time/.meta/exemplar.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/exercises/concept/appointment-time/.meta/exemplar.js b/exercises/concept/appointment-time/.meta/exemplar.js index ae0b84fca7..55192ff6f4 100644 --- a/exercises/concept/appointment-time/.meta/exemplar.js +++ b/exercises/concept/appointment-time/.meta/exemplar.js @@ -9,7 +9,10 @@ * @returns {Date} the appointment */ export function createAppointment(days, now = Date.now()) { - return new Date(now + days * 24 * 3600 * 1000); + const date = new Date(now); + date.setDate(date.getDate() + days); + + return date; } /** @@ -73,7 +76,7 @@ export function updateAppointment(timestamp, options) { export function timeBetween(timestampA, timestampB) { return Math.round( (new Date(timestampB).getTime() - new Date(timestampA).getTime()) / 1000, - ); + ); } /** From 186c05a549c93d603225a3f867d5694d4f5d649d Mon Sep 17 00:00:00 2001 From: BadIdeaException <7235795+BadIdeaException@users.noreply.github.com> Date: Wed, 24 Sep 2025 10:31:22 +0200 Subject: [PATCH 2/8] fix: correct tests for `createAppointment` Corrects the test so that they respect locales with Daylight Savings Time. Previously, tests and suggested implementation simply did simple time arithmetic based on the offset provided to `createAppointment`. This is wrong, as it will shift appointment time-of-day when moving accross DST boundaries. This changes test implementation so that: 1. correct usage of input times is checked, by passing a 0 offset 2. correct offsetting of appointment time is checked, by passing in a known start date and then creating one appointment that is within the same DST state and one that is not. re: https://forum.exercism.org/t/tests-and-suggested-implementation-for-appointment-time-are-wrong/ --- .../appointment-time/appointment-time.spec.js | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/exercises/concept/appointment-time/appointment-time.spec.js b/exercises/concept/appointment-time/appointment-time.spec.js index 689e2075c5..ec9e4359a0 100644 --- a/exercises/concept/appointment-time/appointment-time.spec.js +++ b/exercises/concept/appointment-time/appointment-time.spec.js @@ -10,34 +10,38 @@ import { } from './appointment-time'; describe('createAppointment', () => { - test('creates appointment 4 days in the future', () => { - const currentTime = Date.now(); - const expectedTime = currentTime + 345600 * 1000; + test('uses the passed in current time', () => { + const currentTime = Date.UTC(2000, 6, 16, 12, 0, 0, 0); + const result = createAppointment(0, currentTime); - expect(createAppointment(4, currentTime)).toEqual(new Date(expectedTime)); + expect(result).toEqual(new Date(currentTime)); }); - test('creates appointment 124 in the future', () => { + test('uses the actual current time when it is not passed in', () => { const currentTime = Date.now(); - const expectedTime = currentTime + 10713600 * 1000; + const result = createAppointment(0); - expect(createAppointment(124, currentTime)).toEqual(new Date(expectedTime)); + expect(result).toEqual(new Date(currentTime)); }); - test('uses the passed in current time', () => { - const currentTime = Date.UTC(2000, 6, 16, 12, 0, 0, 0); - const result = createAppointment(0, currentTime); + test('creates appointment without DST change', () => { + const offset = 4; // days - expect(result.getFullYear()).toEqual(2000); + const currentTime = Date.UTC(2000, 6, 1, 12, 0, 0, 0); + const expectedTime = currentTime + offset * 24 * 60 * 60 * 1000; + + expect(createAppointment(offset, currentTime)).toEqual(new Date(expectedTime)); }); - test('uses the actual current time when it is not passed in', () => { - const result = createAppointment(0); + test('creates appointment with potential DST change', () => { + const offset = 180; // days - expect(Math.abs(Date.now() - result.getTime())).toBeLessThanOrEqual( - // Maximum number of time zones difference - 27 * 60 * 60 * 1000, - ); + const currentTime = Date.UTC(2000, 6, 1, 12, 0, 0, 0); + let expectedTime = currentTime + offset * 24 * 60 * 60 * 1000; + // Manually adjust for DST timezone offset: + expectedTime += (new Date(expectedTime).getTimezoneOffset() - new Date(currentTime).getTimezoneOffset()) * 60 * 1000; + + expect(createAppointment(offset, currentTime)).toEqual(new Date(expectedTime)); }); test('rolls over days, months, and years', () => { From cc0c9faee5ca1c789365dd1e95b741987b8a97de Mon Sep 17 00:00:00 2001 From: BadIdeaException <7235795+BadIdeaException@users.noreply.github.com> Date: Thu, 25 Sep 2025 09:24:41 +0200 Subject: [PATCH 3/8] docs: update hints --- exercises/concept/appointment-time/.docs/hints.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exercises/concept/appointment-time/.docs/hints.md b/exercises/concept/appointment-time/.docs/hints.md index 805e162bdd..a77deb6ccc 100644 --- a/exercises/concept/appointment-time/.docs/hints.md +++ b/exercises/concept/appointment-time/.docs/hints.md @@ -4,7 +4,8 @@ - You need to create a new date. The introduction elaborates on the different ways. - `Date.now()` gives you current time in milliseconds -- A day consist of 24 hour. An hour consist of 60 minutes. A minute consist of 60 seconds. A second consist of 1000 milliseconds. In order to get timestamp of `n` days later from current date, you can sum current timestamp and `n * 24 * 60 * 60 * 1000`. +- `Date` has several getter methods to get date components - months, hours, etc. - for a given date. `getMinutes`, for instance, returns the minutes component. +- Likewise, `Date` has several setter methods to set those components, rolling over into "higher" components if needed. `setMinutes(80)`, for example, will increase the hours component by one and set the minutes component to 20. ## 2. Convert a date into a timestamp From 527e290b39f162fc2eadda071d62cc7dfd09e2fd Mon Sep 17 00:00:00 2001 From: BadIdeaException <7235795+BadIdeaException@users.noreply.github.com> Date: Thu, 25 Sep 2025 09:24:59 +0200 Subject: [PATCH 4/8] chore: update contributors --- exercises/concept/appointment-time/.meta/config.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/exercises/concept/appointment-time/.meta/config.json b/exercises/concept/appointment-time/.meta/config.json index 4488a8e345..649f219e32 100644 --- a/exercises/concept/appointment-time/.meta/config.json +++ b/exercises/concept/appointment-time/.meta/config.json @@ -3,6 +3,9 @@ "SalahuddinAhammed", "SleeplessByte" ], + "contributors": [ + "BadIdeaException" + ], "files": { "solution": [ "appointment-time.js" From 0770f145eb22f6a4f23d37498bc14adab6364046 Mon Sep 17 00:00:00 2001 From: BadIdeaException <7235795+BadIdeaException@users.noreply.github.com> Date: Thu, 25 Sep 2025 14:47:28 +0200 Subject: [PATCH 5/8] style: prettier --- .../concept/appointment-time/.docs/hints.md | 2 +- .../concept/appointment-time/.meta/exemplar.js | 2 +- .../appointment-time/appointment-time.spec.js | 16 ++++++++++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/exercises/concept/appointment-time/.docs/hints.md b/exercises/concept/appointment-time/.docs/hints.md index a77deb6ccc..50d7e03432 100644 --- a/exercises/concept/appointment-time/.docs/hints.md +++ b/exercises/concept/appointment-time/.docs/hints.md @@ -4,7 +4,7 @@ - You need to create a new date. The introduction elaborates on the different ways. - `Date.now()` gives you current time in milliseconds -- `Date` has several getter methods to get date components - months, hours, etc. - for a given date. `getMinutes`, for instance, returns the minutes component. +- `Date` has several getter methods to get date components - months, hours, etc. - for a given date. `getMinutes`, for instance, returns the minutes component. - Likewise, `Date` has several setter methods to set those components, rolling over into "higher" components if needed. `setMinutes(80)`, for example, will increase the hours component by one and set the minutes component to 20. ## 2. Convert a date into a timestamp diff --git a/exercises/concept/appointment-time/.meta/exemplar.js b/exercises/concept/appointment-time/.meta/exemplar.js index 55192ff6f4..ff47aad2fc 100644 --- a/exercises/concept/appointment-time/.meta/exemplar.js +++ b/exercises/concept/appointment-time/.meta/exemplar.js @@ -76,7 +76,7 @@ export function updateAppointment(timestamp, options) { export function timeBetween(timestampA, timestampB) { return Math.round( (new Date(timestampB).getTime() - new Date(timestampA).getTime()) / 1000, - ); + ); } /** diff --git a/exercises/concept/appointment-time/appointment-time.spec.js b/exercises/concept/appointment-time/appointment-time.spec.js index ec9e4359a0..d0872cc2b3 100644 --- a/exercises/concept/appointment-time/appointment-time.spec.js +++ b/exercises/concept/appointment-time/appointment-time.spec.js @@ -30,7 +30,9 @@ describe('createAppointment', () => { const currentTime = Date.UTC(2000, 6, 1, 12, 0, 0, 0); const expectedTime = currentTime + offset * 24 * 60 * 60 * 1000; - expect(createAppointment(offset, currentTime)).toEqual(new Date(expectedTime)); + expect(createAppointment(offset, currentTime)).toEqual( + new Date(expectedTime), + ); }); test('creates appointment with potential DST change', () => { @@ -39,9 +41,15 @@ describe('createAppointment', () => { const currentTime = Date.UTC(2000, 6, 1, 12, 0, 0, 0); let expectedTime = currentTime + offset * 24 * 60 * 60 * 1000; // Manually adjust for DST timezone offset: - expectedTime += (new Date(expectedTime).getTimezoneOffset() - new Date(currentTime).getTimezoneOffset()) * 60 * 1000; - - expect(createAppointment(offset, currentTime)).toEqual(new Date(expectedTime)); + expectedTime += + (new Date(expectedTime).getTimezoneOffset() - + new Date(currentTime).getTimezoneOffset()) * + 60 * + 1000; + + expect(createAppointment(offset, currentTime)).toEqual( + new Date(expectedTime), + ); }); test('rolls over days, months, and years', () => { From 5a06cf9cfa145ed5df6d463d1bfa04b27699ee43 Mon Sep 17 00:00:00 2001 From: BadIdeaException <7235795+BadIdeaException@users.noreply.github.com> Date: Sun, 28 Sep 2025 20:21:22 +0200 Subject: [PATCH 6/8] docs: refer to instructions for going about getter method Co-authored-by: Cool-Katt --- exercises/concept/appointment-time/.docs/hints.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/appointment-time/.docs/hints.md b/exercises/concept/appointment-time/.docs/hints.md index 50d7e03432..ec694f785c 100644 --- a/exercises/concept/appointment-time/.docs/hints.md +++ b/exercises/concept/appointment-time/.docs/hints.md @@ -4,7 +4,7 @@ - You need to create a new date. The introduction elaborates on the different ways. - `Date.now()` gives you current time in milliseconds -- `Date` has several getter methods to get date components - months, hours, etc. - for a given date. `getMinutes`, for instance, returns the minutes component. +- `Date` has several getter methods, listed in the introduction, to get date components. Can you use one of those methods? - Likewise, `Date` has several setter methods to set those components, rolling over into "higher" components if needed. `setMinutes(80)`, for example, will increase the hours component by one and set the minutes component to 20. ## 2. Convert a date into a timestamp From ab2c41679e246e5e92702c8f59ea95a40d147837 Mon Sep 17 00:00:00 2001 From: BadIdeaException <7235795+BadIdeaException@users.noreply.github.com> Date: Sun, 28 Sep 2025 20:22:21 +0200 Subject: [PATCH 7/8] docs: more concise hint about setters Co-authored-by: Cool-Katt --- exercises/concept/appointment-time/.docs/hints.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/appointment-time/.docs/hints.md b/exercises/concept/appointment-time/.docs/hints.md index ec694f785c..12b3279d28 100644 --- a/exercises/concept/appointment-time/.docs/hints.md +++ b/exercises/concept/appointment-time/.docs/hints.md @@ -5,7 +5,7 @@ - You need to create a new date. The introduction elaborates on the different ways. - `Date.now()` gives you current time in milliseconds - `Date` has several getter methods, listed in the introduction, to get date components. Can you use one of those methods? -- Likewise, `Date` has several setter methods to set those components, rolling over into "higher" components if needed. `setMinutes(80)`, for example, will increase the hours component by one and set the minutes component to 20. +- Likewise, `Date` has matching setter methods to set those components, rolling over into "higher" components if needed. ## 2. Convert a date into a timestamp From 027a8c0620a76116ac53375d45fc3a8dba194884 Mon Sep 17 00:00:00 2001 From: Derk-Jan Karrenbeld Date: Mon, 29 Sep 2025 22:26:54 +0200 Subject: [PATCH 8/8] Format all the things --- .prettierignore | 8 +++++--- exercises/concept/appointment-time/.docs/hints.md | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.prettierignore b/.prettierignore index 1306859a0c..0187784ddc 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,7 +1,9 @@ /.github/labels.yml -/.github/workflows/sync-labels.yml -/.github/workflows/no-important-files-changed.yml + +# Generated exercises/**/README.md +pnpm-lock.yaml + !/README.md # Originates from https://github.com/exercism/org-wide-files @@ -19,4 +21,4 @@ config.json # Originates from https://github.com/exercism/problem-specifications exercises/practice/**/.docs/instructions.md -exercises/practice/**/.docs/introduction.md +exercises/practice/**/.docs/introduction.md \ No newline at end of file diff --git a/exercises/concept/appointment-time/.docs/hints.md b/exercises/concept/appointment-time/.docs/hints.md index 12b3279d28..f089f650fb 100644 --- a/exercises/concept/appointment-time/.docs/hints.md +++ b/exercises/concept/appointment-time/.docs/hints.md @@ -4,8 +4,8 @@ - You need to create a new date. The introduction elaborates on the different ways. - `Date.now()` gives you current time in milliseconds -- `Date` has several getter methods, listed in the introduction, to get date components. Can you use one of those methods? -- Likewise, `Date` has matching setter methods to set those components, rolling over into "higher" components if needed. +- `Date` has several getter methods, listed in the introduction, to get date components. Can you use one of those methods? +- Likewise, `Date` has matching setter methods to set those components, rolling over into "higher" components if needed. ## 2. Convert a date into a timestamp