Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Switched to using `gleam_time` instead of `birl`.
- All `birl.Time` usages have been replaced with `gleam/time/timestamp.Timestamp`.
- All `birl.Duration` usages have been replaced with `gleam/time/duration.Duration`.

## [1.0.1] - 2025-07-26

### Changed
Expand Down
2 changes: 1 addition & 1 deletion gleam.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ licenses = ["MIT"]
repository = { type = "github", user = "maxdeviant", repo = "bigben" }

[dependencies]
birl = ">= 1.8.0 and < 2.0.0"
gleam_erlang = ">= 1.2.0 and < 2.0.0"
gleam_otp = ">= 1.0.0 and < 2.0.0"
gleam_stdlib = ">= 0.62.0 and < 1.0.0"
gleam_time = ">= 1.4.0 and < 2.0.0"

[dev-dependencies]
gleeunit = ">= 1.6.1 and < 2.0.0"
7 changes: 2 additions & 5 deletions manifest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,16 @@
# You typically do not need to edit this file

packages = [
{ name = "birl", version = "1.8.0", build_tools = ["gleam"], requirements = ["gleam_regexp", "gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "2AC7BA26F998E3DFADDB657148BD5DDFE966958AD4D6D6957DD0D22E5B56C400" },
{ name = "gleam_erlang", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "F91CE62A2D011FA13341F3723DB7DB118541AAA5FE7311BD2716D018F01EF9E3" },
{ name = "gleam_otp", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "7020E652D18F9ABAC9C877270B14160519FA0856EE80126231C505D719AD68DA" },
{ name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" },
{ name = "gleam_stdlib", version = "0.62.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "DC8872BC0B8550F6E22F0F698CFE7F1E4BDA7312FDEB40D6C3F44C5B706C8310" },
{ name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
{ name = "gleam_time", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "DCDDC040CE97DA3D2A925CDBBA08D8A78681139745754A83998641C8A3F6587E" },
{ name = "gleeunit", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "FDC68A8C492B1E9B429249062CD9BAC9B5538C6FBF584817205D0998C42E1DAC" },
{ name = "ranger", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_yielder"], otp_app = "ranger", source = "hex", outer_checksum = "C8988E8F8CDBD3E7F4D8F2E663EF76490390899C2B2885A6432E942495B3E854" },
]

[requirements]
birl = { version = ">= 1.8.0 and < 2.0.0" }
gleam_erlang = { version = ">= 1.2.0 and < 2.0.0" }
gleam_otp = { version = ">= 1.0.0 and < 2.0.0" }
gleam_stdlib = { version = ">= 0.62.0 and < 1.0.0" }
gleam_time = { version = ">= 1.4.0 and < 2.0.0" }
gleeunit = { version = ">= 1.6.1 and < 2.0.0" }
10 changes: 5 additions & 5 deletions src/bigben/clock.gleam
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
//// A clock.

import bigben/fake_clock.{type FakeClock}
import birl.{type Time}
import gleam/time/timestamp.{type Timestamp}

/// A clock.
pub opaque type Clock {
Clock(utc_now: fn() -> Time)
Clock(utc_now: fn() -> Timestamp)
}

/// Returns a new `Clock`.
pub fn new() -> Clock {
Clock(birl.utc_now)
Clock(timestamp.system_time)
}

/// Returns the current time on the given `Clock`, in UTC.
pub fn now(clock: Clock) -> Time {
/// Returns the current time on the given `Clock`.
pub fn now(clock: Clock) -> Timestamp {
clock.utc_now()
}

Expand Down
22 changes: 11 additions & 11 deletions src/bigben/fake_clock.gleam
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//// A fake clock for manipulating the flow of time.

import birl.{type Time}
import birl/duration.{type Duration}
import gleam/erlang/process.{type Subject}
import gleam/otp/actor
import gleam/time/duration.{type Duration}
import gleam/time/timestamp.{type Timestamp}

/// A fake clock.
pub opaque type FakeClock {
Expand All @@ -12,25 +12,25 @@ pub opaque type FakeClock {

/// Returns a new `FakeClock`.
///
/// The current time will be now in UTC.
/// The current time will be the instant the clock was created.
pub fn new() -> FakeClock {
new_at(birl.utc_now())
new_at(timestamp.system_time())
}

/// Returns a new `FakeClock` at the given time.
pub fn new_at(now: Time) -> FakeClock {
pub fn new_at(now: Timestamp) -> FakeClock {
let assert Ok(actor) =
actor.new(now) |> actor.on_message(handle_message) |> actor.start
FakeClock(actor.data)
}

/// Returns the current time on the given `FakeClock`.
pub fn now(clock: FakeClock) -> Time {
pub fn now(clock: FakeClock) -> Timestamp {
process.call(clock.subject, 10, Get)
}

/// Sets the current time on the given `FakeClock` to the specified value.
pub fn set_now(clock: FakeClock, now: Time) -> Nil {
pub fn set_now(clock: FakeClock, now: Timestamp) -> Nil {
process.send(clock.subject, Set(now))
}

Expand All @@ -40,18 +40,18 @@ pub fn advance(clock: FakeClock, duration: Duration) -> Nil {
}

type Message {
Get(reply_with: Subject(Time))
Set(Time)
Get(reply_with: Subject(Timestamp))
Set(Timestamp)
Advance(Duration)
}

fn handle_message(state: Time, message: Message) {
fn handle_message(state: Timestamp, message: Message) {
case message {
Get(client) -> {
process.send(client, state)
actor.continue(state)
}
Set(now) -> actor.continue(now)
Advance(duration) -> actor.continue(birl.add(state, duration))
Advance(duration) -> actor.continue(timestamp.add(state, duration))
}
}
24 changes: 12 additions & 12 deletions test/bigben/clock_test.gleam
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
import bigben/clock.{type Clock}
import bigben/fake_clock
import birl.{Day}
import birl/duration
import gleam/int
import gleam/time/calendar
import gleam/time/duration
import gleam/time/timestamp
import gleeunit/should

pub fn clock_can_be_faked_test() {
let assert Ok(now) = birl.parse("2024-04-12T01:33:46.382Z")
let assert Ok(now) = timestamp.parse_rfc3339("2024-04-12T01:33:46.382Z")
let fake_clock = fake_clock.new_at(now)
let clock = clock.from_fake(fake_clock)

what_day_is_it(clock)
|> should.equal("Today is Friday, April 12, 2024")
|> should.equal("Today is April 12, 2024")

fake_clock.advance(fake_clock, duration.days(5))
fake_clock.advance(fake_clock, duration.hours(5 * 24))

what_day_is_it(clock)
|> should.equal("Today is Wednesday, April 17, 2024")
|> should.equal("Today is April 17, 2024")
}

fn what_day_is_it(clock: Clock) -> String {
let now = clock.now(clock)
let #(date, _time) = now |> timestamp.to_calendar(calendar.utc_offset)

let weekday = birl.string_weekday(now)
let month = birl.string_month(now)
let Day(year, _, day) = birl.get_day(now)
let day = int.to_string(day)
let year = int.to_string(year)
let month = date.month |> calendar.month_to_string
let day = int.to_string(date.day)
let year = int.to_string(date.year)

"Today is " <> weekday <> ", " <> month <> " " <> day <> ", " <> year
"Today is " <> month <> " " <> day <> ", " <> year
}
31 changes: 16 additions & 15 deletions test/bigben/fake_clock_test.gleam
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
import bigben/fake_clock
import birl
import birl/duration
import gleam/time/calendar
import gleam/time/duration
import gleam/time/timestamp
import gleeunit/should

pub fn fake_clock_set_now_test() {
let assert Ok(now) = birl.parse("2024-04-13T01:33:46.382Z")
let assert Ok(now) = timestamp.parse_rfc3339("2024-04-13T01:33:46.382Z")
let clock = fake_clock.new_at(now)

fake_clock.now(clock)
|> birl.to_iso8601
|> should.equal(birl.to_iso8601(now))
|> timestamp.to_rfc3339(calendar.utc_offset)
|> should.equal(timestamp.to_rfc3339(now, calendar.utc_offset))

let assert Ok(new_now) = birl.parse("2025-04-13T01:33:46.382Z")
let assert Ok(new_now) = timestamp.parse_rfc3339("2025-04-13T01:33:46.382Z")
fake_clock.set_now(clock, new_now)

fake_clock.now(clock)
|> birl.to_iso8601
|> should.equal(birl.to_iso8601(new_now))
|> timestamp.to_rfc3339(calendar.utc_offset)
|> should.equal(timestamp.to_rfc3339(new_now, calendar.utc_offset))
}

pub fn fake_clock_advance_test() {
let assert Ok(now) = birl.parse("2024-04-13T01:33:46.382Z")
let assert Ok(now) = timestamp.parse_rfc3339("2024-04-13T01:33:46.382Z")
let clock = fake_clock.new_at(now)

fake_clock.advance(clock, duration.days(3))
fake_clock.advance(clock, duration.hours(3 * 24))
fake_clock.now(clock)
|> birl.to_iso8601
|> timestamp.to_rfc3339(calendar.utc_offset)
|> should.equal("2024-04-16T01:33:46.382Z")

fake_clock.advance(clock, duration.weeks(6))
fake_clock.advance(clock, duration.hours(6 * 7 * 24))
fake_clock.now(clock)
|> birl.to_iso8601
|> timestamp.to_rfc3339(calendar.utc_offset)
|> should.equal("2024-05-28T01:33:46.382Z")

fake_clock.advance(clock, duration.months(9))
fake_clock.advance(clock, duration.hours(9 * 30 * 24))
fake_clock.now(clock)
|> birl.to_iso8601
|> timestamp.to_rfc3339(calendar.utc_offset)
|> should.equal("2025-02-22T01:33:46.382Z")
}