class Instant
class Instant is Cool does Real { }
An Instant is a particular moment in time measured in atomic seconds, with
fractions. It is not tied to or aware of any epoch.
An Instant can be used to create a DateTime object set to that
Instant. The pseudo-constant now returns the current time as an
Instant.
Basic math is defined for Instants (as well as Durations). Adding an
Instant to a Duration returns another Instant. Subtracting two Instants
will yield a Duration. Adding two Instants is explicitly disallowed. All
other operations with Instants are undefined.
NOTE: POSIX time, a commonly used
time standard,
does not address leap seconds, while Instant objects do, so there's some
extra machinery in the conversion methods to handle this. See methods from-posix,
to-posix, and the discussion of leap seconds below.
Methods
method from-posix
method from-posix($posix, Bool $prefer-leap-second = False)
Converts the POSIX timestamp $posix to an Instant.
If $prefer-leap-second is True, the return value will be
the first of the two possible seconds in the case of a leap second.
say DateTime.new(Instant.from-posix(1483228800, True)); # OUTPUT: «2016-12-31T23:59:60Z»
say DateTime.new(Instant.from-posix(1483228800)); # OUTPUT: «2017-01-01T00:00:00Z»
method to-posix
method to-posix()
Converts the invocant to a POSIX timestamp and returns a two
element list containing the POSIX timestamp and a Bool.
It is the inverse of method from-posix, except that the second return
value is True if *and only if* this Instant is in a leap
second.
say DateTime.new('2017-01-01T00:00:00Z').Instant.to-posix; # OUTPUT: «(1483228800 False)»
say DateTime.new('2016-12-31T23:59:60Z').Instant.to-posix; # OUTPUT: «(1483228800 True)»
method Date
method Date(Instant:D: --> Date:D)
Coerces the invocant to Date.
my $i = "/etc/passwd".IO.modified;
say $i; # OUTPUT: «Instant:1771879757.95139447»
say $i.Date; # OUTPUT: «2026-02-23»
method DateTime
method DateTime(Instant:D: --> DateTime:D)
Coerces the invocant to DateTime.
say now.DateTime; # OUTPUT: «2026-03-07T13:56:42.930951Z»
Leap Seconds
POSIX time (commonly called "Unix time") does not address leap seconds; in
other words, it assumes that the period of rotation of the Earth is a fixed
constant. Since in fact the amount of time that passes between one noon and
the next varies from day to day, we must occasionally have a 61st second in
the 60th minute of some hour; this is called a leap second, and happens at the
same time all over the world, and therefore at different times of day in
different timezones. POSIX handles this by assigning the same integer label to
two different consecutive seconds; that is, when a leap second happens,
DateTime.now.posix does not change for two whole seconds.
my Instant $i .= from-posix(1483228799);
my Duration $s = DateTime.new(1) - DateTime.new(0);
sub demo { say [$_, .posix] with DateTime.new($i + $^n * $s) }
demo(0); # OUTPUT: «[2016-12-31T23:59:59Z 1483228799]»
demo(1); # OUTPUT: «[2016-12-31T23:59:60Z 1483228800]»
demo(2); # OUTPUT: «[2017-01-01T00:00:00Z 1483228800]»
demo(3); # OUTPUT: «[2017-01-01T00:00:01Z 1483228801]»
Atomic clocks also disregard the Earth's rotation, so between 1958 when they
were first calibrated and the introduction of leap seconds in 1972,
UTC had fallen 10 seconds
behind atomic-clock time.
The numerical value of Instant follows atomic-clock time, and as of
2026 there have been 27 leap seconds recorded. This adds up to a total of 37
seconds, which is why, as of 2026, the following holds:
with now { say .Int - DateTime.new($_).posix } # OUTPUT: «37»
Future Leap Seconds
The methods that involve knowledge of leap seconds always assume that there will be no further leaps after the last leap second that the implementation knows about, which may not be the last leap second that has actually been scheduled. This means you can get different results, depending on the compiler version you're using. For example, the December 31, 2016 leap second was announced in July and shipped with Rakudo 2016.07, so 2016.06 and earlier releases won't know about it.
$ perl6-2016.06 -e 'say Instant.from-posix: 1485726595'
Instant:1485726631
$ perl6-2016.07 -e 'say Instant.from-posix: 1485726595'
Instant:1485726632
Since a Rakudo compiler always returns 0 for future leap seconds it doesn't know about, you can patch your old code when new leap seconds are announced, so it will give correct results, regardless of what version of the compiler it runs on:
$ perl6-2016.06 -e 'say ($*VM.version before v2016.07 ?? 1 !! 0) + Instant.from-posix: 1485726595'
Instant:1485726632
$ perl6-2016.07 -e 'say ($*VM.version before v2016.07 ?? 1 !! 0) + Instant.from-posix: 1485726595'
Instant:1485726632
These examples require compilers that predate the rename, and so still refer to perl6. This is because there have been no new leap seconds so far since then, as Earth's rotation has been steady since the end of 2016.