Fuzion Logo
fuzion-lang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

time/duration.fz


# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation.  If not, see <https://www.gnu.org/licenses/>.


# -----------------------------------------------------------------------
#
#  Tokiwa Software GmbH, Germany
#
#  Source code of Fuzion standard library feature time.duration
#
#  Author: Fridtjof Siebert (siebert@tokiwa.software)
#
# -----------------------------------------------------------------------

# time.duration -- value representing a duration, i.e., a time span
#
# This is intended for high precision time specification and measurement, it
# uses a time resolution of 1ns.
#
# The maximum value is about 580 years, so this is not intended for use in
# calendars that may require time spans exceeding several centuries or millennia,
# nor astrological time spans.
#
module:public duration (

  # the duration in nano seconds
  #
  public nanos u64
  )
  : time.period,
    property.orderable,
    property.hashable

is

  # For `duration`, this feature redefined from `period` will just return an equal `duration`
  # like `duration.this`.
  #
  public redef fixed as_duration time.duration
  =>
    # NYI: UNDER DEVELOPMENT: #5595: Once `time` is declared `final` or similar, this should work:
    #
    #   duration.this
    time.duration nanos


  # is this period infinite, i.e., it never ends?
  #
  public redef is_infinity bool
  =>
    false


  # this duration in micro seconds, omitting fractional part
  #
  public micros u64 => nanos / time_unit.?s.in_ns

  # this duration in milli seconds, omitting fractional part
  #
  public millis u64 => nanos / time_unit.ms.in_ns

  # this duration in whole seconds, omitting fractional part
  #
  public seconds u64 => nanos / time_unit.s.in_ns

  # this duration in whole minutes, omitting fractional part
  #
  public minutes u64 => nanos / time_unit.m.in_ns

  # this duration in whole hours, omitting fractional part
  #
  public hours u64 => nanos / time_unit.h.in_ns

  # this duration in whole days, omitting fractional part
  #
  public days u64 => nanos / time_unit.d.in_ns

  # this duration in whole weeks, omitting fractional part
  #
  public weeks u64 => nanos / time_unit.w.in_ns

  # this duration in whole Julian years, omitting fractional part
  #
  public years u64 => nanos / time_unit.a.in_ns


  # this duration and another one combined
  #
  public infix + (other duration) duration
  pre
    safety: nanos +! other.nanos
  =>
    duration (nanos + other.nanos)


  # this duration minus another duration
  #
  public fixed infix - (other duration) duration
  pre
    safety: duration.this >= other
  =>
    duration (nanos - other.nanos)


  # this duration multiplied by factor n
  #
  public redef infix * (n u64) time.duration
  =>
    time.duration nanos*n


  # this duration multiplied by factor f
  #
  public times(f f64) time.duration
  =>
    time.duration (nanos.as_f64 * f).as_i64.as_u64


  # this duration divided by duration other, rounding down
  #
  public infix / (other duration.this) u64
  =>
    nanos / other.nanos


  # Returns a compact string representation of this duration using
  # a short unit name without padding.
  #
  # The unit is determined by `unit_for_as_string`, preferring the
  # largest unit whose integer part still contains at least two digits.
  #
  # The representation is not exact. Fractional parts are omitted.
  #
  # Example:
  #
  #     say "'$(time.duration.h 3 .as_string)'"
  #     # Output: '180m'
  #
  public redef as_string String =>
    as_string unit_for_as_string false


  # Returns a compact string representation of this duration using
  # a short unit name with left-padded output for alignment.
  #
  # The unit is determined by `unit_for_as_string`, preferring the
  # largest unit whose integer part still contains at least two digits.
  #
  # The representation is not exact. Fractional parts are omitted.
  #
  # Example:
  #
  #     say "'$(time.duration.h 3 .as_string_pad)'"
  #     # Output: ' 180m'
  #
  public as_string_pad String =>
    as_string unit_for_as_string true


  # Returns a string representation of this duration using
  # a long unit name without padding.
  #
  # The unit is determined by `unit_for_as_string`, preferring the
  # largest unit whose integer part still contains at least two digits.
  #
  # The representation is not exact. Fractional parts are omitted.
  #
  # Example:
  #
  #     say "'$(time.duration.h 3 .as_string_long)'"
  #     # Output: '180 min'
  #
  public as_string_long String =>
    as_string_long unit_for_as_string


  # Returns a string representation of this duration using
  # the supplied unit and its short name without padding.
  #
  # The representation is not exact. Fractional parts are omitted.
  #
  # Example:
  #
  #     say "'$(time.duration.h 3 .as_string time.time_unit.s)'"
  #     # Output: '10800s'
  #
  public as_string(u time.time_unit) String =>
    as_string u false

  # Returns a string representation of this duration using
  # the supplied unit and its short name.
  #
  # The representation is not exact. Fractional parts are omitted.
  #
  # When `pad` is true, the numeric value is left-padded to four digits.
  #
  as_string(u time.time_unit, pad bool) String =>
    n := $(nanos / u.in_ns)
    "$(pad ? n.pad_left 4 : n)$(u.short_name)"


  # Returns a string representation of this duration using
  # the supplied unit and its long name without padding.
  #
  # The representation is not exact. Fractional parts are omitted.
  #
  # Example:
  #
  #     say "'$(time.duration.h 3 .as_string_long time.time_unit.s)'"
  #     # Output: '10800 sec'
  #
  public as_string_long(u time.time_unit) String =>
    "$(nanos / u.in_ns) $(u.name)"


  # Determines the unit for compact string representation.
  #
  # Prefers larger units, but keeps at least two integer digits so
  # values such as "0h" or "2h" are avoided in favor of "59m" or "120m".
  #
  public unit_for_as_string time.time_unit =>
    for
      x := time.time_unit.ns, nx.or_panic
      nx := x.larger
    while nx >>? (u -> nanos / u.in_ns >= 10) else
      x


  # total order
  #
  public fixed redef type.lteq(a, b time.duration) bool =>
    u64.lteq a.nanos b.nanos


  # create hash code from a duration
  #
  public redef type.hash_code(d duration.this) u64 =>
    d.nanos


  # max value for a duration given in nanoseconds
  public type.max_duration_nanos   u64 => u64.max

  # max value for a duration given in microseconds
  public type.max_duration_micros  u64 => u64.max / time.time_unit.?s.in_ns

  # max value for a duration given in milliseconds
  public type.max_duration_millis  u64 => u64.max / time.time_unit.ms.in_ns

  # max value for a duration given in seconds
  public type.max_duration_seconds u64 => u64.max / time.time_unit.s.in_ns

  # max value for a duration given in minutes
  public type.max_duration_minutes u64 => u64.max / time.time_unit.m.in_ns

  # max value for a duration given in hours
  public type.max_duration_hours   u64 => u64.max / time.time_unit.h.in_ns

  # max value for a duration given in days
  public type.max_duration_days    u64 => u64.max / time.time_unit.d.in_ns

  # max value for a duration given in weeks
  public type.max_duration_weeks   u64 => u64.max / time.time_unit.w.in_ns

  # max value for a duration given in years
  public type.max_duration_years   u64 => u64.max / time.time_unit.a.in_ns


  # create duration of n ns
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.ns (n u64) time.duration
  pre
    debug: n ? max_duration_nanos
  => time.duration n


  # create duration of n ?s
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.?s (n u64) time.duration
  pre
    debug: n ? max_duration_micros
  => time.duration n*time_unit.?s.in_ns


  # create duration of n ms
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.ms (n u64) time.duration
  pre
    debug: n ? max_duration_millis
  => time.duration n*time_unit.ms.in_ns


  # create duration of n seconds
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.s (n u64) time.duration
  pre
    debug: n ? max_duration_seconds
  => time.duration n*time_unit.s.in_ns


  # create duration of n seconds
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.seconds (n u64) time.duration
  pre
    debug: n ? max_duration_seconds
  => s n


  # create duration of n min
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.min (n u64) time.duration
  pre
    debug: n ? max_duration_minutes
  => time.duration n*time_unit.m.in_ns


  # create duration of n min
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.minutes (n u64) time.duration
  pre
    debug: n ? max_duration_minutes
  => min n


  # create duration of n hours
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.h (n u64) time.duration
  pre
    debug: n ? max_duration_hours
  => time.duration n*time.time_unit.h.in_ns


  # create duration of n hours
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.hours (n u64) time.duration
  pre
    debug: n ? max_duration_hours
  => h n


  # create duration of n days
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.days  (n u64) time.duration
  pre
    debug: n ? max_duration_days
  => time.duration n*time.time_unit.d.in_ns


  # create duration of n weeks
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.weeks (n u64) time.duration
  pre
    debug: n ? max_duration_weeks
  => time.duration n*time.time_unit.w.in_ns


  # create duration of n years
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.a (n u64) time.duration
  pre
    debug: n ? max_duration_years
  => time.duration n*time.time_unit.a.in_ns


  # create duration of n years
  #
  # NYI: Turn this into a 'postfix' call, see https://fuzion-lang.dev/design/postfix_calls
  #
  public type.years (n u64) time.duration
  pre
    debug: n ? max_duration_years
  => a n


  # the zero duration, representing a time span of zero
  #
  public type.zero time.duration => time.duration 0


  # the maximum duration
  #
  public type.max time.duration => time.duration.ns time.duration.max_duration_nanos

last changed: 2026-07-15