std.time.DateTime
class pub DateTime
An object representing the current system time.
Internally the time is represented as the number of seconds since the Unix epoch, excluding leap seconds.
DateTime
is based on the Gregorian calendar, and doesn't support additional
calendars such as the Julian calendar.
If you want to measure the duration between two events, it's best to use the
Instant
type, as it's not affected by external factors such as clock
adjustments and leap seconds.
Fields
year
let pub @year: Int
The year.
month
let pub @month: Int
The month, from 1
to 12
.
day
let pub @day: Int
The day, from 1
to 31
.
hour
let pub @hour: Int
The hour, from 0
to 23
.
minute
let pub @minute: Int
The minute, from 0
to 59
.
second
let pub @second: Int
The second, from 0
to 59
.
sub_second
let pub @sub_second: Float
The sub seconds.
utc_offset
let pub @utc_offset: Int
The UTC offset (in seconds).
Static methods
from_timestamp
Show source codeHide source code
fn pub static from_timestamp[T: ToFloat](
time: ref T,
utc_offset: Int,
) -> DateTime {
# This implementation is based on the algorithms as described on
# http://howardhinnant.github.io/date_algorithms.html, specifically the
# `civil_from_days()` algorithm.
#
# To be truly honest, at the time of writing I didn't fully understand the
# algorithm, and reading through the linked article made my head spin. But
# it works, so ship it!
#
# Important note: this algorithm works because Inko implements integer
# divisions as floored divisions (like e.g. Python and Ruby), instead of
# rounding towards zero (like Rust and C).
let time = time.to_float
let epoch_secs = time.to_int + utc_offset
let epoch_days = (epoch_secs / SECS_PER_DAY) + 719_468
let era = if epoch_days >= 0 { epoch_days } else { epoch_days - 146_096 }
/ 146_097
let doe = epoch_days - (era * 146_097)
let yoe = (doe - (doe / 1460) + (doe / 36_524) - (doe / 146_096)) / 365
let doy = doe - ((365 * yoe) + (yoe / 4) - (yoe / 100))
let mp = ((5 * doy) + 2) / 153
let day = doy - ((153 * mp) + 2 / 5) + 1
let month = if mp < 10 { mp + 3 } else { mp - 9 }
let mut year = yoe + (era * 400)
if month <= 2 { year += 1 }
# The number of seconds since the start of the day.
let mut day_secs = epoch_secs - ((epoch_secs / SECS_PER_DAY) * SECS_PER_DAY)
let second = day_secs % 60
let minute = (day_secs % SECS_PER_HOUR) / 60
let hour = day_secs / SECS_PER_HOUR
DateTime(
year: year,
month: month,
day: day,
hour: hour,
minute: minute,
second: second,
sub_second: time.fractional,
utc_offset: utc_offset,
)
}
fn pub static from_timestamp[T: ToFloat](time: ref T, utc_offset: Int) -> DateTime
Returns a new DateTime
from a Unix timestamp and UTC offset.
The time
argument is the number of seconds since or before the Unix epoch.
Example
import std.time (DateTime)
DateTime.from_timestamp(time: 1661546853, utc_offset: 0).year # => 2022
new
Show source codeHide source code
fn pub static new -> DateTime {
from_timestamp(inko_time_system, inko_time_system_offset as Int)
}
fn pub static new -> DateTime
Returns a new DateTime
representing the current time using the local
timezone.
Examples
Getting the current time:
import std.time (DateTime)
DateTime.new
utc
Show source codeHide source code
fn pub static utc -> DateTime {
from_timestamp(time: inko_time_system, utc_offset: 0)
}
fn pub static utc -> DateTime
Returns a new DateTime
representing the current time using UTC as the
timezone.
Examples
Getting the current time in UTC:
import std.time (DateTime)
DateTime.utc
Instance methods
!=
Show source codeHide source code
fn pub !=(other: T) -> Bool {
(self == other).false?
}
fn pub !=(other: T) -> Bool
Returns true
if self
and the given object are not equal to each other.
+
Show source codeHide source code
fn pub +(other: ref Duration) -> DateTime {
let timestamp = to_float + other.to_secs
DateTime.from_timestamp(timestamp, utc_offset: @utc_offset)
}
fn pub +(other: ref Duration) -> DateTime
Adds the given object to self
.
-
Show source codeHide source code
fn pub -(other: ref Duration) -> DateTime {
let timestamp = to_float - other.to_secs
DateTime.from_timestamp(timestamp, utc_offset: @utc_offset)
}
fn pub -(other: ref Duration) -> DateTime
Subtracts the given object from self
.
<
Show source codeHide source code
fn pub <(other: ref T) -> Bool {
match cmp(other) {
case Less -> true
case _ -> false
}
}
fn pub <(other: ref T) -> Bool
Returns true
if self
is lower than the given argument.
<=
Show source codeHide source code
fn pub <=(other: ref T) -> Bool {
match cmp(other) {
case Less or Equal -> true
case _ -> false
}
}
fn pub <=(other: ref T) -> Bool
Returns true
if self
is lower than or equal to the given argument.
==
Show source codeHide source code
fn pub ==(other: ref DateTime) -> Bool {
@year == other.year
and @month == other.month
and @day == other.day
and @hour == other.hour
and @minute == other.minute
and @second == other.second
and @sub_second == other.sub_second
and @utc_offset == other.utc_offset
}
fn pub ==(other: ref DateTime) -> Bool
Returns true
if self
and the given object are equal to each other.
This operator is used to perform structural equality. This means two objects residing in different memory locations may be considered equal, provided their structure is equal. For example, two different arrays may be considered to have structural equality if they contain the exact same values.
>
Show source codeHide source code
fn pub >(other: ref T) -> Bool {
match cmp(other) {
case Greater -> true
case _ -> false
}
}
fn pub >(other: ref T) -> Bool
Returns true
if self
is greater than the given argument.
>=
Show source codeHide source code
fn pub >=(other: ref T) -> Bool {
match cmp(other) {
case Greater or Equal -> true
case _ -> false
}
}
fn pub >=(other: ref T) -> Bool
Returns true
if self
is equal to or greater than the given argument.
clone
Show source codeHide source code
fn pub clone -> DateTime {
DateTime(
year: @year,
month: @month,
day: @day,
hour: @hour,
minute: @minute,
second: @second,
sub_second: @sub_second,
utc_offset: @utc_offset,
)
}
fn pub clone -> DateTime
Creates a clone of self
.
cmp
Show source codeHide source code
fn pub cmp(other: ref DateTime) -> Ordering {
to_float.cmp(other.to_float)
}
fn pub cmp(other: ref DateTime) -> Ordering
Returns the ordering between self
and the given argument.
The returned value should be as follows:
a == b
:Ordering.Equal
a > b
:Ordering.Greater
a < b
:Ordering.Less
day_of_week
Show source codeHide source code
fn pub day_of_week -> Int {
# January 1st, 1970 (our anchor date) was on a Thursday. We add 3 so that
# Monday (3 days before Thursday) becomes the anchor date.
#
# We later on add 1 since the % operator will return 0 for Monday (since its
# the first value in the range), but week days range from 1 to 7; not 0 to
# 6.
#
# The following table should help illustrate this:
#
# | Date | Day of week | days_since_unix_epoch
# |:-----------|:------------|:----------------------
# | 1969-12-29 | Monday | -3
# | 1969-12-30 | Tuesday | -2
# | 1969-12-31 | Wednesday | -1
# | 1970-01-01 | Thursday | 0
# | 1970-01-02 | Friday | 1
# | 1970-01-03 | Saturday | 2
# | 1970-01-04 | Sunday | 3
#
# For these dates, the calculations would be as follows:
#
# | Date | Calculation | Simplified | Return value
# |:-----------|:-------------------|:------------|:------------
# | 1969-12-29 | ((-3 + 3) % 7) + 1 | (0 % 7) + 1 | 1
# | 1969-12-30 | ((-2 + 3) % 7) + 1 | (1 % 7) + 1 | 2
# | 1969-12-31 | ((-1 + 3) % 7) + 1 | (2 % 7) + 1 | 3
# | 1970-01-01 | ((0 + 3) % 7) + 1 | (3 % 7) + 1 | 4
# | 1970-01-02 | ((1 + 3) % 7) + 1 | (4 % 7) + 1 | 5
# | 1970-01-03 | ((2 + 3) % 7) + 1 | (5 % 7) + 1 | 6
# | 1970-01-04 | ((3 + 3) % 7) + 1 | (6 % 7) + 1 | 7
days_since_unix_epoch + 3 % DAYS_PER_WEEK + 1
}
fn pub day_of_week -> Int
Returns the day of the week from 1 to 7.
Per ISO 8601 the first day of the week starts on Monday, not Sunday.
day_of_year
Show source codeHide source code
fn pub day_of_year -> Int {
let days = if leap_year? { LEAP_DAYS } else { NORMAL_DAYS }
days.get(@month - 1) + @day
}
fn pub day_of_year -> Int
Returns the day of the year from 1 to 366 for leap years, and from 1 to 365 for regular years.
days_since_unix_epoch
Show source codeHide source code
fn pub days_since_unix_epoch -> Int {
let year = if @month <= 2 { @year - 1 } else { @year }
let month = @month
let era = if year >= 0 { year } else { year - 399 } / 400
let yoe = year - (era * 400)
let doy = (((153 * if month > 2 { month - 3 } else { month + 9 }) + 2) / 5)
+ @day
- 1
let doe = (yoe * 365) + (yoe / 4) - (yoe / 100) + doy
(era * 146_097) + doe - 719_468
}
fn pub days_since_unix_epoch -> Int
Returns the number of days between self
and the Unix epoch.
The returned Int
is negative if self
is before the Unix epoch, and
positive for a value that is on or after the Unix epoch.
fmt
Show source codeHide source code
fn pub fmt(formatter: mut Formatter) {
let sign = if @utc_offset > 0 { '+' } else { '-' }
let offset = if @utc_offset == 0 {
' UTC'
} else {
let hh = (@utc_offset / SECS_PER_HOUR).to_string.pad_start(
with: '0',
chars: 2,
)
let mm = (@utc_offset % SECS_PER_HOUR / 60).to_string.pad_start(
with: '0',
chars: 2,
)
' ${sign}${hh}${mm}'
}
let year = @year.to_string.pad_start(with: '0', chars: 4)
let month = @month.to_string.pad_start(with: '0', chars: 2)
let day = @day.to_string.pad_start(with: '0', chars: 2)
let hour = @hour.to_string.pad_start(with: '0', chars: 2)
let min = @minute.to_string.pad_start(with: '0', chars: 2)
let secs = @second.to_string.pad_start(with: '0', chars: 2)
formatter.write('${year}-${month}-${day} ${hour}:${min}:${secs}${offset}')
}
fn pub fmt(formatter: mut Formatter)
Formats self
in a human-readable format for debugging purposes.
leap_year?
Show source codeHide source code
fn pub leap_year? -> Bool {
let year = @year
(year % 4) == 0 and ((year % 100) > 0 or (year % 400) == 0)
}
fn pub leap_year? -> Bool
Returns true
if the current year is a leap year.
to_float
Show source codeHide source code
fn pub to_float -> Float {
to_int.to_float + @sub_second
}
fn pub to_float -> Float
Returns the timestamp since the Unix epoch, the including fractional seconds.
to_int
Show source codeHide source code
fn pub to_int -> Int {
let days = days_since_unix_epoch
let days_sec = days.absolute * SECS_PER_DAY
let time_sec = (@hour * SECS_PER_HOUR) + (@minute * SECS_PER_MIN) + @second
let timestamp = if days < 0 {
0 - (days_sec - time_sec)
} else {
days_sec + time_sec
}
# Timestamps are always in UTC, not in the local time.
timestamp - @utc_offset
}
fn pub to_int -> Int
Returns the number of seconds since the Unix epoch in UTC.
This value will be negative if self
is a DateTime
before the Unix
epoch.
to_utc
Show source codeHide source code
fn pub to_utc -> DateTime {
DateTime.from_timestamp(time: to_float, utc_offset: 0)
}
fn pub to_utc -> DateTime
Converts the DateTime
to another DateTime
that uses UTC as the
timezone.
utc?
Show source codeHide source code
fn pub utc? -> Bool {
@utc_offset == 0
}
fn pub utc? -> Bool
Returns true
if UTC is used.
Implemented traits
Clone
impl Clone[DateTime] for DateTime
Compare
impl Compare[DateTime] for DateTime
Equal
impl Equal[ref DateTime] for DateTime
ToFloat
impl ToFloat for DateTime
Format
impl Format for DateTime
ToInt
impl ToInt for DateTime
Add
impl Add[Duration, DateTime] for DateTime
Subtract
impl Subtract[Duration, DateTime] for DateTime