tempo/time

Functions to use with the Time type in Tempo. The time values are wall time values unless explicitly stated otherwise.

Examples

import tempo/time

pub fn is_past_5pm() {
  tempo.is_time_later(than: time.literal("17:00"))
}
import tempo/time

pub fn get_enthusiastic_time() {
  time.literal("13:42")
  |> time.format(tempo.CustomTime(
    "[The hour is:] HH, [wow! And even better the minute is:] mm!"
  ))
  // -> "The hour is: 13, wow! And even better the minute is: 42!"
}

Calendar and range of valid times

A Time is a time of day on its own, with no date attached, so nothing in this module depends on the Gregorian calendar or on any other, and there is no range of valid dates.

The range of valid times is 00:00:00.000000 through 23:59:59.999999, with two additions allowed by ISO 8601:

Sub-second precision is microseconds, so the microsecond component runs from 0 to 999_999. Values with more precision than that are rejected rather than rounded.

Types

pub type Boundary {
  Boundary(time: tempo.Time, inclusive: Bool)
}

Constructors

Values

pub fn add(
  a: tempo.Time,
  duration b: duration.Duration,
) -> tempo.Time

Adds a duration to a time.

Example

time.literal("08:42:53")
|> time.add(duration.mintues(36))
// -> time.literal("09:18:53")
pub fn compare(a: tempo.Time, to b: tempo.Time) -> order.Order

Compares two time values.

Example

time.literal("13:42:11")
|> time.compare(to: time.literal("13:42:11"))
// -> order.Eq
time.literal("15:32:01")
|> time.compare(to: time.literal("13:42:11"))
// -> order.Gt
time.literal("13:10:11")
|> time.compare(to: time.literal("13:42:11"))
// -> order.Lt
pub fn describe_out_of_bounds_error(
  error: error.TimeOutOfBoundsError,
) -> String

Converts a time out of bounds error to a human readable error message.

Example

time.new(23, 59, 60)
|> snag.map_error(with: time.describe_out_of_bounds_error)
// -> snag.error("Second out of bounds in time: 60")
pub fn describe_parse_error(
  error: error.TimeParseError,
) -> String

Converts a time parse error to a human readable error message.

Example

time.parse("13 42 11", "HH:mm:ss")
|> snag.map_error(with: time.describe_parse_error)
// -> snag.error("Invalid time format: "13 42 11"")
pub fn difference(
  from a: tempo.Time,
  to b: tempo.Time,
) -> duration.Duration

Gets the difference between two times as a duration. Always prefer using duration.start_monotonic and duration.stop_monotonic to record live time passing, as it is more precise.

Example

time.literal("23:42:11.435")
|> time.difference(from: time.literal("23:42:09.743"))
|> duration.as_milliseconds
// -> 1692
time.literal("13:30:11")
|> time.difference(from: time.literal("13:55:13"))
|> duration.as_minutes
// -> -25
pub fn difference_abs(
  a: tempo.Time,
  from b: tempo.Time,
) -> duration.Duration

Gets the absolute difference between two times as a duration.

Example

time.literal("23:42:11.435")
|> time.difference_abs(from: time.literal("23:42:09.743"))
|> duration.as_milliseconds
// -> 1692
time.literal("13:30:11")
|> time.difference_abs(from: time.literal("13:55:13"))
|> duration.as_minutes
// -> 25
pub const end_of_day: tempo.Time

The end of the last second of the day.

Example

time.end_of_day
|> time.to_string
// "24:00:00.000000"
tempo.DateTime(date.literal("2024-06-21"), time.end_of_day, offset.utc)
|> datetime.to_string
// "2024-06-21T24:00:00.000000Z"
pub fn format(
  time: tempo.Time,
  in format: tempo.TimeFormat,
) -> String

Formats a time value using the provided format.

Example

time.literal("13:42:11")
|> time.format(tempo.ISO8601TimeMilli)
// -> "13:42:11.000"
time.literal("13:42:11.314")
|> time.format("h:mm A")
// -> "1:42 PM"
time.literal("09:02:01.014920202")
|> time.format("HH:mm:ss SSS SSSS SSSSS")
// -> "09:02:01 014 014920 014920202"
naive_datetime.literal("13:02:01")
|> naive_datetime.format("H HH h hh m mm s ss a A [An ant]")
// -------------------> "13 13 1 01 2 02 1 01 pm PM An ant"
pub fn from_calendar_time_of_day(
  time: calendar.TimeOfDay,
) -> Result(tempo.Time, error.TimeOutOfBoundsError)

Converts a core gleam time time of day to a tempo time.

pub fn from_duration(duration: duration.Duration) -> tempo.Time

Converts a duration to the equivalent time of day, assuming the duration epoch is “00:00:00”. Durations longer than 24 hours will be wrapped to fit within a 24 hour representation.

Example

duration.seconds(58)
|> time.from_duration
|> time.to_second_precision
|> time.to_string
// -> "00:00:58"
duration.minutes(17)
|> time.from_duration
|> time.to_string
// -> "00:17:00.000000000"
duration.hours(25)
|> time.from_duration
|> time.to_string
// -> "01:00:00.000000000"
duration.microseconds(-3_000_000)
|> time.from_duration
|> time.to_string
// -> "23:59:57.000000"
pub fn from_string(
  time_str: String,
) -> Result(tempo.Time, error.TimeParseError)

Converts a string to a time value. Accepted formats are hh:mm:ss.s, hhmmss.s, hh:mm:ss, hhmmss, hh:mm, or hhmm.

Valid times run from 00:00:00 through 23:59:59, plus 24:00:00 as the end-of-day marker and 23:59:60 as a leap second. A sub-second value finer than microseconds is rejected rather than rounded.

Example

time.from_string("00:00:00.000300")
// -> Ok(time.literal("00:00:00.000300"))
time.from_string("34:54:16")
// -> Error(tempo_error.TimeOutOfBounds)
pub fn from_tuple(
  time: #(Int, Int, Int),
) -> Result(tempo.Time, error.TimeOutOfBoundsError)

Converts a tuple of hours, minutes, and seconds to a time value. Useful for using with another time library.

Example

#(13, 42, 11)
|> time.from_tuple
// -> time.literal("13:42:11")
pub fn from_tuple_microsecond(
  time: #(Int, Int, Int, Int),
) -> Result(tempo.Time, error.TimeOutOfBoundsError)

Converts a tuple of hours, minutes, seconds, and microseconds to a time value. Useful for using with another time library.

Example

#(13, 42, 11, 872000)
|> time.from_tuple_microsecond
// -> time.literal("13:42:11.872")
pub fn get_hour(time: tempo.Time) -> Int

Gets the hour value of a time.

Example

time.literal("13:42:11")
|> time.get_hour
// -> 13
pub fn get_microsecond(time: tempo.Time) -> Int

Gets the microsecond value of a time.

Example

time.literal("13:42:11.123")
|> time.get_microsecond
// -> 123000
pub fn get_minute(time: tempo.Time) -> Int

Gets the minute value of a time.

Example

time.literal("13:42:11")
|> time.get_minute
// -> 42
pub fn get_second(time: tempo.Time) -> Int

Gets the second value of a time.

Example

time.literal("13:42:11")
|> time.get_second
// -> 11
pub fn is_between(
  time: tempo.Time,
  start: Boundary,
  and end: Boundary,
) -> Bool

Checks if a time is between two boundaries.

Example

time.literal("13:42:11")
|> time.is_between(
    Boundary(time.literal("05:00:00"), inclusive: True), 
    and: Boundary(time.literal("15:00:00"), inclusive: False),
  )
// -> True
pub fn is_earlier(a: tempo.Time, than b: tempo.Time) -> Bool

Checks if the first time is earlier than the second time.

Example

time.literal("13:42:11")
|> time.is_earlier(than: time.literal("13:42:12"))
// -> True
time.literal("13:42:11")
|> time.is_earlier(than: time.literal("13:42:11"))
// -> False
time.literal("13:22:15")
|> time.is_earlier(than: time.literal("07:42:11"))
// -> False
pub fn is_earlier_or_equal(
  a: tempo.Time,
  to b: tempo.Time,
) -> Bool

Checks if the first time is earlier or equal to the second time.

Example

time.literal("13:42:11")
|> time.is_earlier_or_equal(to: time.literal("13:42:12"))
// -> True
time.literal("13:42:11")
|> time.is_earlier_or_equal(to: time.literal("13:42:11.000"))
// -> True
time.literal("13:22:15")
|> time.is_earlier_or_equal(to: time.literal("07:42:12"))
// -> False
pub fn is_equal(a: tempo.Time, to b: tempo.Time) -> Bool

Checks if the first time is equal to the second time.

Example

time.literal("13:42:11.000")
|> time.is_equal(to: time.literal("13:42:11"))
// -> True
time.literal("13:42:11.002")
|> time.is_equal(to: time.literal("13:42:11"))
// -> False
pub fn is_later(a: tempo.Time, than b: tempo.Time) -> Bool

Checks if the first time is later than the second time.

Example

time.literal("13:22:15")
|> time.is_later(than: time.literal("07:42:11"))
// -> True
time.literal("13:42:11")
|> time.is_later(than: time.literal("13:42:12"))
// -> False
time.literal("13:42:11")
|> time.is_later(than: time.literal("13:42:11"))
// -> False
pub fn is_later_or_equal(a: tempo.Time, to b: tempo.Time) -> Bool

Checks if the first time is earlier or equal to the second time.

Example

time.literal("13:22:15")
|> time.is_later_or_equal(to: time.literal("07:42:12"))
// -> True

```gleam
time.literal("13:42")
|> time.is_later_or_equal(to: time.literal("13:42:00.000"))
// -> True
time.literal("13:42:11")
|> time.is_later_or_equal(to: time.literal("13:42:12"))
// -> False
pub fn is_outside(
  time: tempo.Time,
  start: Boundary,
  and end: Boundary,
) -> Bool

Checks if a time is outside of two boundaries.

Example

time.literal("13:42:11")
|> time.is_outside(
    time.Boundary(time.literal("05:00:00"), inclusive: True), 
    and: time.Boundary(time.literal("15:00:00"), inclusive: False),
  )
// -> False
pub fn left_in_day(time: tempo.Time) -> tempo.Time

Converts a time to the equivalent time left in the day.

Example

time.literal("23:59:03") |> time.left_in_day
// -> time.literal("00:00:57")
time.literal("08:05:20") |> time.left_in_day
// -> time.literal("15:54:40")
pub fn literal(time: String) -> tempo.Time

Creates a new time value from a string literal, but will panic if the string is invalid. Accepted formats are hh:mm:ss.s, hhmmss.s, hh:mm:ss, hhmmss, hh:mm, or hhmm.

Useful for declaring time literals that you know are valid within your program.

Valid times run from 00:00:00 through 23:59:59, plus 24:00:00 as the end-of-day marker and 23:59:60 as a leap second. Anything else panics, including a sub-second value finer than microseconds.

Example

case 
  time.now_local() 
  |> time.is_later(than: time.literal("11:50:00")) 
{ 
  True -> "We are late!"
  False -> "No rush :)"
}
pub fn new(
  hour: Int,
  minute: Int,
  second: Int,
) -> Result(tempo.Time, error.TimeOutOfBoundsError)

Creates a new time value with second precision.

Valid times run from 00:00:00 through 23:59:59, plus 24:00:00 as the end-of-day marker and 23:59:60 as a leap second.

Example

time.new(13, 42, 11)
// -> Ok(time.literal("13:42:11"))
time.new(53, 42, 61)
// -> Error(tempo_error.TimeOutOfBounds)
pub fn new_micro(
  hour: Int,
  minute: Int,
  second: Int,
  microsecond: Int,
) -> Result(tempo.Time, error.TimeOutOfBoundsError)

Creates a new time value with microsecond precision. The microsecond component must be between 0 and 999_999, which is the finest precision this package represents.

Valid times run from 00:00:00 through 23:59:59, plus 24:00:00 as the end-of-day marker and 23:59:60 as a leap second.

Example

time.new_micro(13, 42, 11, 20)
// -> Ok(time.literal("13:42:11.000020"))
time.new_micro(13, 42, 11, 200_000)
// -> Ok(time.litteral("13:42:11.200000"))
time.new_micro(13, 42, 11, 7_500_000)
|> result.map_error(time.describe_out_of_bounds_error)
// -> Error("Subsecond value out of bounds in time: 13:42:11.7500000")
pub fn new_milli(
  hour: Int,
  minute: Int,
  second: Int,
  millisecond: Int,
) -> Result(tempo.Time, error.TimeOutOfBoundsError)

Creates a new time value with millisecond precision. The millisecond component must be between 0 and 999.

Valid times run from 00:00:00 through 23:59:59, plus 24:00:00 as the end-of-day marker and 23:59:60 as a leap second.

Example

time.new_milli(13, 42, 11, 20)
// -> Ok(time.literal("13:42:11.020"))
time.new_milli(13, 42, 11, 200)
// -> Ok(time.literal("13:42:11.200"))
time.new_milli(13, 42, 11, 7_500)
// -> Error(tempo_error.TimeOutOfBounds)
pub fn parse(
  str: String,
  in format: tempo.TimeFormat,
) -> Result(tempo.Time, error.TimeParseError)

Parses a time string in the provided format. Always prefer using this over parse_any. All parsed formats must have an hour and a second.

Values can be escaped by putting brackets around them, like “[Hello!] HH”.

Available directives: H (hour), HH (two-digit hour), h (12-hour clock hour), hh (two-digit 12-hour clock hour), m (minute), mm (two-digit minute), s (second), ss (two-digit second), SSS (millisecond), SSSS (microsecond), A (AM/PM), a (am/pm),

Example

time.parse("2024/06/08, 13:42:11", "YYYY/MM/DD")
// -> Ok(time.literal("13:42:11"))
time.parse("January 13, 2024", "MMMM DD, YYYY")
|> result.map_error(time.describe_parse_error)
// -> Error("Invlid time format: January 13, 2024")
time.parse("Hi! 12 2 am", "[Hi!] h m a")
// -> Ok(time.literal("00:02:00"))
pub fn parse_any(
  str: String,
) -> Result(tempo.Time, error.TimeParseError)

Tries to parse a given date string without a known format. It will not parse two digit years and will assume the month always comes before the day in a date. Will leave off any time offset values present.

Example

time.parse_any("2024.06.21 01:32 PM -04:00")
// -> Ok(time.literal("13:32:00"))
time.parse_any("2024.06.21")
// -> Error(tempo.ParseMissingTime)
pub fn since(
  time time: tempo.Time,
  since since: tempo.Time,
) -> duration.Duration

Returns a duration representing the time since the first time to the given time.

Example

time.literal("23:54:00")
|> time.since(time.literal("13:30:04"))
|> duration.as_hours
// -> 10
time.literal("12:30:54")
|> time.since(time.literal("22:00:00"))
|> duration.as_milliseconds
// -> 0
pub const start_of_day: tempo.Time

The first second of the day.

Example

time.start_of_day
|> time.to_string
// "00:00:00.000000"
tempo.DateTime(date.literal("2024-06-21"), time.start_of_day, offset.utc)
|> datetime.to_string
// "2024-06-21T00:00:00.000000Z"
pub fn subtract(
  a: tempo.Time,
  duration b: duration.Duration,
) -> tempo.Time

Subtracts a duration from a time.

Example

time.literal("13:42:02")
|> time.subtract(duration.hours(2))
// -> time.literal("11:42:02")
pub fn to_calendar_time_of_day(
  time: tempo.Time,
) -> calendar.TimeOfDay

Converts a tempo time to a time of day type in the core gleam time package.

pub fn to_duration(time: tempo.Time) -> duration.Duration

Converts a time to duration, assuming the duration epoch is “00:00:00”.

Example

time.literal("00:00:00.000300")
|> time.to_duration
|> duration.as_microseconds
// -> 300
time.literal("00:03:06")
|> time.to_duration 
|> duration.as_milliseconds
// -> 186_000
pub fn to_string(time: tempo.Time) -> String

Converts a time value to a string in the format hh:mm:ss.s with millisecond precision. If a different precision is needed, use the format function.

Example

time.to_string(my_time)
// -> "21:53:03.534"
pub fn to_tuple(time: tempo.Time) -> #(Int, Int, Int)

Returns a time value as a tuple of hours, minutes, and seconds. Useful for using with another time library.

Example

time.literal("13:42:11")
|> time.to_tuple
// -> #(13, 42, 11)
pub fn to_tuple_microsecond(
  time: tempo.Time,
) -> #(Int, Int, Int, Int)

Returns a time value as a tuple of hours, minutes, seconds, and microseconds. Useful for using with another time library.

Example

time.literal("13:42:11.872")
|> time.to_tuple_microsecond
// -> #(13, 42, 11, 872000)
pub fn until(
  time: tempo.Time,
  until: tempo.Time,
) -> duration.Duration

Returns a duration representing the time left from the first time until a given time.

Example

time.literal("23:54:00")
|> time.until(time.literal("23:59:04"))
|> duration.as_seconds
// -> 304
time.literal("23:59:03")
|> time.until(time.literal("22:00:00"))
|> duration.as_milliseconds
// -> 0
Search Document