From 4de2a922ab548b0166ac6ea16e81c8991d091cc9 Mon Sep 17 00:00:00 2001 From: Glenn Jackman Date: Sun, 29 Mar 2026 14:28:06 -0400 Subject: [PATCH 1/2] Add gigasecond It relies on the [lua-tz](https://luarocks.org/modules/anaef/lua-tz) rock. --- .github/workflows/pr.yml | 1 + .github/workflows/test.yml | 1 + config.json | 8 +++++ exercises/practice/gigasecond/.busted | 5 +++ .../gigasecond/.docs/instructions.append.md | 33 +++++++++++++++++++ .../practice/gigasecond/.docs/instructions.md | 8 +++++ .../practice/gigasecond/.docs/introduction.md | 24 ++++++++++++++ .../practice/gigasecond/.meta/config.json | 20 +++++++++++ .../practice/gigasecond/.meta/example.moon | 25 ++++++++++++++ .../gigasecond/.meta/spec_generator.moon | 15 +++++++++ .../practice/gigasecond/.meta/tests.toml | 28 ++++++++++++++++ exercises/practice/gigasecond/gigasecond.moon | 4 +++ .../practice/gigasecond/gigasecond_spec.moon | 28 ++++++++++++++++ 13 files changed, 200 insertions(+) create mode 100644 exercises/practice/gigasecond/.busted create mode 100644 exercises/practice/gigasecond/.docs/instructions.append.md create mode 100644 exercises/practice/gigasecond/.docs/instructions.md create mode 100644 exercises/practice/gigasecond/.docs/introduction.md create mode 100644 exercises/practice/gigasecond/.meta/config.json create mode 100644 exercises/practice/gigasecond/.meta/example.moon create mode 100644 exercises/practice/gigasecond/.meta/spec_generator.moon create mode 100644 exercises/practice/gigasecond/.meta/tests.toml create mode 100644 exercises/practice/gigasecond/gigasecond.moon create mode 100644 exercises/practice/gigasecond/gigasecond_spec.moon diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 8217393..ff4f676 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -20,6 +20,7 @@ jobs: run: | luarocks install busted luarocks install moonscript + luarocks install lua-tz - name: Run tests for changed/added exercises env: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f2c067c..d405a69 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -22,6 +22,7 @@ jobs: run: | luarocks install busted luarocks install moonscript + luarocks install lua-tz - name: test run: | diff --git a/config.json b/config.json index e60a2a6..93a4d21 100644 --- a/config.json +++ b/config.json @@ -282,6 +282,14 @@ "prerequisites": [], "difficulty": 3 }, + { + "slug": "gigasecond", + "name": "Gigasecond", + "uuid": "f870722b-6bfc-4516-92ba-9fb1c2866d34", + "practices": [], + "prerequisites": [], + "difficulty": 3 + }, { "slug": "high-scores", "name": "High Scores", diff --git a/exercises/practice/gigasecond/.busted b/exercises/practice/gigasecond/.busted new file mode 100644 index 0000000..86b84e7 --- /dev/null +++ b/exercises/practice/gigasecond/.busted @@ -0,0 +1,5 @@ +return { + default = { + ROOT = { '.' } + } +} diff --git a/exercises/practice/gigasecond/.docs/instructions.append.md b/exercises/practice/gigasecond/.docs/instructions.append.md new file mode 100644 index 0000000..06a16e5 --- /dev/null +++ b/exercises/practice/gigasecond/.docs/instructions.append.md @@ -0,0 +1,33 @@ +# dummy + +## MoonScript-specific instructions + +The input and expected datetime strings in the tests are expressed in the UTC timezone. +This is done to remove the effects of daylight saving time in your local timezone. + +The key challenge in this exercise is to parse the input timestamp _as if you are in the UTC timezone_. +Lua's builtin `os.time` function simply can't do that. +It can only return the **local** time. +And it's not as simple as adjusting that local time with your timezone offset (in seconds) from UTC: +you need to know the offset _at the moment you are parsing_, not the _current_ offset. + +Datetime arithmetic is a **very** complicated topic, and you don't want to have to re-invent that wheel: you want to be able to rely on a well-tested library to get the details right. + +The `lua-tz` module works well for this exercise. +It provides `tz.time` and `tz.date` functions that are drop-in replacements for the builtin `os.time` and `os.date` functions, but allow you to provide a timezone name as an extra parameter. + +We have provided some additional datetime modules to the MoonScript test runner, if you want to experiment with them. + +* `lua-tz`: [luarocks info page][lua-tz-rock], [website][lua-tz-home], [documentation][lua-tz-doc] +* `date`: [luarocks info page][date-rock], [website][date-home], [documentation][date-doc] +* `luatz`: [luarocks info page][luatz-rock], [website][luatz-home], [documentation][luatz-doc] + +[lua-tz-rock]: https://luarocks.org/modules/anaef/lua-tz +[lua-tz-home]: https://github.com/anaef/lua-tz#readme +[lua-tz-doc]: https://github.com/anaef/lua-tz/tree/master/doc#readme +[date-rock]: https://luarocks.org/modules/tieske/date +[date-home]: https://github.com/Tieske/date#readme +[date-doc]: https://tieske.github.io/date/ +[luatz-rock]: https://luarocks.org/modules/daurnimator/luatz +[luatz-home]: https://github.com/daurnimator/luatz#readme +[luatz-doc]: https://daurnimator.github.io/luatz/ diff --git a/exercises/practice/gigasecond/.docs/instructions.md b/exercises/practice/gigasecond/.docs/instructions.md new file mode 100644 index 0000000..1e20f00 --- /dev/null +++ b/exercises/practice/gigasecond/.docs/instructions.md @@ -0,0 +1,8 @@ +# Instructions + +Your task is to determine the date and time one gigasecond after a certain date. + +A gigasecond is one thousand million seconds. +That is a one with nine zeros after it. + +If you were born on _January 24th, 2015 at 22:00 (10:00:00pm)_, then you would be a gigasecond old on _October 2nd, 2046 at 23:46:40 (11:46:40pm)_. diff --git a/exercises/practice/gigasecond/.docs/introduction.md b/exercises/practice/gigasecond/.docs/introduction.md new file mode 100644 index 0000000..18a3dc2 --- /dev/null +++ b/exercises/practice/gigasecond/.docs/introduction.md @@ -0,0 +1,24 @@ +# Introduction + +The way we measure time is kind of messy. +We have 60 seconds in a minute, and 60 minutes in an hour. +This comes from ancient Babylon, where they used 60 as the basis for their number system. +We have 24 hours in a day, 7 days in a week, and how many days in a month? +Well, for days in a month it depends not only on which month it is, but also on what type of calendar is used in the country you live in. + +What if, instead, we only use seconds to express time intervals? +Then we can use metric system prefixes for writing large numbers of seconds in more easily comprehensible quantities. + +- A food recipe might explain that you need to let the brownies cook in the oven for two kiloseconds (that's two thousand seconds). +- Perhaps you and your family would travel to somewhere exotic for two megaseconds (that's two million seconds). +- And if you and your spouse were married for _a thousand million_ seconds, you would celebrate your one gigasecond anniversary. + +~~~~exercism/note +If we ever colonize Mars or some other planet, measuring time is going to get even messier. +If someone says "year" do they mean a year on Earth or a year on Mars? + +The idea for this exercise came from the science fiction novel ["A Deepness in the Sky"][vinge-novel] by author Vernor Vinge. +In it the author uses the metric system as the basis for time measurements. + +[vinge-novel]: https://www.tor.com/2017/08/03/science-fiction-with-something-for-everyone-a-deepness-in-the-sky-by-vernor-vinge/ +~~~~ diff --git a/exercises/practice/gigasecond/.meta/config.json b/exercises/practice/gigasecond/.meta/config.json new file mode 100644 index 0000000..1f7a427 --- /dev/null +++ b/exercises/practice/gigasecond/.meta/config.json @@ -0,0 +1,20 @@ +{ + "authors": [ + "glennj", + "BNAndras" + ], + "files": { + "solution": [ + "gigasecond.moon" + ], + "test": [ + "gigasecond_spec.moon" + ], + "example": [ + ".meta/example.moon" + ] + }, + "blurb": "Given a moment, determine the moment that would be after a gigasecond has passed.", + "source": "Chapter 9 in Chris Pine's online Learn to Program tutorial.", + "source_url": "https://pine.fm/LearnToProgram/chap_09.html" +} diff --git a/exercises/practice/gigasecond/.meta/example.moon b/exercises/practice/gigasecond/.meta/example.moon new file mode 100644 index 0000000..cd39e3c --- /dev/null +++ b/exercises/practice/gigasecond/.meta/example.moon @@ -0,0 +1,25 @@ +tz = require 'tz' -- https://luarocks.org/modules/anaef/lua-tz + +GIGASECOND = 1e9 +DATE_FORMAT = '%Y-%m-%dT%H:%M:%S' +DATE_PATTERN = '^(%d%d%d%d)-(%d%d)-(%d%d)T(%d%d):(%d%d):(%d%d)$' + +parse = (timestamp) -> + local m + spec = -> {year: m[1], month: m[2], day: m[3], hour: m[4], min: m[5], sec: m[6]} + + m = table.pack timestamp\match DATE_PATTERN + return spec! if m.n > 1 + + m = table.pack (timestamp .. 'T00:00:00')\match DATE_PATTERN + return spec! if m.n > 1 + + error "can't parse \"#{timestamp}\"" + + +{ + add: (timestamp) -> + time = tz.time parse(timestamp), 'UTC' + tz.date DATE_FORMAT, time + GIGASECOND, 'UTC' + -- os.date works here too: os.date '!...', time + GIGASECOND +} diff --git a/exercises/practice/gigasecond/.meta/spec_generator.moon b/exercises/practice/gigasecond/.meta/spec_generator.moon new file mode 100644 index 0000000..03df107 --- /dev/null +++ b/exercises/practice/gigasecond/.meta/spec_generator.moon @@ -0,0 +1,15 @@ +{ + module_name: 'Gigasecond', + + generate_test: (case, level) -> + lines = { + "result = Gigasecond.#{case.property} #{quote case.input.moment}", + "expected = #{quote case.expected}", + "assert.are.equal expected, result" + } + table.concat [indent line, level for line in *lines], '\n' + + exclusions: { + {key: 'scenarios', op: 'contains', value: 'immutable'} + } +} diff --git a/exercises/practice/gigasecond/.meta/tests.toml b/exercises/practice/gigasecond/.meta/tests.toml new file mode 100644 index 0000000..a7caf00 --- /dev/null +++ b/exercises/practice/gigasecond/.meta/tests.toml @@ -0,0 +1,28 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[92fbe71c-ea52-4fac-bd77-be38023cacf7] +description = "date only specification of time" + +[6d86dd16-6f7a-47be-9e58-bb9fb2ae1433] +description = "second test for date only specification of time" + +[77eb8502-2bca-4d92-89d9-7b39ace28dd5] +description = "third test for date only specification of time" + +[c9d89a7d-06f8-4e28-a305-64f1b2abc693] +description = "full time specified" + +[09d4e30e-728a-4b52-9005-be44a58d9eba] +description = "full time with day roll-over" + +[fcec307c-7529-49ab-b0fe-20309197618a] +description = "does not mutate the input" diff --git a/exercises/practice/gigasecond/gigasecond.moon b/exercises/practice/gigasecond/gigasecond.moon new file mode 100644 index 0000000..7753ad0 --- /dev/null +++ b/exercises/practice/gigasecond/gigasecond.moon @@ -0,0 +1,4 @@ +{ + add: (timestamp) -> + error 'Implement me' +} diff --git a/exercises/practice/gigasecond/gigasecond_spec.moon b/exercises/practice/gigasecond/gigasecond_spec.moon new file mode 100644 index 0000000..b15a05a --- /dev/null +++ b/exercises/practice/gigasecond/gigasecond_spec.moon @@ -0,0 +1,28 @@ +Gigasecond = require 'gigasecond' + +describe 'gigasecond', -> + it 'date only specification of time', -> + result = Gigasecond.add '2011-04-25' + expected = '2043-01-01T01:46:40' + assert.are.equal expected, result + + pending 'second test for date only specification of time', -> + result = Gigasecond.add '1977-06-13' + expected = '2009-02-19T01:46:40' + assert.are.equal expected, result + + pending 'third test for date only specification of time', -> + result = Gigasecond.add '1959-07-19' + expected = '1991-03-27T01:46:40' + assert.are.equal expected, result + + pending 'full time specified', -> + result = Gigasecond.add '2015-01-24T22:00:00' + expected = '2046-10-02T23:46:40' + assert.are.equal expected, result + + pending 'full time with day roll-over', -> + result = Gigasecond.add '2015-01-24T23:59:59' + expected = '2046-10-03T01:46:39' + assert.are.equal expected, result + From 8dca1f73ab1f4aa8fd59bac38ef91d5d4a21e563 Mon Sep 17 00:00:00 2001 From: Glenn Jackman Date: Sun, 29 Mar 2026 15:18:15 -0400 Subject: [PATCH 2/2] bump the difficulty --- config.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/config.json b/config.json index 93a4d21..bea1cbe 100644 --- a/config.json +++ b/config.json @@ -282,14 +282,6 @@ "prerequisites": [], "difficulty": 3 }, - { - "slug": "gigasecond", - "name": "Gigasecond", - "uuid": "f870722b-6bfc-4516-92ba-9fb1c2866d34", - "practices": [], - "prerequisites": [], - "difficulty": 3 - }, { "slug": "high-scores", "name": "High Scores", @@ -642,6 +634,14 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "gigasecond", + "name": "Gigasecond", + "uuid": "f870722b-6bfc-4516-92ba-9fb1c2866d34", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "matching-brackets", "name": "Matching Brackets",