How do I get the current time in Sui Move?
November 10, 2026
To read the current time in Sui Move, add a &Clock parameter to your function and call clock.timestamp_ms(), which returns Unix time in milliseconds as a u64. Clock is a system shared object at address 0x6. You pass it in as an argument, and you can only take it by immutable reference. If you only need a coarse timestamp and want to stay on the owned-object fast path, use ctx.epoch_timestamp_ms(), which returns the time the current epoch started.
Using sui::clock::Clock
module example::timer;
use sui::clock::Clock;
use sui::event;
public struct TimeEvent has copy, drop {
timestamp_ms: u64,
}
entry fun now(clock: &Clock) {
event::emit(TimeEvent { timestamp_ms: clock.timestamp_ms() });
}The same pattern works in public functions, for example a deadline check:
const EExpired: u64 = 0;
public fun assert_not_expired(deadline_ms: u64, clock: &Clock) {
assert!(clock.timestamp_ms() < deadline_ms, EExpired);
}A system transaction updates the clock at every consensus commit, which the docs put at roughly every quarter second. Within one transaction, every call to timestamp_ms returns the same value. Across transactions, the value never goes backwards.
Passing the clock from a transaction
From the CLI, pass 0x6:
sui client call --package <PACKAGE_ID> --module timer --function now --args 0x6From TypeScript (@mysten/sui v2), use the tx.object.clock() helper:
import { Transaction } from '@mysten/sui/transactions'
const tx = new Transaction()
tx.moveCall({
target: `${PACKAGE_ID}::timer::now`,
arguments: [tx.object.clock()],
})Epoch timestamps: the fast-path alternative
Because Clock is a shared object, any transaction that uses it goes through consensus. If you don't need sub-second precision, TxContext has the start time of the current epoch:
public fun epoch_started_at(ctx: &TxContext): u64 {
ctx.epoch_timestamp_ms()
}This value only changes at epoch boundaries, roughly every 24 hours on mainnet (see Sui epochs). It suits things like "claimable after N epochs". It doesn't suit auctions or anything that needs minute-level precision.
Testing time-dependent code
You can't use the real 0x6 object in unit tests. The framework has test-only helpers instead:
#[test]
fun deadline_passes() {
let mut ctx = tx_context::dummy();
let mut clock = sui::clock::create_for_testing(&mut ctx);
clock.set_for_testing(1_000);
assert!(clock.timestamp_ms() == 1_000);
clock.increment_for_testing(500);
assert!(clock.timestamp_ms() == 1_500);
clock.destroy_for_testing();
}For epoch-based logic, test_scenario::later_epoch(scenario, delta_ms, sender) moves the epoch forward and adds delta_ms to the epoch timestamp. See Move unit tests for the test setup.
Gotchas
- Taking
&mut ClockorClockby value doesn't work. The docs say packages with entry functions that do this fail to publish, and validators won't sign transactions that pass the clock any other way. - Every transaction that touches
0x6becomes a consensus transaction. See shared vs owned objects for what that costs. - Timestamps are milliseconds, not seconds. Keep deadlines in ms as well.
- Don't use the timestamp as a source of randomness. Use
sui::random.
Sources
- Access Onchain Time, Sui documentation
- clock.move, Sui framework source
- tx_context.move, Sui framework source