struct Duration

Overview

The Duration type represents calendar months, calendar days, and monotonic time spans, allowing for more precise temporal math.

Defined in:

duration.cr
parser/iso8601.cr
pg.cr

Constant Summary

VERSION = "0.1.0"

Constructors

Class Method Summary

Instance Method Summary

Constructor Detail

def self.between(earlier : Time, later : Time) : self #

Get the Duration between earlier and later. This doesn't just return the nanoseconds-based time between the two timestamps the way that latest - earliest does. Instead, it calculates how many months and days are also in between, then takes the nanoseconds.

now = Time.utc
before = now - 1.month

duration = Duration.between(before, now)
# => Duration(@months=1, @days=0, @nanoseconds=0)

def self.new(month_span : Time::MonthSpan, span : Time::Span) #

Instantiate a Duration from both a Time::MonthSpan and a Time::Span.

Duration.new(5.seconds)
# => Duration(@months=0, @days=0, @nanoseconds=5000000000)

NOTE While you can get months and monotonic time, there is no way to get calendar days from this constructor.


def self.new(span : Time::Span) #

Instantiate a Duration from a Time::Span.

Duration.new(5.seconds)
# => Duration(@months=0, @days=0, @nanoseconds=5000000000)

def self.new(month_span : Time::MonthSpan) #

Instantiate a Duration from a Time::MonthSpan.

Duration.new(6.months)
# => Duration(@months=6, @days=0, @nanoseconds=0)

def self.new(*, years : Int32 = 0, months : Int32 = 0, weeks : Int64 = 0, days : Int32 = 0, hours : Int64 = 0_i64, minutes : Int64 = 0_i64, seconds : Int64 = 0_i64, milliseconds : Int64 = 0_i64, microseconds : Int64 = 0_i64, nanoseconds : Int64 = 0_i64) #

Class Method Detail

def self.parse_iso8601(string : String) #

Parse ISO8601 duration strings like "P3Y6M4DT12H30M5S" into Duration instances.

# 3 years, 6 months, 4 days, 12 hours, 30 minutes, 5.5 seconds
Duration.parse_iso8601("P3Y6M4DT12H30M5.5S")
# => Duration(@months=42, @days=4, @nanoseconds=45005500000000)

The parser is incredibly efficient and performs no heap allocations.


Instance Method Detail

def *(factor : Int) : self #

Multiplies this Duration by the given factor.


def +(other : Time::Span | Time::MonthSpan) : self #

Add a Time::Span a Time::MonthSpan from the crystal standard library to this Duration. The Time::Span will be added to the monotonic portion of this Duration and the Time::MonthSpan will be added to the #months portion.

Duration.new(years: 1) + 1.month + 1.hour
# => Duration(@months=13, @days=0, @nanoseconds=3600000000000)

def +(other : self) : self #

Returns the sum of two Duration instances.


def -(other : Time::Span | Time::MonthSpan) : self #

Subtract a Time::Span or Time::MonthSpan (from the crystal standard library) to this Duration. The Time::Span will be subtracted from the monotonic portion of this Duration and the Time::MonthSpan will be subtracted from the #months portion.


def -(other : self) : self #

Returns the difference between two Duration instances.


def - : self #

def //(factor : Int) : self #

Divides this Durtation by the given scalar. Note that only integer division is supported.


def ago(location = Time::Location.local) #

Returns the time that this Duration represents before the current local time.

1.calendar_day.ago

def before(time : Time) #

Returns the time that this Duration represents before the given time.

previous_run = 1.calendar_day.before(next_scheduled_run)

def days : Int32 #

def from(time : Time) #

Returns the time that this Duration represents from the given time.

next_bill_at = 1.calendar_month.from(subscription.last_billed_at)

def from_now(location = Time::Location.local) #

Returns the time that this Duration represents from the current local time.

1.calendar_day.from_now

def hours : Float64 #

Returns monotonic hours, including the fractional part.

Duration.new(hours: 3, minutes: 30).hours # => 3.5

def microseconds : Float64 #

Returns monotonic microseconds, including the fractional part.

Duration.new(nanoseconds: 15_500).microseconds # => 15.5

def milliseconds : Float64 #

Returns monotonic milliseconds, including the fractional part.

Duration.new(microseconds: 15_500).milliseconds # => 15.5

def minutes : Float64 #

Returns monotonic minutes, including the fractional part.

Duration.new(minutes: 3, seconds: 30).minutes # => 3.5

def months : Int32 #

def nanoseconds : Int64 #

def seconds : Float64 #

Returns monotonic seconds, including the fractional part.

Duration.new(milliseconds: 15_500).seconds # => 15.5

def sign #

def to_iso8601(io : IO) : Nil #

def to_iso8601 : String #

Output an ISO8601 representation of this Duration to the given IO


def to_month_span #

Return the month portion of this Duration as a Crystal stdlib Time::MonthSpan instance.


def to_postgres(io) : Nil #

def to_postgres #

def to_span(include_days = false) #

Return the monotonic portion of this Duration as a Crystal stdlib Time::Span instance.

NOTE Since the Crystal stdlib has no representation of calendar days, it is not currently possible to incorporate the concept of calendar days. If you are comfortable with approximating the number of days as 24 monotonic hours you can pass include_days: true, however keep in mind that this may return an incorrect value when performing arithmetic on a Duration and a Time crosses a daylight savings boundary.


def weeks : Float64 #

Returns the number of calendar weeks represented by this Duration, including the fractional part

Duration.new(days: 45).weeks # => 6.428571428571429

def years : Float64 #

Returns the number of calendar years represented by this Duration, including the fractional part

Duration.new(months: 45).years # => 3.75

def zero? #

Returns true if this Duration does not measure any time at all, false otherwise.