From 11890c8b3fb0b7f5e9a77b22da9a80b2a8dbc40f Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 12:14:37 +0300 Subject: [PATCH 01/13] Add Temporal Adjusters concept with documentation and config Introduces the `Temporal Adjusters` concept, including an overview, examples, and links for Java's `TemporalAdjuster` and `TemporalAdjusters` utilities. Updates `config.json` to include the concept and a new exercise, "Meetup," with relevant prerequisites. --- concepts/temporal-adjusters/.meta/config.json | 5 + concepts/temporal-adjusters/about.md | 140 ++++++++++++++++++ concepts/temporal-adjusters/introduction.md | 140 ++++++++++++++++++ concepts/temporal-adjusters/links.json | 18 +++ config.json | 17 +++ 5 files changed, 320 insertions(+) create mode 100644 concepts/temporal-adjusters/.meta/config.json create mode 100644 concepts/temporal-adjusters/about.md create mode 100644 concepts/temporal-adjusters/introduction.md create mode 100644 concepts/temporal-adjusters/links.json diff --git a/concepts/temporal-adjusters/.meta/config.json b/concepts/temporal-adjusters/.meta/config.json new file mode 100644 index 000000000..0c2bc3cab --- /dev/null +++ b/concepts/temporal-adjusters/.meta/config.json @@ -0,0 +1,5 @@ +{ + "blurb": "Perform common and complex date adjustments using Java's `TemporalAdjuster` interface and `TemporalAdjusters` utility class.", + "authors": ["rabestro"], + "contributors": [] +} diff --git a/concepts/temporal-adjusters/about.md b/concepts/temporal-adjusters/about.md new file mode 100644 index 000000000..be786485a --- /dev/null +++ b/concepts/temporal-adjusters/about.md @@ -0,0 +1,140 @@ +# About + +While the core `java.time` classes like `LocalDate` and `LocalDateTime` provide basic methods for adding or subtracting time units, more complex date adjustments often require more sophisticated logic (e.g., finding the "second Tuesday of the month" or the "last day of the year"). + +The `java.time.temporal` package provides the [`TemporalAdjuster`][temporaladjuster-docs] functional interface for this purpose. It represents a strategy for adjusting a temporal object (like a `LocalDate`). The [`TemporalAdjusters`][temporaladjusters-docs] (note the plural 's') utility class contains static factory methods providing many common, predefined adjuster implementations. + +## Using TemporalAdjusters + +Temporal objects like `LocalDate` and `LocalDateTime` have a `with()` method that accepts a `TemporalAdjuster`. This method returns a *new* temporal object with the adjustment applied. + +```exercism/note +Using `with(TemporalAdjuster)` returns a _new_ instance and does not update the existing instance, as all `java.time` temporal classes are immutable. +``` + +```java +import java.time.LocalDate; +import java.time.Month; +import java.time.DayOfWeek; +import java.time.temporal.TemporalAdjusters; + +LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 (a Thursday) + +// Use a predefined adjuster from TemporalAdjusters +LocalDate firstDayOfNextMonth = date.with(TemporalAdjusters.firstDayOfNextMonth()); +// => 2024-09-01 + +LocalDate nextSunday = date.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)); +// => 2024-08-18 +``` + +## Common Predefined Adjusters + +The `TemporalAdjusters` class provides many useful static methods. Here are some common examples: + +### Finding Ordinal Day of Week + +The `dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)` adjuster finds the nth occurrence of a specific day of the week within the month. + +```java +LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 + +// Find the second Tuesday of August 2024 +LocalDate secondTuesday = date.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.TUESDAY)); +// => 2024-08-13 + +// Find the fourth Friday of August 2024 +LocalDate fourthFriday = date.with(TemporalAdjusters.dayOfWeekInMonth(4, DayOfWeek.FRIDAY)); +// => 2024-08-23 +``` + +### Finding First/Last Day of Week in Month + +The `firstInMonth(DayOfWeek dayOfWeek)` and `lastInMonth(DayOfWeek dayOfWeek)` adjusters find the first or last occurrence of a day of the week within the month. + +```java +LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 + +// Find the first Sunday of August 2024 +LocalDate firstSunday = date.with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY)); +// => 2024-08-04 + +// Find the last Monday of August 2024 +LocalDate lastMonday = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY)); +// => 2024-08-26 +``` + +### Finding First/Last Day of Month/Year + +Simpler adjusters find the first or last day of the current month or year. + +```java +LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 + +LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth()); +// => 2024-08-01 + +LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth()); +// => 2024-08-31 + +LocalDate lastDayOfYear = date.with(TemporalAdjusters.lastDayOfYear()); +// => 2024-12-31 +``` + +### Relative Adjustments (Next/Previous) + +Adjusters like `next()`, `previous()`, `nextOrSame()`, and `previousOrSame()` find the next or previous occurrence of a given day of the week, relative to the current date. + +* `next()`/`previous()`: Excludes the current date if it matches. +* `nextOrSame()`/`previousOrSame()`: Includes the current date if it matches. + +```java +LocalDate thursday = LocalDate.of(2024, Month.AUGUST, 15); // A Thursday + +// Find the next Sunday (exclusive) +LocalDate nextSunday = thursday.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)); +// => 2024-08-18 + +// Find the next Thursday (exclusive) +LocalDate nextThursday = thursday.with(TemporalAdjusters.next(DayOfWeek.THURSDAY)); +// => 2024-08-22 + +// Find the next Thursday (inclusive) - returns the same date +LocalDate nextOrSameThursday = thursday.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY)); +// => 2024-08-15 + +// Find the previous Monday (exclusive) +LocalDate previousMonday = thursday.with(TemporalAdjusters.previous(DayOfWeek.MONDAY)); +// => 2024-08-12 +``` +The `nextOrSame()` adjuster is particularly useful for finding dates in ranges like the "teenth" days (13th-19th) of a month, as seen in the Meetup exercise. Applying `nextOrSame(targetDayOfWeek)` to the 13th day of the month will find the correct "teenth" date. + +## Custom Adjusters + +Since `TemporalAdjuster` is a [`@FunctionalInterface`][functionalinterface-docs], you can create your own custom adjusters using lambda expressions for logic not covered by the predefined methods. The interface requires implementing a single method: `Temporal adjustInto(Temporal temporal)`. + +```java +// Example: An adjuster that finds the next workday (Mon-Fri), skipping weekends. +TemporalAdjuster nextWorkday = temporal -> { + LocalDate result = (LocalDate) temporal; // Assuming input is LocalDate + do { + result = result.plusDays(1); + } while (result.getDayOfWeek() == DayOfWeek.SATURDAY || result.getDayOfWeek() == DayOfWeek.SUNDAY); + return result; +}; + +LocalDate friday = LocalDate.of(2024, Month.AUGUST, 16); +LocalDate nextWorkdayDate = friday.with(nextWorkday); +// => 2024-08-19 (Monday) + +LocalDate sunday = LocalDate.of(2024, Month.AUGUST, 18); +LocalDate nextWorkdayFromSunday = sunday.with(nextWorkday); +// => 2024-08-19 (Monday) +``` +While custom adjusters are powerful, the predefined adjusters in the `TemporalAdjusters` class cover a wide range of common use cases. + +[temporaladjuster-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjuster.html +[temporaladjusters-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjusters.html +[localdate-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html +[dayofweek-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html +[functionalinterface-docs]: https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html diff --git a/concepts/temporal-adjusters/introduction.md b/concepts/temporal-adjusters/introduction.md new file mode 100644 index 000000000..afefbd651 --- /dev/null +++ b/concepts/temporal-adjusters/introduction.md @@ -0,0 +1,140 @@ +# Introduction + +While the core `java.time` classes like `LocalDate` and `LocalDateTime` provide basic methods for adding or subtracting time units, more complex date adjustments often require more sophisticated logic (e.g., finding the "second Tuesday of the month" or the "last day of the year"). + +The `java.time.temporal` package provides the [`TemporalAdjuster`][temporaladjuster-docs] functional interface for this purpose. It represents a strategy for adjusting a temporal object (like a `LocalDate`). The [`TemporalAdjusters`][temporaladjusters-docs] (note the plural 's') utility class contains static factory methods providing many common, predefined adjuster implementations. + +## Using TemporalAdjusters + +Temporal objects like `LocalDate` and `LocalDateTime` have a `with()` method that accepts a `TemporalAdjuster`. This method returns a *new* temporal object with the adjustment applied. + +```exercism/note +Using `with(TemporalAdjuster)` returns a _new_ instance and does not update the existing instance, as all `java.time` temporal classes are immutable. +``` + +```java +import java.time.LocalDate; +import java.time.Month; +import java.time.DayOfWeek; +import java.time.temporal.TemporalAdjusters; + +LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 (a Thursday) + +// Use a predefined adjuster from TemporalAdjusters +LocalDate firstDayOfNextMonth = date.with(TemporalAdjusters.firstDayOfNextMonth()); +// => 2024-09-01 + +LocalDate nextSunday = date.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)); +// => 2024-08-18 +``` + +## Common Predefined Adjusters + +The `TemporalAdjusters` class provides many useful static methods. Here are some common examples: + +### Finding Ordinal Day of Week + +The `dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)` adjuster finds the nth occurrence of a specific day of the week within the month. + +```java +LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 + +// Find the second Tuesday of August 2024 +LocalDate secondTuesday = date.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.TUESDAY)); +// => 2024-08-13 + +// Find the fourth Friday of August 2024 +LocalDate fourthFriday = date.with(TemporalAdjusters.dayOfWeekInMonth(4, DayOfWeek.FRIDAY)); +// => 2024-08-23 +``` + +### Finding First/Last Day of Week in Month + +The `firstInMonth(DayOfWeek dayOfWeek)` and `lastInMonth(DayOfWeek dayOfWeek)` adjusters find the first or last occurrence of a day of the week within the month. + +```java +LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 + +// Find the first Sunday of August 2024 +LocalDate firstSunday = date.with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY)); +// => 2024-08-04 + +// Find the last Monday of August 2024 +LocalDate lastMonday = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY)); +// => 2024-08-26 +``` + +### Finding First/Last Day of Month/Year + +Simpler adjusters find the first or last day of the current month or year. + +```java +LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 + +LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth()); +// => 2024-08-01 + +LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth()); +// => 2024-08-31 + +LocalDate lastDayOfYear = date.with(TemporalAdjusters.lastDayOfYear()); +// => 2024-12-31 +``` + +### Relative Adjustments (Next/Previous) + +Adjusters like `next()`, `previous()`, `nextOrSame()`, and `previousOrSame()` find the next or previous occurrence of a given day of the week, relative to the current date. + +* `next()`/`previous()`: Excludes the current date if it matches. +* `nextOrSame()`/`previousOrSame()`: Includes the current date if it matches. + +```java +LocalDate thursday = LocalDate.of(2024, Month.AUGUST, 15); // A Thursday + +// Find the next Sunday (exclusive) +LocalDate nextSunday = thursday.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)); +// => 2024-08-18 + +// Find the next Thursday (exclusive) +LocalDate nextThursday = thursday.with(TemporalAdjusters.next(DayOfWeek.THURSDAY)); +// => 2024-08-22 + +// Find the next Thursday (inclusive) - returns the same date +LocalDate nextOrSameThursday = thursday.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY)); +// => 2024-08-15 + +// Find the previous Monday (exclusive) +LocalDate previousMonday = thursday.with(TemporalAdjusters.previous(DayOfWeek.MONDAY)); +// => 2024-08-12 +``` +The `nextOrSame()` adjuster is particularly useful for finding dates in ranges like the "teenth" days (13th-19th) of a month, as seen in the Meetup exercise. Applying `nextOrSame(targetDayOfWeek)` to the 13th day of the month will find the correct "teenth" date. + +## Custom Adjusters + +Since `TemporalAdjuster` is a [`@FunctionalInterface`][functionalinterface-docs], you can create your own custom adjusters using lambda expressions for logic not covered by the predefined methods. The interface requires implementing a single method: `Temporal adjustInto(Temporal temporal)`. + +```java +// Example: An adjuster that finds the next workday (Mon-Fri), skipping weekends. +TemporalAdjuster nextWorkday = temporal -> { + LocalDate result = (LocalDate) temporal; // Assuming input is LocalDate + do { + result = result.plusDays(1); + } while (result.getDayOfWeek() == DayOfWeek.SATURDAY || result.getDayOfWeek() == DayOfWeek.SUNDAY); + return result; +}; + +LocalDate friday = LocalDate.of(2024, Month.AUGUST, 16); +LocalDate nextWorkdayDate = friday.with(nextWorkday); +// => 2024-08-19 (Monday) + +LocalDate sunday = LocalDate.of(2024, Month.AUGUST, 18); +LocalDate nextWorkdayFromSunday = sunday.with(nextWorkday); +// => 2024-08-19 (Monday) +``` +While custom adjusters are powerful, the predefined adjusters in the `TemporalAdjusters` class cover a wide range of common use cases. + +[temporaladjuster-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjuster.html +[temporaladjusters-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjusters.html +[localdate-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html +[dayofweek-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html +[functionalinterface-docs]: https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html diff --git a/concepts/temporal-adjusters/links.json b/concepts/temporal-adjusters/links.json new file mode 100644 index 000000000..d2a0b0185 --- /dev/null +++ b/concepts/temporal-adjusters/links.json @@ -0,0 +1,18 @@ +[ + { + "url": "https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/temporal/TemporalAdjuster.html", + "description": "TemporalAdjuster interface documentation" + }, + { + "url": "https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/temporal/TemporalAdjusters.html", + "description": "TemporalAdjusters utility class documentation" + }, + { + "url": "https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/temporal/Temporal.html", + "description": "Temporal interface documentation" + }, + { + "url": "https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/DayOfWeek.html", + "description": "DayOfWeek enum documentation" + } +] diff --git a/config.json b/config.json index 7c8f6b933..ad71adad0 100644 --- a/config.json +++ b/config.json @@ -321,6 +321,18 @@ "foreach-loops", "generic-types" ] + }, + { + "slug": "meetup", + "name": "Meetup", + "uuid": "602511d5-7e89-4def-b072-4dd311816810", + "concepts": [ + "temporal-adjusters" + ], + "prerequisites": [ + "datetime", + "enums" + ] } ], "practice": [ @@ -1971,6 +1983,11 @@ "uuid": "78f3c7b2-cb9c-4d21-8cb4-7106a188f713", "slug": "ternary-operators", "name": "Ternary Operators" + }, + { + "uuid": "cc7a06d1-ddb3-4722-88a5-f762254d664e", + "slug": "temporal-adjusters", + "name": "Temporal Adjusters" } ], "key_features": [ From 5c6101e056f701bbf7e685d9c826496ef73670bf Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 12:21:59 +0300 Subject: [PATCH 02/13] Refactor and streamline TemporalAdjusters documentation Simplify the introduction and examples for `TemporalAdjusters` to improve clarity and focus on practical use cases. Removed redundant examples and reorganized sections to prioritize key adjusters like ordinal days and "teenth" date calculations. Enhanced consistency and readability across code snippets and explanations. --- concepts/temporal-adjusters/introduction.md | 116 ++++---------------- 1 file changed, 19 insertions(+), 97 deletions(-) diff --git a/concepts/temporal-adjusters/introduction.md b/concepts/temporal-adjusters/introduction.md index afefbd651..bd775babd 100644 --- a/concepts/temporal-adjusters/introduction.md +++ b/concepts/temporal-adjusters/introduction.md @@ -1,15 +1,11 @@ # Introduction -While the core `java.time` classes like `LocalDate` and `LocalDateTime` provide basic methods for adding or subtracting time units, more complex date adjustments often require more sophisticated logic (e.g., finding the "second Tuesday of the month" or the "last day of the year"). +When working with `java.time` objects like `LocalDate`, you often need to perform complex date adjustments, such as finding the "second Tuesday of the month". Instead of calculating this manually, you can use **`TemporalAdjusters`**. -The `java.time.temporal` package provides the [`TemporalAdjuster`][temporaladjuster-docs] functional interface for this purpose. It represents a strategy for adjusting a temporal object (like a `LocalDate`). The [`TemporalAdjusters`][temporaladjusters-docs] (note the plural 's') utility class contains static factory methods providing many common, predefined adjuster implementations. - -## Using TemporalAdjusters - -Temporal objects like `LocalDate` and `LocalDateTime` have a `with()` method that accepts a `TemporalAdjuster`. This method returns a *new* temporal object with the adjustment applied. +The `java.time.temporal.TemporalAdjusters` (note the plural 's') utility class provides static methods for many common date adjustments. You apply these adjustments using the `.with()` method on a temporal object (like `LocalDate`). ```exercism/note -Using `with(TemporalAdjuster)` returns a _new_ instance and does not update the existing instance, as all `java.time` temporal classes are immutable. +Using `with(TemporalAdjuster)` returns a _new_ instance and does not update the existing instance, as `java.time` objects are immutable. ``` ```java @@ -20,121 +16,47 @@ import java.time.temporal.TemporalAdjusters; LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 (a Thursday) -// Use a predefined adjuster from TemporalAdjusters -LocalDate firstDayOfNextMonth = date.with(TemporalAdjusters.firstDayOfNextMonth()); -// => 2024-09-01 - -LocalDate nextSunday = date.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)); -// => 2024-08-18 +// Use a predefined adjuster: find the last day of the month +LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth()); +// => 2024-08-31 ``` -## Common Predefined Adjusters - -The `TemporalAdjusters` class provides many useful static methods. Here are some common examples: +Here are some key adjusters useful for scheduling calculations: ### Finding Ordinal Day of Week -The `dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)` adjuster finds the nth occurrence of a specific day of the week within the month. +Use `dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)` to find the nth occurrence of a day of the week. ```java -LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 - // Find the second Tuesday of August 2024 LocalDate secondTuesday = date.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.TUESDAY)); // => 2024-08-13 - -// Find the fourth Friday of August 2024 -LocalDate fourthFriday = date.with(TemporalAdjusters.dayOfWeekInMonth(4, DayOfWeek.FRIDAY)); -// => 2024-08-23 ``` ### Finding First/Last Day of Week in Month -The `firstInMonth(DayOfWeek dayOfWeek)` and `lastInMonth(DayOfWeek dayOfWeek)` adjusters find the first or last occurrence of a day of the week within the month. +Use `firstInMonth(DayOfWeek dayOfWeek)` or `lastInMonth(DayOfWeek dayOfWeek)`. ```java -LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 - -// Find the first Sunday of August 2024 -LocalDate firstSunday = date.with(TemporalAdjusters.firstInMonth(DayOfWeek.SUNDAY)); -// => 2024-08-04 - // Find the last Monday of August 2024 LocalDate lastMonday = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY)); // => 2024-08-26 ``` -### Finding First/Last Day of Month/Year - -Simpler adjusters find the first or last day of the current month or year. - -```java -LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 - -LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth()); -// => 2024-08-01 - -LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth()); -// => 2024-08-31 - -LocalDate lastDayOfYear = date.with(TemporalAdjusters.lastDayOfYear()); -// => 2024-12-31 -``` - -### Relative Adjustments (Next/Previous) - -Adjusters like `next()`, `previous()`, `nextOrSame()`, and `previousOrSame()` find the next or previous occurrence of a given day of the week, relative to the current date. +### Finding Relative Occurrences ("Teenth" dates) -* `next()`/`previous()`: Excludes the current date if it matches. -* `nextOrSame()`/`previousOrSame()`: Includes the current date if it matches. +Use `nextOrSame(DayOfWeek dayOfWeek)`. This is useful for finding dates like the "teenth" days (13th-19th). Apply it to the 13th day of the month to find the target day of the week within that "teenth" range. ```java -LocalDate thursday = LocalDate.of(2024, Month.AUGUST, 15); // A Thursday +LocalDate thirteenth = LocalDate.of(2024, Month.AUGUST, 13); // Tuesday the 13th -// Find the next Sunday (exclusive) -LocalDate nextSunday = thursday.with(TemporalAdjusters.next(DayOfWeek.SUNDAY)); -// => 2024-08-18 +// Find the first Saturday on or after the 13th ("Teenth" Saturday) +LocalDate teenthSaturday = thirteenth.with(TemporalAdjusters.nextOrSame(DayOfWeek.SATURDAY)); +// => 2024-08-17 -// Find the next Thursday (exclusive) -LocalDate nextThursday = thursday.with(TemporalAdjusters.next(DayOfWeek.THURSDAY)); -// => 2024-08-22 - -// Find the next Thursday (inclusive) - returns the same date -LocalDate nextOrSameThursday = thursday.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY)); -// => 2024-08-15 - -// Find the previous Monday (exclusive) -LocalDate previousMonday = thursday.with(TemporalAdjusters.previous(DayOfWeek.MONDAY)); -// => 2024-08-12 -``` -The `nextOrSame()` adjuster is particularly useful for finding dates in ranges like the "teenth" days (13th-19th) of a month, as seen in the Meetup exercise. Applying `nextOrSame(targetDayOfWeek)` to the 13th day of the month will find the correct "teenth" date. - -## Custom Adjusters - -Since `TemporalAdjuster` is a [`@FunctionalInterface`][functionalinterface-docs], you can create your own custom adjusters using lambda expressions for logic not covered by the predefined methods. The interface requires implementing a single method: `Temporal adjustInto(Temporal temporal)`. - -```java -// Example: An adjuster that finds the next workday (Mon-Fri), skipping weekends. -TemporalAdjuster nextWorkday = temporal -> { - LocalDate result = (LocalDate) temporal; // Assuming input is LocalDate - do { - result = result.plusDays(1); - } while (result.getDayOfWeek() == DayOfWeek.SATURDAY || result.getDayOfWeek() == DayOfWeek.SUNDAY); - return result; -}; - -LocalDate friday = LocalDate.of(2024, Month.AUGUST, 16); -LocalDate nextWorkdayDate = friday.with(nextWorkday); -// => 2024-08-19 (Monday) - -LocalDate sunday = LocalDate.of(2024, Month.AUGUST, 18); -LocalDate nextWorkdayFromSunday = sunday.with(nextWorkday); -// => 2024-08-19 (Monday) +// Find the first Tuesday on or after the 13th ("Teenth" Tuesday) +LocalDate teenthTuesday = thirteenth.with(TemporalAdjusters.nextOrSame(DayOfWeek.TUESDAY)); +// => 2024-08-13 (returns the same date as it matches) ``` -While custom adjusters are powerful, the predefined adjusters in the `TemporalAdjusters` class cover a wide range of common use cases. -[temporaladjuster-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjuster.html -[temporaladjusters-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjusters.html -[localdate-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html -[dayofweek-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html -[functionalinterface-docs]: https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html +Using these adjusters from the `TemporalAdjusters` class can greatly simplify date manipulation tasks. From 0c94854ff87c12d58dc7b85d0881f457dec45a1c Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 12:38:16 +0300 Subject: [PATCH 03/13] Simplify JSON formatting in Temporal Adjusters config. Adjusted the `blurb` text for clarity and reformatted the `authors` field for improved readability. These changes maintain consistency with JSON coding standards and enhance the file's maintainability. --- concepts/temporal-adjusters/.meta/config.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/concepts/temporal-adjusters/.meta/config.json b/concepts/temporal-adjusters/.meta/config.json index 0c2bc3cab..48d931526 100644 --- a/concepts/temporal-adjusters/.meta/config.json +++ b/concepts/temporal-adjusters/.meta/config.json @@ -1,5 +1,7 @@ { - "blurb": "Perform common and complex date adjustments using Java's `TemporalAdjuster` interface and `TemporalAdjusters` utility class.", - "authors": ["rabestro"], + "blurb": "Perform date adjustments using Java's `TemporalAdjuster` interface and `TemporalAdjusters` utility class.", + "authors": [ + "rabestro" + ], "contributors": [] } From 0bff3ea95fb42af14ef6918cafa8f4a6a4f0466c Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 12:45:59 +0300 Subject: [PATCH 04/13] Enhance formatting in temporal-adjusters documentation Replaced asterisks with dashes for consistency in list formatting and added blank lines for better readability. These changes improve the overall structure and clarity of the documentation. --- concepts/temporal-adjusters/about.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/concepts/temporal-adjusters/about.md b/concepts/temporal-adjusters/about.md index be786485a..4b95a5140 100644 --- a/concepts/temporal-adjusters/about.md +++ b/concepts/temporal-adjusters/about.md @@ -85,8 +85,8 @@ LocalDate lastDayOfYear = date.with(TemporalAdjusters.lastDayOfYear()); Adjusters like `next()`, `previous()`, `nextOrSame()`, and `previousOrSame()` find the next or previous occurrence of a given day of the week, relative to the current date. -* `next()`/`previous()`: Excludes the current date if it matches. -* `nextOrSame()`/`previousOrSame()`: Includes the current date if it matches. +- `next()`/`previous()`: Excludes the current date if it matches. +- `nextOrSame()`/`previousOrSame()`: Includes the current date if it matches. ```java LocalDate thursday = LocalDate.of(2024, Month.AUGUST, 15); // A Thursday @@ -107,6 +107,7 @@ LocalDate nextOrSameThursday = thursday.with(TemporalAdjusters.nextOrSame(DayOfW LocalDate previousMonday = thursday.with(TemporalAdjusters.previous(DayOfWeek.MONDAY)); // => 2024-08-12 ``` + The `nextOrSame()` adjuster is particularly useful for finding dates in ranges like the "teenth" days (13th-19th) of a month, as seen in the Meetup exercise. Applying `nextOrSame(targetDayOfWeek)` to the 13th day of the month will find the correct "teenth" date. ## Custom Adjusters @@ -131,6 +132,7 @@ LocalDate sunday = LocalDate.of(2024, Month.AUGUST, 18); LocalDate nextWorkdayFromSunday = sunday.with(nextWorkday); // => 2024-08-19 (Monday) ``` + While custom adjusters are powerful, the predefined adjusters in the `TemporalAdjusters` class cover a wide range of common use cases. [temporaladjuster-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjuster.html From fd1ca6e8da1ef59f8c07cccb32e2a3f204ac914c Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 12:46:51 +0300 Subject: [PATCH 05/13] Update section headings in temporal adjusters guide. Standardize heading levels for consistency and readability. Changed `###` to `##` in multiple sections to align with the document's structure. No content modifications were made. --- concepts/temporal-adjusters/introduction.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/concepts/temporal-adjusters/introduction.md b/concepts/temporal-adjusters/introduction.md index bd775babd..d2c6e4ce5 100644 --- a/concepts/temporal-adjusters/introduction.md +++ b/concepts/temporal-adjusters/introduction.md @@ -23,7 +23,7 @@ LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth()); Here are some key adjusters useful for scheduling calculations: -### Finding Ordinal Day of Week +## Finding Ordinal Day of Week Use `dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)` to find the nth occurrence of a day of the week. @@ -33,7 +33,7 @@ LocalDate secondTuesday = date.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfW // => 2024-08-13 ``` -### Finding First/Last Day of Week in Month +## Finding First/Last Day of Week in Month Use `firstInMonth(DayOfWeek dayOfWeek)` or `lastInMonth(DayOfWeek dayOfWeek)`. @@ -43,7 +43,7 @@ LocalDate lastMonday = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY) // => 2024-08-26 ``` -### Finding Relative Occurrences ("Teenth" dates) +## Finding Relative Occurrences ("Teenth" dates) Use `nextOrSame(DayOfWeek dayOfWeek)`. This is useful for finding dates like the "teenth" days (13th-19th). Apply it to the 13th day of the month to find the target day of the week within that "teenth" range. From c1ece9d326275f07e2bc9f26b9038246027e635e Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 12:49:15 +0300 Subject: [PATCH 06/13] Remove unused links from temporal-adjusters documentation The links to LocalDate and DayOfWeek documentation were unused and have been removed to improve clarity and maintainability. This helps keep the documentation clean and focused. --- concepts/temporal-adjusters/about.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/concepts/temporal-adjusters/about.md b/concepts/temporal-adjusters/about.md index 4b95a5140..7eb7bc99a 100644 --- a/concepts/temporal-adjusters/about.md +++ b/concepts/temporal-adjusters/about.md @@ -137,6 +137,4 @@ While custom adjusters are powerful, the predefined adjusters in the `TemporalAd [temporaladjuster-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjuster.html [temporaladjusters-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjusters.html -[localdate-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html -[dayofweek-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html [functionalinterface-docs]: https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html From 2dc27b952687c3c0a3cbda3c36d57fc5b82cbb0a Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 15:16:14 +0300 Subject: [PATCH 07/13] Move meetup exercise from practice to concept track Relocated the `meetup` exercise and updated its structure to align with the concept track. Adjusted paths, references, and configuration files accordingly to reflect this transition. No functional changes to the implementation or tests were made. --- .../meetup/.docs/instructions.md | 0 .../meetup/.docs/introduction.md | 0 .../{practice => concept}/meetup/.meta/config.json | 0 .../meetup/.meta/src/reference/java/Meetup.java | 0 .../.meta/src/reference/java/MeetupSchedule.java | 0 .../{practice => concept}/meetup/.meta/tests.toml | 0 exercises/{practice => concept}/meetup/build.gradle | 0 .../meetup/gradle/wrapper/gradle-wrapper.jar | Bin .../meetup/gradle/wrapper/gradle-wrapper.properties | 0 exercises/{practice => concept}/meetup/gradlew | 0 exercises/{practice => concept}/meetup/gradlew.bat | 0 .../meetup/src/main/java/Meetup.java | 0 .../meetup/src/main/java/MeetupSchedule.java | 0 .../meetup/src/test/java/MeetupTest.java | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename exercises/{practice => concept}/meetup/.docs/instructions.md (100%) rename exercises/{practice => concept}/meetup/.docs/introduction.md (100%) rename exercises/{practice => concept}/meetup/.meta/config.json (100%) rename exercises/{practice => concept}/meetup/.meta/src/reference/java/Meetup.java (100%) rename exercises/{practice => concept}/meetup/.meta/src/reference/java/MeetupSchedule.java (100%) rename exercises/{practice => concept}/meetup/.meta/tests.toml (100%) rename exercises/{practice => concept}/meetup/build.gradle (100%) rename exercises/{practice => concept}/meetup/gradle/wrapper/gradle-wrapper.jar (100%) rename exercises/{practice => concept}/meetup/gradle/wrapper/gradle-wrapper.properties (100%) rename exercises/{practice => concept}/meetup/gradlew (100%) rename exercises/{practice => concept}/meetup/gradlew.bat (100%) rename exercises/{practice => concept}/meetup/src/main/java/Meetup.java (100%) rename exercises/{practice => concept}/meetup/src/main/java/MeetupSchedule.java (100%) rename exercises/{practice => concept}/meetup/src/test/java/MeetupTest.java (100%) diff --git a/exercises/practice/meetup/.docs/instructions.md b/exercises/concept/meetup/.docs/instructions.md similarity index 100% rename from exercises/practice/meetup/.docs/instructions.md rename to exercises/concept/meetup/.docs/instructions.md diff --git a/exercises/practice/meetup/.docs/introduction.md b/exercises/concept/meetup/.docs/introduction.md similarity index 100% rename from exercises/practice/meetup/.docs/introduction.md rename to exercises/concept/meetup/.docs/introduction.md diff --git a/exercises/practice/meetup/.meta/config.json b/exercises/concept/meetup/.meta/config.json similarity index 100% rename from exercises/practice/meetup/.meta/config.json rename to exercises/concept/meetup/.meta/config.json diff --git a/exercises/practice/meetup/.meta/src/reference/java/Meetup.java b/exercises/concept/meetup/.meta/src/reference/java/Meetup.java similarity index 100% rename from exercises/practice/meetup/.meta/src/reference/java/Meetup.java rename to exercises/concept/meetup/.meta/src/reference/java/Meetup.java diff --git a/exercises/practice/meetup/.meta/src/reference/java/MeetupSchedule.java b/exercises/concept/meetup/.meta/src/reference/java/MeetupSchedule.java similarity index 100% rename from exercises/practice/meetup/.meta/src/reference/java/MeetupSchedule.java rename to exercises/concept/meetup/.meta/src/reference/java/MeetupSchedule.java diff --git a/exercises/practice/meetup/.meta/tests.toml b/exercises/concept/meetup/.meta/tests.toml similarity index 100% rename from exercises/practice/meetup/.meta/tests.toml rename to exercises/concept/meetup/.meta/tests.toml diff --git a/exercises/practice/meetup/build.gradle b/exercises/concept/meetup/build.gradle similarity index 100% rename from exercises/practice/meetup/build.gradle rename to exercises/concept/meetup/build.gradle diff --git a/exercises/practice/meetup/gradle/wrapper/gradle-wrapper.jar b/exercises/concept/meetup/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from exercises/practice/meetup/gradle/wrapper/gradle-wrapper.jar rename to exercises/concept/meetup/gradle/wrapper/gradle-wrapper.jar diff --git a/exercises/practice/meetup/gradle/wrapper/gradle-wrapper.properties b/exercises/concept/meetup/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from exercises/practice/meetup/gradle/wrapper/gradle-wrapper.properties rename to exercises/concept/meetup/gradle/wrapper/gradle-wrapper.properties diff --git a/exercises/practice/meetup/gradlew b/exercises/concept/meetup/gradlew similarity index 100% rename from exercises/practice/meetup/gradlew rename to exercises/concept/meetup/gradlew diff --git a/exercises/practice/meetup/gradlew.bat b/exercises/concept/meetup/gradlew.bat similarity index 100% rename from exercises/practice/meetup/gradlew.bat rename to exercises/concept/meetup/gradlew.bat diff --git a/exercises/practice/meetup/src/main/java/Meetup.java b/exercises/concept/meetup/src/main/java/Meetup.java similarity index 100% rename from exercises/practice/meetup/src/main/java/Meetup.java rename to exercises/concept/meetup/src/main/java/Meetup.java diff --git a/exercises/practice/meetup/src/main/java/MeetupSchedule.java b/exercises/concept/meetup/src/main/java/MeetupSchedule.java similarity index 100% rename from exercises/practice/meetup/src/main/java/MeetupSchedule.java rename to exercises/concept/meetup/src/main/java/MeetupSchedule.java diff --git a/exercises/practice/meetup/src/test/java/MeetupTest.java b/exercises/concept/meetup/src/test/java/MeetupTest.java similarity index 100% rename from exercises/practice/meetup/src/test/java/MeetupTest.java rename to exercises/concept/meetup/src/test/java/MeetupTest.java From e533bf98c7335bcdd954299578c0e5daaf9b4d8e Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 15:18:55 +0300 Subject: [PATCH 08/13] Remove "Meetup" exercise from config.json The "Meetup" exercise entry has been deleted, including its slug, name, uuid, practices, prerequisites, and difficulty level. --- config.json | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/config.json b/config.json index ad71adad0..cd9ca7b86 100644 --- a/config.json +++ b/config.json @@ -1493,17 +1493,6 @@ ], "difficulty": 7 }, - { - "slug": "meetup", - "name": "Meetup", - "uuid": "602511d5-7e89-4def-b072-4dd311816810", - "practices": [], - "prerequisites": [ - "datetime", - "enums" - ], - "difficulty": 7 - }, { "slug": "poker", "name": "Poker", From 874839d31748d4a147bdbb66a7773088cf113d68 Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 15:36:26 +0300 Subject: [PATCH 09/13] Add documentation for the Meetup concept exercise Introduce `introduction.md.tpl` and `hints.md` for the Meetup exercise to guide learners. The hints provide detailed steps on working with `LocalDate` and `TemporalAdjusters` for date manipulations. --- exercises/concept/meetup/.docs/hints.md | 43 +++++++++++++++++++ .../concept/meetup/.docs/introduction.md.tpl | 3 ++ 2 files changed, 46 insertions(+) create mode 100644 exercises/concept/meetup/.docs/hints.md create mode 100644 exercises/concept/meetup/.docs/introduction.md.tpl diff --git a/exercises/concept/meetup/.docs/hints.md b/exercises/concept/meetup/.docs/hints.md new file mode 100644 index 000000000..2c00700c5 --- /dev/null +++ b/exercises/concept/meetup/.docs/hints.md @@ -0,0 +1,43 @@ +# Hints + +## 1. Representing the Date + +- The core class for representing dates without time in Java is [`java.time.LocalDate`][localdate-docs]. +- You'll need to work with the `year` and `month` provided in the constructor. +- The target day of the week is conveniently provided directly as a [`java.time.DayOfWeek`][dayofweek-docs] enum instance in the `day()` method. + +## 2. Starting Point for Adjustments + +- `LocalDate` objects are immutable. To find the target meetup date, you typically start with *any* date within the target `month` and `year` and then apply an "adjuster" to find the correct day. +- For example, you could create a `LocalDate` for the 1st of the month: `LocalDate.of(year, month, 1)`. +- For "Teenth" calculations, starting from the 13th of the month (`LocalDate.of(year, month, 13)`) can be helpful. + +## 3. Adjusting Dates with `TemporalAdjusters` + +- The key to solving this idiomatically is the [`java.time.temporal.TemporalAdjusters`][temporaladjusters-docs] utility class (note the plural 's'). It provides static methods that return [`TemporalAdjuster`][temporaladjuster-docs] instances for common date calculations. +- You apply an adjuster to a `LocalDate` using its `.with()` method: `someLocalDate.with(TemporalAdjusters.someAdjuster(...))` +- This returns a *new* `LocalDate` instance with the adjustment applied. + +## 4. Handling "Ordinal" Schedules (FIRST, SECOND, THIRD, FOURTH) + +- Look for a method in `TemporalAdjusters` that allows you to find a date based on its ordinal position (1st, 2nd, 3rd, 4th) and its `DayOfWeek` within the month. +- You might need to convert the `MeetupSchedule` enum values (`FIRST`, `SECOND`, etc.) into the corresponding integer ordinals (1, 2, 3, 4) to use this adjuster. + +## 5. Handling the "LAST" Schedule + +- `TemporalAdjusters` provides a specific adjuster to find the *last* occurrence of a given `DayOfWeek` within the month. + +## 6. Handling the "TEENTH" Schedule + +- "Teenth" days run from the 13th to the 19th of the month. +- Consider starting from the 13th day of the month (`LocalDate.of(year, month, 13)`). +- Look for an adjuster in `TemporalAdjusters` that finds the *next* occurrence of the target `DayOfWeek`, potentially *including* the date you're adjusting if it already matches the target day of the week. + +## 7. Selecting the Right Adjuster + +- Use the input `schedule` (which is a `MeetupSchedule` enum value) to determine which specific `TemporalAdjuster` method to use. A `switch` statement or `if-else if` chain on the `schedule` value is a common approach. + +[localdate-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html +[dayofweek-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html +[temporaladjuster-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjuster.html +[temporaladjusters-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjusters.html \ No newline at end of file diff --git a/exercises/concept/meetup/.docs/introduction.md.tpl b/exercises/concept/meetup/.docs/introduction.md.tpl new file mode 100644 index 000000000..1dc0a9066 --- /dev/null +++ b/exercises/concept/meetup/.docs/introduction.md.tpl @@ -0,0 +1,3 @@ +# Introduction + +%{concept:strings} From 95a5639ae2eb0bd837e1c3f1341384ee52acdcfd Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 15:47:13 +0300 Subject: [PATCH 10/13] Update meetup exercise metadata and fix file formatting Added the "exemplar" key to the config.json for better exercise organization. Also fixed the missing newline at the end of the hints.md file to ensure proper formatting. --- exercises/concept/meetup/.docs/hints.md | 2 +- exercises/concept/meetup/.meta/config.json | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/exercises/concept/meetup/.docs/hints.md b/exercises/concept/meetup/.docs/hints.md index 2c00700c5..8080fee71 100644 --- a/exercises/concept/meetup/.docs/hints.md +++ b/exercises/concept/meetup/.docs/hints.md @@ -40,4 +40,4 @@ [localdate-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html [dayofweek-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/DayOfWeek.html [temporaladjuster-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjuster.html -[temporaladjusters-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjusters.html \ No newline at end of file +[temporaladjusters-docs]: https://docs.oracle.com/javase/8/docs/api/java/time/temporal/TemporalAdjusters.html diff --git a/exercises/concept/meetup/.meta/config.json b/exercises/concept/meetup/.meta/config.json index f312b8205..6eec5aeeb 100644 --- a/exercises/concept/meetup/.meta/config.json +++ b/exercises/concept/meetup/.meta/config.json @@ -30,6 +30,9 @@ "test": [ "src/test/java/MeetupTest.java" ], + "exemplar": [ + ".meta/src/reference/java/Meetup.java" + ], "example": [ ".meta/src/reference/java/Meetup.java" ], From 69ce48191c066d365c8d57b30154be966d510c60 Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 15:53:25 +0300 Subject: [PATCH 11/13] Remove deprecated test configuration for meetup exercise The `tests.toml` file and specific keys in `config.json` for the meetup exercise have been removed. These changes clean up outdated metadata and streamline the exercise configuration. --- exercises/concept/meetup/.meta/config.json | 6 - exercises/concept/meetup/.meta/tests.toml | 288 --------------------- 2 files changed, 294 deletions(-) delete mode 100644 exercises/concept/meetup/.meta/tests.toml diff --git a/exercises/concept/meetup/.meta/config.json b/exercises/concept/meetup/.meta/config.json index 6eec5aeeb..1a98cb3c5 100644 --- a/exercises/concept/meetup/.meta/config.json +++ b/exercises/concept/meetup/.meta/config.json @@ -33,12 +33,6 @@ "exemplar": [ ".meta/src/reference/java/Meetup.java" ], - "example": [ - ".meta/src/reference/java/Meetup.java" - ], - "editor": [ - "src/main/java/MeetupSchedule.java" - ], "invalidator": [ "build.gradle" ] diff --git a/exercises/concept/meetup/.meta/tests.toml b/exercises/concept/meetup/.meta/tests.toml deleted file mode 100644 index 76a8e06ae..000000000 --- a/exercises/concept/meetup/.meta/tests.toml +++ /dev/null @@ -1,288 +0,0 @@ -# This is an auto-generated file. Regular comments will be removed when this -# file is regenerated. Regenerating will not touch any manually added keys, -# so comments can be added in a "comment" key. - -[d7f8eadd-d4fc-46ee-8a20-e97bd3fd01c8] -description = "monteenth of May 2013" - -[f78373d1-cd53-4a7f-9d37-e15bf8a456b4] -description = "monteenth of August 2013" - -[8c78bea7-a116-425b-9c6b-c9898266d92a] -description = "monteenth of September 2013" - -[cfef881b-9dc9-4d0b-8de4-82d0f39fc271] -description = "tuesteenth of March 2013" - -[69048961-3b00-41f9-97ee-eb6d83a8e92b] -description = "tuesteenth of April 2013" - -[d30bade8-3622-466a-b7be-587414e0caa6] -description = "tuesteenth of August 2013" - -[8db4b58b-92f3-4687-867b-82ee1a04f851] -description = "wednesteenth of January 2013" - -[6c27a2a2-28f8-487f-ae81-35d08c4664f7] -description = "wednesteenth of February 2013" - -[008a8674-1958-45b5-b8e6-c2c9960d973a] -description = "wednesteenth of June 2013" - -[e4abd5e3-57cb-4091-8420-d97e955c0dbd] -description = "thursteenth of May 2013" - -[85da0b0f-eace-4297-a6dd-63588d5055b4] -description = "thursteenth of June 2013" - -[ecf64f9b-8413-489b-bf6e-128045f70bcc] -description = "thursteenth of September 2013" - -[ac4e180c-7d0a-4d3d-b05f-f564ebb584ca] -description = "friteenth of April 2013" - -[b79101c7-83ad-4f8f-8ec8-591683296315] -description = "friteenth of August 2013" - -[6ed38b9f-0072-4901-bd97-7c8b8b0ef1b8] -description = "friteenth of September 2013" - -[dfae03ed-9610-47de-a632-655ab01e1e7c] -description = "saturteenth of February 2013" - -[ec02e3e1-fc72-4a3c-872f-a53fa8ab358e] -description = "saturteenth of April 2013" - -[d983094b-7259-4195-b84e-5d09578c89d9] -description = "saturteenth of October 2013" - -[d84a2a2e-f745-443a-9368-30051be60c2e] -description = "sunteenth of May 2013" - -[0e64bc53-92a3-4f61-85b2-0b7168c7ce5a] -description = "sunteenth of June 2013" - -[de87652c-185e-4854-b3ae-04cf6150eead] -description = "sunteenth of October 2013" - -[2cbfd0f5-ba3a-46da-a8cc-0fe4966d3411] -description = "first Monday of March 2013" - -[a6168c7c-ed95-4bb3-8f92-c72575fc64b0] -description = "first Monday of April 2013" - -[1bfc620f-1c54-4bbd-931f-4a1cd1036c20] -description = "first Tuesday of May 2013" - -[12959c10-7362-4ca0-a048-50cf1c06e3e2] -description = "first Tuesday of June 2013" - -[1033dc66-8d0b-48a1-90cb-270703d59d1d] -description = "first Wednesday of July 2013" - -[b89185b9-2f32-46f4-a602-de20b09058f6] -description = "first Wednesday of August 2013" - -[53aedc4d-b2c8-4dfb-abf7-a8dc9cdceed5] -description = "first Thursday of September 2013" - -[b420a7e3-a94c-4226-870a-9eb3a92647f0] -description = "first Thursday of October 2013" - -[61df3270-28b4-4713-bee2-566fa27302ca] -description = "first Friday of November 2013" - -[cad33d4d-595c-412f-85cf-3874c6e07abf] -description = "first Friday of December 2013" - -[a2869b52-5bba-44f0-a863-07bd1f67eadb] -description = "first Saturday of January 2013" - -[3585315a-d0db-4ea1-822e-0f22e2a645f5] -description = "first Saturday of February 2013" - -[c49e9bd9-8ccf-4cf2-947a-0ccd4e4f10b1] -description = "first Sunday of March 2013" - -[1513328b-df53-4714-8677-df68c4f9366c] -description = "first Sunday of April 2013" - -[49e083af-47ec-4018-b807-62ef411efed7] -description = "second Monday of March 2013" - -[6cb79a73-38fe-4475-9101-9eec36cf79e5] -description = "second Monday of April 2013" - -[4c39b594-af7e-4445-aa03-bf4f8effd9a1] -description = "second Tuesday of May 2013" - -[41b32c34-2e39-40e3-b790-93539aaeb6dd] -description = "second Tuesday of June 2013" - -[90a160c5-b5d9-4831-927f-63a78b17843d] -description = "second Wednesday of July 2013" - -[23b98ce7-8dd5-41a1-9310-ef27209741cb] -description = "second Wednesday of August 2013" - -[447f1960-27ca-4729-bc3f-f36043f43ed0] -description = "second Thursday of September 2013" - -[c9aa2687-300c-4e79-86ca-077849a81bde] -description = "second Thursday of October 2013" - -[a7e11ef3-6625-4134-acda-3e7195421c09] -description = "second Friday of November 2013" - -[8b420e5f-9290-4106-b5ae-022f3e2a3e41] -description = "second Friday of December 2013" - -[80631afc-fc11-4546-8b5f-c12aaeb72b4f] -description = "second Saturday of January 2013" - -[e34d43ac-f470-44c2-aa5f-e97b78ecaf83] -description = "second Saturday of February 2013" - -[a57d59fd-1023-47ad-b0df-a6feb21b44fc] -description = "second Sunday of March 2013" - -[a829a8b0-abdd-4ad1-b66c-5560d843c91a] -description = "second Sunday of April 2013" - -[501a8a77-6038-4fc0-b74c-33634906c29d] -description = "third Monday of March 2013" - -[49e4516e-cf32-4a58-8bbc-494b7e851c92] -description = "third Monday of April 2013" - -[4db61095-f7c7-493c-85f1-9996ad3012c7] -description = "third Tuesday of May 2013" - -[714fc2e3-58d0-4b91-90fd-61eefd2892c0] -description = "third Tuesday of June 2013" - -[b08a051a-2c80-445b-9b0e-524171a166d1] -description = "third Wednesday of July 2013" - -[80bb9eff-3905-4c61-8dc9-bb03016d8ff8] -description = "third Wednesday of August 2013" - -[fa52a299-f77f-4784-b290-ba9189fbd9c9] -description = "third Thursday of September 2013" - -[f74b1bc6-cc5c-4bf1-ba69-c554a969eb38] -description = "third Thursday of October 2013" - -[8900f3b0-801a-466b-a866-f42d64667abd] -description = "third Friday of November 2013" - -[538ac405-a091-4314-9ccd-920c4e38e85e] -description = "third Friday of December 2013" - -[244db35c-2716-4fa0-88ce-afd58e5cf910] -description = "third Saturday of January 2013" - -[dd28544f-f8fa-4f06-9bcd-0ad46ce68e9e] -description = "third Saturday of February 2013" - -[be71dcc6-00d2-4b53-a369-cbfae55b312f] -description = "third Sunday of March 2013" - -[b7d2da84-4290-4ee6-a618-ee124ae78be7] -description = "third Sunday of April 2013" - -[4276dc06-a1bd-4fc2-b6c2-625fee90bc88] -description = "fourth Monday of March 2013" - -[ddbd7976-2deb-4250-8a38-925ac1a8e9a2] -description = "fourth Monday of April 2013" - -[eb714ef4-1656-47cc-913c-844dba4ebddd] -description = "fourth Tuesday of May 2013" - -[16648435-7937-4d2d-b118-c3e38fd084bd] -description = "fourth Tuesday of June 2013" - -[de062bdc-9484-437a-a8c5-5253c6f6785a] -description = "fourth Wednesday of July 2013" - -[c2ce6821-169c-4832-8d37-690ef5d9514a] -description = "fourth Wednesday of August 2013" - -[d462c631-2894-4391-a8e3-dbb98b7a7303] -description = "fourth Thursday of September 2013" - -[9ff1f7b6-1b72-427d-9ee9-82b5bb08b835] -description = "fourth Thursday of October 2013" - -[83bae8ba-1c49-49bc-b632-b7c7e1d7e35f] -description = "fourth Friday of November 2013" - -[de752d2a-a95e-48d2-835b-93363dac3710] -description = "fourth Friday of December 2013" - -[eedd90ad-d581-45db-8312-4c6dcf9cf560] -description = "fourth Saturday of January 2013" - -[669fedcd-912e-48c7-a0a1-228b34af91d0] -description = "fourth Saturday of February 2013" - -[648e3849-ea49-44a5-a8a3-9f2a43b3bf1b] -description = "fourth Sunday of March 2013" - -[f81321b3-99ab-4db6-9267-69c5da5a7823] -description = "fourth Sunday of April 2013" - -[1af5e51f-5488-4548-aee8-11d7d4a730dc] -description = "last Monday of March 2013" - -[f29999f2-235e-4ec7-9dab-26f137146526] -description = "last Monday of April 2013" - -[31b097a0-508e-48ac-bf8a-f63cdcf6dc41] -description = "last Tuesday of May 2013" - -[8c022150-0bb5-4a1f-80f9-88b2e2abcba4] -description = "last Tuesday of June 2013" - -[0e762194-672a-4bdf-8a37-1e59fdacef12] -description = "last Wednesday of July 2013" - -[5016386a-f24e-4bd7-b439-95358f491b66] -description = "last Wednesday of August 2013" - -[12ead1a5-cdf9-4192-9a56-2229e93dd149] -description = "last Thursday of September 2013" - -[7db89e11-7fbe-4e57-ae3c-0f327fbd7cc7] -description = "last Thursday of October 2013" - -[e47a739e-b979-460d-9c8a-75c35ca2290b] -description = "last Friday of November 2013" - -[5bed5aa9-a57a-4e5d-8997-2cc796a5b0ec] -description = "last Friday of December 2013" - -[61e54cba-76f3-4772-a2b1-bf443fda2137] -description = "last Saturday of January 2013" - -[8b6a737b-2fa9-444c-b1a2-80ce7a2ec72f] -description = "last Saturday of February 2013" - -[0b63e682-f429-4d19-9809-4a45bd0242dc] -description = "last Sunday of March 2013" - -[5232307e-d3e3-4afc-8ba6-4084ad987c00] -description = "last Sunday of April 2013" - -[0bbd48e8-9773-4e81-8e71-b9a51711e3c5] -description = "last Wednesday of February 2012" - -[fe0936de-7eee-4a48-88dd-66c07ab1fefc] -description = "last Wednesday of December 2014" - -[2ccf2488-aafc-4671-a24e-2b6effe1b0e2] -description = "last Sunday of February 2015" - -[00c3ce9f-cf36-4b70-90d8-92b32be6830e] -description = "first Friday of December 2012" From 9150859719dad612f4e65c7ee53f44e2b10b0a9f Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 15:53:34 +0300 Subject: [PATCH 12/13] Add design document for the Meetup concept exercise Introduces learning objectives, out-of-scope topics, concepts, prerequisites, and analyzer rules for the exercise. Clarifies focus on `TemporalAdjusters` and proper usage of `java.time` API while providing guidance for evaluations in the analyzer. --- exercises/concept/meetup/.meta/design.md | 45 ++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 exercises/concept/meetup/.meta/design.md diff --git a/exercises/concept/meetup/.meta/design.md b/exercises/concept/meetup/.meta/design.md new file mode 100644 index 000000000..81faaa66b --- /dev/null +++ b/exercises/concept/meetup/.meta/design.md @@ -0,0 +1,45 @@ +# Design + +## Learning objectives + +- Know about the `java.time.temporal.TemporalAdjuster` interface and its purpose. +- Know about the `java.time.temporal.TemporalAdjusters` utility class and how to use its static factory methods. +- Know how to apply a `TemporalAdjuster` to a `LocalDate` using the `.with()` method. +- Know how to select and use common predefined adjusters like `TemporalAdjusters.dayOfWeekInMonth()`, `TemporalAdjusters.lastInMonth()`, and `TemporalAdjusters.nextOrSame()`. +- Understand that `java.time` objects are immutable and adjustment methods return new instances. +- Know how to use a `java.time.DayOfWeek` enum value. +- Know how to use a custom `enum` (like `MeetupSchedule`) in conditional logic (e.g., `switch` statement). + +## Out of scope + +- Creating complex custom `TemporalAdjuster` implementations. +- Time zones, offsets, `ZonedDateTime`. +- `LocalDateTime`, `LocalTime`. +- Durations (`java.time.Duration`) and Periods (`java.time.Period`). +- Date/time parsing and formatting. + +## Concepts + +- `temporal-adjusters`: This exercise introduces and focuses on the `TemporalAdjusters` concept. +- `datetime`: Reinforces basic usage of `LocalDate` and `DayOfWeek`. +- `enums`: Reinforces usage of enums. + +## Prerequisites + +- `datetime`: Must know how to create and use basic `java.time.LocalDate` objects and understand `DayOfWeek`. +- `enums`: Must know how to work with `enum` types, including using them in `switch` statements or accessing properties like `ordinal()`. +- `classes`: Basic understanding of Java classes and methods. +- `methods`: Basic understanding of Java methods. + +## Analyzer + +This exercise could benefit from the following rules in the [analyzer]: + +- `essential` (replaces `actionable` if it MUST be fixed): If the solution involves significant manual date calculation logic (e.g., loops checking day of week, complex `plusDays`/`minusDays` sequences) instead of using `TemporalAdjusters`, instruct the student that using the `TemporalAdjusters` class is the idiomatic approach for this exercise. Provide a link to the `TemporalAdjusters` concept documentation. +- `actionable`: If the student uses `TemporalAdjusters.dayOfWeekInMonth()`, check if they correctly map the `MeetupSchedule` enum ordinal (0-based) to the required 1-based ordinal argument. If not, provide a hint. +- `actionable`: If the logic for `MeetupSchedule.TEENTH` seems incorrect or overly complex, suggest using `TemporalAdjusters.nextOrSame()` applied to the 13th day of the month. +- `informative`: If the student uses `TemporalAdjusters` correctly, mention the specific adjusters used (`dayOfWeekInMonth`, `lastInMonth`, `nextOrSame`) as good choices for their respective cases. + +If the solution uses `TemporalAdjusters` correctly for all `MeetupSchedule` cases, it should be considered exemplar. Leave a `celebratory` comment to celebrate the success! + +[analyzer]: https://github.com/exercism/java-analyzer From e76ec259e8d1d4240ac4e2ba41d597e10c636963 Mon Sep 17 00:00:00 2001 From: Jegors Cemisovs Date: Sun, 4 May 2025 16:24:21 +0300 Subject: [PATCH 13/13] Add configuration for concept 'meetup' exercise Updated `config.json` to include 'editor' paths for 'meetup' and adjusted `settings.gradle` to include the concept version while removing the practice version. This aligns with the intended migration from a practice exercise to a concept exercise. --- exercises/concept/meetup/.meta/config.json | 3 +++ exercises/settings.gradle | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/exercises/concept/meetup/.meta/config.json b/exercises/concept/meetup/.meta/config.json index 1a98cb3c5..44da62752 100644 --- a/exercises/concept/meetup/.meta/config.json +++ b/exercises/concept/meetup/.meta/config.json @@ -33,6 +33,9 @@ "exemplar": [ ".meta/src/reference/java/Meetup.java" ], + "editor": [ + "src/main/java/MeetupSchedule.java" + ], "invalidator": [ "build.gradle" ] diff --git a/exercises/settings.gradle b/exercises/settings.gradle index 2ff1e9a14..8dc7dc723 100644 --- a/exercises/settings.gradle +++ b/exercises/settings.gradle @@ -16,6 +16,7 @@ include 'concept:karls-languages' include 'concept:lasagna' include 'concept:log-levels' include 'concept:logs-logs-logs' +include 'concept:meetup' include 'concept:need-for-speed' include 'concept:remote-control-competition' include 'concept:salary-calculator' @@ -91,7 +92,6 @@ include 'practice:markdown' include 'practice:matching-brackets' include 'practice:matrix' include 'practice:mazy-mice' -include 'practice:meetup' include 'practice:micro-blog' include 'practice:minesweeper' include 'practice:nth-prime'