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
  ) : property.orderable

is

  # this duration in micro seconds, omitting fractional part
  #
  public micros u64 => nanos / units.nanos_per_micro

  # this duration in milli seconds, omitting fractional part
  #
  public millis u64 => nanos / units.nanos_per_milli

  # this duration in whole seconds, omitting fractional part
  #
  public seconds u64 => nanos / units.nanos_per_second

  # this duration in whole minutes, omitting fractional part
  #
  public minutes u64 => nanos / units.nanos_per_minute

  # this duration in whole hours, omitting fractional part
  #
  public hours u64 => nanos / units.nanos_per_hour

  # this duration in whole days, omitting fractional part
  #
  public days u64 => nanos / units.nanos_per_day

  # this duration in whole weeks, omitting fractional part
  #
  public weeks u64 => nanos / units.nanos_per_week

  # this duration in whole Julian years, omitting fractional part
  #
  public years u64 => nanos / units.nanos_per_year


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


  # this duration multiplied by n
  #
  public infix * (n u64) duration => (duration nanos*n)


  # create a string representation of this duration. The string
  # representation is not accurate, it consists of at least two
  # and at most 4 decimal digits followed by a time unit string.
  #
  public redef as_string String =>
    f,u,_ := for
               x := units.unit_names.first.get, n0
               # NYI: BUG: : name n leads to duplicate feature declaration
               n0 in units.unit_names.drop 1
               nf := n0.0
             while (!(nf = 0 || nanos / nf < 10)) else
               x
    n := $(nanos / f)
    " "*(max 0 4-n.byte_length) + n + u


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


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

  # max value for a duration given in micros
  public type.max_duration_micros  u64 => u64.max / time.units.nanos_per_micro

  # max value for a duration given in millis
  public type.max_duration_millis  u64 => u64.max / time.units.nanos_per_milli

  # max value for a duration given in seconds
  public type.max_duration_seconds u64 => u64.max / time.units.nanos_per_second

  # max value for a duration given in minutes
  public type.max_duration_minutes u64 => u64.max / time.units.nanos_per_minute

  # max value for a duration given in hours
  public type.max_duration_hours   u64 => u64.max / time.units.nanos_per_hour

  # max value for a duration given in days
  public type.max_duration_days    u64 => u64.max / time.units.nanos_per_day

  # max value for a duration given in weeks
  public type.max_duration_weeks   u64 => u64.max / time.units.nanos_per_week

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


  # 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.units.nanos_per_micro


  # 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.units.nanos_per_milli


  # 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.units.nanos_per_second


  # 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.units.nanos_per_minute


  # 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.units.nanos_per_hour


  # 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.units.nanos_per_day


  # 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.units.nanos_per_week


  # 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.units.nanos_per_year


  # 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


# time.duration.units -- unit time defining units used in duration
#
public units is

  # factor converting nanos to nanos, just for completeness
  public nanos_per_nano   u64 => u64 1

  # factor converting micros to nanos
  public nanos_per_micro  u64 => u64 1_000

  # factor converting millis to nanos
  public nanos_per_milli  u64 => nanos_per_micro * 1_000

  # factor converting seconds to nanos
  public nanos_per_second u64 => nanos_per_milli * 1_000

  # factor converting minutes to nanos
  public nanos_per_minute u64 => nanos_per_second * 60

  # factor converting hours to nanos
  public nanos_per_hour   u64 => nanos_per_minute * 60

  # factor converting days to nanos
  public nanos_per_day    u64 => nanos_per_hour * 24

  # factor converting weeks to nanos
  public nanos_per_week   u64 => nanos_per_day * 7

  # factor converting years to nanos
  public nanos_per_year   u64 => nanos_per_second * 31_557_600


  # array of tuples consisting of the nanos_per_* conversion
  # factors and an (mostly ISO) name of the corresponding unit.
  #
  # Entries are sorted by increasing duration size.  The last
  # entry is an ((u64 0), "--end marker--").
  #
  unit_names =>
    [ (nanos_per_nano   , "ns", "ns"),
      (nanos_per_micro  , "µs", "µs"),
      (nanos_per_milli  , "ms", "ms"),
      (nanos_per_second , "s ", "sec"),
      (nanos_per_minute , "m ", "min"),
      (nanos_per_hour   , "h ", "hours"),
      (nanos_per_day    , "d ", "days"),
      (nanos_per_year   , "a ", "years"),
      ((u64 0          ), "--end marker--", "--end marker--"),
      ]

last changed: 2025-07-10