Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/book/spell-check-custom-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -247,3 +247,5 @@ Cfg
evm
AbiEncode
AbiDecode
Durations
durations
1 change: 1 addition & 0 deletions docs/book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
- [Access Control](./blockchain-development/access_control.md)
- [Calling Contracts](./blockchain-development/calling_contracts.md)
- [External Code](./blockchain-development/external_code.md)
- [Time](./blockchain-development/time.md)
- [Advanced Concepts](./advanced/index.md)
- [Advanced Types](./advanced/advanced_types.md)
- [Advanced Storage](./advanced/advanced_storage.md)
Expand Down
105 changes: 105 additions & 0 deletions docs/book/src/blockchain-development/time.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Time Library

The `std::time` library provides utilities for handling time durations and timestamps in Sway smart contracts.

## Duration

Represents a span of time in seconds.

### Creating Durations

```sway
{{#include ../../../../examples/time/src/main.sw:create_durations}}
```

### Converting Durations

Time `std::time` library supports conversion between different time scales such as `seconds`, `minutes`, `hours`, `days`, and `weeks`.

```sway
{{#include ../../../../examples/time/src/main.sw:convert_durations}}
```

### Operations

The `std::time` supports operations on the `Duration` type.

```sway
{{#include ../../../../examples/time/src/main.sw:duration_operations}}
```

## Time

Represents a UNIX timestamp (seconds since Jan 1, 1970).

### Creating Timestamps

There are 3 major ways to create a new timestamp.

```sway
{{#include ../../../../examples/time/src/main.sw:create_timestamps}}
```

### Time Operations

Operations on the `Time` type are supported with conjunction of the `Duration` type.

```sway
{{#include ../../../../examples/time/src/main.sw:time_operations}}
```

### TAI64 Conversion

The Fuel VM internally uses TAI64 time. Conversions between UNIX and TAI64 are maintained with the `Time` type.

```sway
{{#include ../../../../examples/time/src/main.sw:tai64_conversion}}
```

### TAI64 vs UNIX Time

#### Conversion Details

The library uses:

```sway
const TAI_64_CONVERTER: u64 = 10 + (1 << 62);
```

(1 << 62) (0x4000000000000000) marks value as TAI64. 10 accounts for initial TAI-UTC offset in 1970.

Conversion formulas:

`UNIX → TAI64: tai64 = unix + TAI_64_CONVERTER`

`TAI64 → UNIX: unix = tai64 - TAI_64_CONVERTER`

#### Key Differences

| Feature | TAI64 | UNIX |
|--------------|--------------------------|---------------------------|
| Epoch | 1970-01-01 00:00:00 TAI | 1970-01-01 00:00:00 UTC |
| Leap Seconds | No leap seconds | Includes leap seconds |
| Stability | Continuous time scale | Discontinuous adjustments |
| Value Range | (1 << 62) + offset (10s) | Seconds since epoch |

#### Why TAI64?

* Deterministic execution: No leap second ambiguities
* Monotonic time: Always increases steadily
* Blockchain-friendly: Aligns with Fuel's timestamp mechanism

## Best Practices

1. Use `Duration` for time spans instead of raw seconds
2. Always handle `TimeError` results from `duration_since()` and `elapsed()`
3. Convert to TAI64 when interacting with blockchain primitives
4. Use `Time::block()` for historical time comparisons
5. Prefer duration constants (`SECOND`, `HOUR`, etc.) for readability

## Limitations

1. Durations only support second-level precision
2. Time comparisons are limited to u64 range (584 billion years)
3. No calendar/date functionality (only timestamps)
4. Duration conversions truncate fractional units
5 changes: 5 additions & 0 deletions examples/Forc.lock
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ dependencies = ["std"]
name = "structs"
source = "member"

[[package]]
name = "time"
source = "member"
dependencies = ["std"]

[[package]]
name = "tuples"
source = "member"
Expand Down
1 change: 1 addition & 0 deletions examples/Forc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ members = [
"storage_vec",
"struct_storage_variables",
"structs",
"time",
"tuples",
"type_aliases",
"upgradeable_proxy/proxy",
Expand Down
8 changes: 8 additions & 0 deletions examples/time/Forc.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
license = "Apache-2.0"
name = "time"

[dependencies]
std = { path = "../../sway-lib-std" }
95 changes: 95 additions & 0 deletions examples/time/src/main.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
library;

use std::time::*;

// ANCHOR: create_durations
fn create_durations() {
// Using constants
let zero = Duration::ZERO;
let second = Duration::SECOND;
let minute = Duration::MINUTE;
let hour = Duration::HOUR;
let day = Duration::DAY;
let week = Duration::WEEK;

// Using constructor methods
let thirty_seconds = Duration::seconds(30);
let two_hours = Duration::hours(2);
let three_days = Duration::days(3);
}
// ANCHOR_END: create_durations

// ANCHOR: convert_durations
fn convert_durations() {
let two_days = Duration::days(2);

assert(two_days.as_seconds() == 172800); // 2 * 86400
assert(two_days.as_minutes() == 2880); // 2 * 1440
assert(two_days.as_hours() == 48); // 2 * 24
assert(two_days.as_days() == 2);
assert(two_days.as_weeks() == 0); // Truncated value
}
// ANCHOR_END: convert_durations

// ANCHOR: duration_operations
fn duration_operations() {
let day1 = Duration::DAY;
let day2 = Duration::days(1);

// Equality
assert(day1 == day2);

// Addition
let two_days = day1 + day2;
assert(two_days.as_days() == 2);

// Subtraction
let half_day = two_days - Duration::days(1).add(Duration::hours(12));
assert(half_day.as_hours() == 12);

// Comparison
assert(Duration::MINUTE < Duration::HOUR);
}
// ANCHOR_END: duration_operations

// ANCHOR: create_timestamps
fn create_timestamps() {
// Current block time
let now = Time::now();

// Specific block time
let block_time = Time::block(12345);

// From UNIX timestamp
let custom_time = Time::new(1672531200); // Jan 1, 2023 00:00:00 UTC
}
// ANCHOR_END: create_timestamps

// ANCHOR: time_operations
fn time_operations() {
let now = Time::now();
let yesterday = now.subtract(Duration::DAY);
let tomorrow = now.add(Duration::DAY);

// Duration calculations
let elapsed = now.duration_since(yesterday).unwrap();
assert(elapsed.as_days() == 1);

// Comparison
assert(yesterday < now);
assert(tomorrow > now);
}
// ANCHOR_END: time_operations

// ANCHOR: tai64_conversion
fn tai64_conversion() {
let now = Time::now();

// Convert to TAI64
let tai64 = now.as_tai64();

// Convert back to UNIX time
let converted = Time::from_tai64(tai64);
assert(now == converted);
}
// ANCHOR_END: tai64_conversion
6 changes: 5 additions & 1 deletion sway-lib-std/src/block.sw
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ pub fn height() -> u32 {
/// }
/// ```
pub fn timestamp() -> u64 {
timestamp_of_block(height())
asm(timestamp, height) {
bhei height;
time timestamp height;
timestamp: u64
}
}

/// Get the TAI64 timestamp of a block at a given `block_height`.
Expand Down
1 change: 1 addition & 0 deletions sway-lib-std/src/lib.sw
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod logging;
pub mod revert;
pub mod assert;
pub mod convert;
pub mod time;
pub mod intrinsics;
pub mod iterator;
pub mod vec;
Expand Down
Loading
Loading