Compare commits

..

No commits in common. "main" and "v0.2.0" have entirely different histories.
main ... v0.2.0

54 changed files with 3080 additions and 2450 deletions

View file

@ -3,7 +3,7 @@ name: Release
on:
push:
tags:
- "v*"
- 'v*'
workflow_dispatch:
permissions:
@ -17,180 +17,78 @@ jobs:
fail-fast: false
matrix:
include:
# macOS
- target: x86_64-macos
os: macos-latest
rust-target: x86_64-apple-darwin
cross-packages: ""
cargo-linker-env: ""
cargo-linker: ""
- target: aarch64-macos
os: macos-latest
rust-target: aarch64-apple-darwin
cross-packages: ""
cargo-linker-env: ""
cargo-linker: ""
# Linux (esbuild tier)
- target: x86_64-linux-gnu
os: ubuntu-latest
rust-target: x86_64-unknown-linux-gnu
cross-packages: ""
cargo-linker-env: ""
cargo-linker: ""
- target: aarch64-linux-gnu
os: ubuntu-latest
rust-target: aarch64-unknown-linux-gnu
cross-packages: gcc-aarch64-linux-gnu
cargo-linker-env: ""
cargo-linker: ""
- target: x86-linux-gnu
os: ubuntu-latest
rust-target: i686-unknown-linux-gnu
cross-packages: gcc-i686-linux-gnu
cargo-linker-env: ""
cargo-linker: ""
- target: arm-linux-gnueabihf
os: ubuntu-latest
rust-target: armv7-unknown-linux-gnueabihf
cross-packages: gcc-arm-linux-gnueabihf
cargo-linker-env: CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_LINKER
cargo-linker: arm-linux-gnueabihf-gcc
- target: loongarch64-linux-gnu
os: ubuntu-latest
rust-target: loongarch64-unknown-linux-gnu
cross-packages: ""
cargo-linker-env: CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER
cargo-linker: zig cc -target loongarch64-linux-gnu
- target: powerpc64le-linux-gnu
os: ubuntu-latest
rust-target: powerpc64le-unknown-linux-gnu
cross-packages: gcc-powerpc64le-linux-gnu
cargo-linker-env: ""
cargo-linker: ""
- target: riscv64-linux-gnu
os: ubuntu-latest
rust-target: riscv64gc-unknown-linux-gnu
cross-packages: gcc-riscv64-linux-gnu
cargo-linker-env: ""
cargo-linker: ""
- target: s390x-linux-gnu
os: ubuntu-latest
rust-target: s390x-unknown-linux-gnu
cross-packages: gcc-s390x-linux-gnu
cargo-linker-env: ""
cargo-linker: ""
# Windows
- target: x86_64-windows-gnu
os: ubuntu-latest
rust-target: x86_64-pc-windows-gnu
cross-packages: mingw-w64
cargo-linker-env: ""
cargo-linker: ""
- target: aarch64-windows-gnu
os: ubuntu-latest
rust-target: aarch64-pc-windows-gnullvm
cross-packages: mingw-w64
cargo-linker-env: ""
cargo-linker: ""
- target: x86-windows-gnu
os: ubuntu-latest
rust-target: i686-pc-windows-gnu
cross-packages: mingw-w64
cargo-linker-env: ""
cargo-linker: ""
# BSD (esbuild tier; use zig cc as cargo linker)
- target: x86_64-freebsd
os: ubuntu-latest
rust-target: x86_64-unknown-freebsd
cross-packages: ""
cargo-linker-env: CARGO_TARGET_X86_64_UNKNOWN_FREEBSD_LINKER
cargo-linker: zig cc -target x86_64-freebsd
- target: x86_64-netbsd
os: ubuntu-latest
rust-target: x86_64-unknown-netbsd
cross-packages: ""
cargo-linker-env: CARGO_TARGET_X86_64_UNKNOWN_NETBSD_LINKER
cargo-linker: zig cc -target x86_64-netbsd
# Additional targets
- target: wasm32-freestanding
os: ubuntu-latest
rust-target: wasm32-unknown-unknown
cross-packages: ""
cargo-linker-env: ""
cargo-linker: ""
- target: wasm32-wasi
os: ubuntu-latest
rust-target: wasm32-wasip1
cross-packages: ""
cargo-linker-env: ""
cargo-linker: ""
- target: x86_64-linux-musl
os: ubuntu-latest
rust-target: x86_64-unknown-linux-musl
cross-packages: ""
cargo-linker-env: ""
cargo-linker: ""
- target: aarch64-linux-musl
os: ubuntu-latest
rust-target: aarch64-unknown-linux-musl
cross-packages: ""
cargo-linker-env: ""
cargo-linker: ""
- target: aarch64-linux-android
os: ubuntu-latest
rust-target: aarch64-linux-android
cross-packages: ""
cargo-linker-env: ""
cargo-linker: ""
- target: aarch64-ios
os: macos-latest
rust-target: aarch64-apple-ios
cross-packages: ""
cargo-linker-env: ""
cargo-linker: ""
steps:
- uses: actions/checkout@v4
- name: Setup Zig
uses: mlugg/setup-zig@v2
with:
version: 0.17.0-dev.1398+cb5635714
version: 0.16.0-dev.2860+9c5460316
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.rust-target }}
- name: Install cross-compilers
if: matrix.cross-packages != ''
- name: Install cross-compilers (Linux-aarch64)
if: contains(matrix.target, 'aarch64-linux')
run: |
sudo apt-get update
sudo apt-get install -y ${{ matrix.cross-packages }}
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Install cross-compilers (Windows-mingw)
if: contains(matrix.target, 'windows-gnu')
run: |
sudo apt-get update
sudo apt-get install -y mingw-w64
- name: Build Package
run: |
if [ -n "${{ matrix.cargo-linker-env }}" ]; then
export "${{ matrix.cargo-linker-env }}=${{ matrix.cargo-linker }}"
fi
cd lib
cd pkg/temporal
zig build -Dbuild-rust -Dtarget=${{ matrix.target }} -Doptimize=ReleaseSafe
- name: Package artifact
run: |
cd lib
mkdir -p dist
tar -czf "dist/${{ matrix.target }}.tar.gz" -C "zig-out/lib/${{ matrix.target }}" .
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.target }}
path: lib/dist/${{ matrix.target }}.tar.gz
name: lib-${{ matrix.target }}
path: pkg/temporal/zig-out/lib/
retention-days: 1
release:
@ -199,18 +97,30 @@ jobs:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- uses: actions/checkout@v4
- name: Checkout code
uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: dist
path: all-libs
pattern: lib-*
merge-multiple: true
- name: Prepare Release Artifact
run: |
mkdir -p release/lib
cp -r all-libs/* release/lib/
cd release
tar -czf ../libtemporal.tar.gz lib/
zip -r ../libtemporal.zip lib/
- name: Release
uses: softprops/action-gh-release@v2
with:
files: dist/*.tar.gz
files: |
libtemporal.tar.gz
libtemporal.zip
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -3,14 +3,6 @@ name: CI
on:
push:
branches: [ main ]
paths:
- 'src/**'
- 'lib/**'
- 'test/**'
- 'build.zig'
- 'build.zig.zon'
- '.github/workflows/ci.yml'
pull_request:
branches: [ main ]
@ -21,6 +13,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
# os: [ubuntu-latest, macos-latest]
steps:
- name: Checkout code
@ -29,17 +22,31 @@ jobs:
- name: Setup Zig
uses: mlugg/setup-zig@v2
with:
version: 0.17.0-dev.1398+cb5635714
version: 0.16.0-dev.2860+9c5460316
- name: Build and run project
run: cd test && zig build run
- name: Build project
run: zig build
- name: Verify executable
run: |
./zig-out/bin/zx --help || echo "Executable built successfully"
shell: bash
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: temporalz-${{ matrix.os }}
path: zig-out/
retention-days: 1
test:
name: Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
needs: build
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
# os: [ubuntu-latest, macos-latest]
steps:
- name: Checkout code
@ -48,7 +55,17 @@ jobs:
- name: Setup Zig
uses: mlugg/setup-zig@v2
with:
version: 0.17.0-dev.1398+cb5635714
version: 0.16.0-dev.2860+9c5460316
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: temporalz-${{ matrix.os }}
path: zig-out/
- name: Make executable (Unix)
if: runner.os != 'Windows'
run: chmod +x zig-out/bin/temporalz
- name: Run tests
run: zig build test

View file

@ -1,55 +0,0 @@
name: Docs
on:
push:
branches:
- main
paths:
- 'src/**'
- 'lib/**'
- '.github/workflows/docs.yml'
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Zig
uses: mlugg/setup-zig@v2
with:
version: 0.17.0-dev.1398+cb5635714
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Build Docs
run: zig build docs
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: ./zig-out/docs
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

5
.gitignore vendored
View file

@ -3,4 +3,7 @@ zig-out
zig-pkg
target
.tool-versions
lib
tmp
test/test262/polyfill-injected.js

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "test/temporal-test262-runner"]
path = test/temporal-test262-runner
url = https://github.com/js-temporal/temporal-test262-runner.git

1
.tool-versions Normal file
View file

@ -0,0 +1 @@
zig master

View file

@ -6,11 +6,12 @@ A Zig library for working with temporal types based on the [Temporal Standard](h
Temporalz provides Zig bindings to the Rust-based [temporal_rs](https://github.com/boa-dev/temporal) library for handling dates, times, and durations with proper timezone support.
## Installation
#### Prerequisites
- Zig 0.17.0-dev.1398+cb5635714
- Zig 0.16.0-dev.2860+9c5460316
- Rust toolchain (only required if [prebuilt staticlibs](#prebuilt) are not available for your platform)
#### Add as a Dependency
@ -34,31 +35,36 @@ const exe = b.addExecutable(.{...});
exe.root_module.addImport("temporalz", temporalz.module("temporalz"));
```
## Checklist
| Namespace | Status |
| -------------- | ------ |
| Instant | ✅ |
| Duration | ✅ |
| PlainDate | ✅ |
| PlainTime | ✅ |
| PlainDateTime | ✅ |
| PlainYearMonth | ✅ |
| PlainMonthDay | ✅ |
| ZonedDateTime | ✅ |
## Checklist ([Test262](https://github.com/tc39/test262/tree/main/test/built-ins/Temporal))
| Namespace | Test262 (todo) |
| --- | --- |
| Instant | 0/0 |
| Duration | 0/0 |
| PlainDate | 0/0 |
| PlainTime | 0/0 |
| PlainDateTime | 0/0 |
| PlainYearMonth | 0/0 |
| PlainMonthDay | 0/0 |
| ZonedDateTime | 0/0 |
## Prebuilt
Prebuilt libraries are included for the following platforms:
- `x86_64-macos`, `aarch64-macos`
- `x86_64-linux-gnu`, `aarch64-linux-gnu`, `x86-linux-gnu`, `arm-linux-gnueabihf`
- `loongarch64-linux-gnu`, `powerpc64le-linux-gnu`, `riscv64-linux-gnu`, `s390x-linux-gnu`
- `x86_64-windows-gnu`, `aarch64-windows-gnu`, `x86-windows-gnu`
- `x86_64-freebsd`, `x86_64-netbsd`
- `wasm32-freestanding`, `wasm32-wasi`
- `x86_64-linux-musl`, `aarch64-linux-musl`
- `aarch64-linux-android`, `aarch64-ios`
- `x86_64-macos`
- `aarch64-macos`
- `x86_64-linux-gnu`
- `aarch64-linux-gnu`
- `x86_64-windows-gnu`
- `aarch64-windows-gnu`
- `wasm32-freestanding`
- `wasm32-wasi`
- `x86_64-linux-musl`
- `aarch64-linux-musl`
- `aarch64-linux-android`
- `aarch64-ios`
For other platforms, the library will build from source; you need the Rust toolchain installed.
@ -75,12 +81,6 @@ cd temporalz
```bash
zig build run
# Node.js
zig build run -Dtarget=wasm32-freestanding
# wasmtime
zig build run -Dtarget=wasm32-wasi
```
#### Run Tests
@ -88,3 +88,8 @@ zig build run -Dtarget=wasm32-wasi
```bash
zig build test
```
## License
MIT

298
SPEC.md Normal file
View file

@ -0,0 +1,298 @@
Temporal.Duration
Temporal.Instant
Temporal.Now
Temporal.PlainDate
Temporal.PlainDateTime
Temporal.PlainMonthDay
Temporal.PlainTime
Temporal.PlainYearMonth
Temporal.ZonedDateTime
Temporal.Duration
Constructor
Temporal.Duration()
Static methods
compare()
from()
Instance methods
abs()
add()
negated()
round()
subtract()
toJSON()
toLocaleString()
toString()
total()
valueOf()
with()
Instance properties
blank
days
hours
microseconds
milliseconds
minutes
months
nanoseconds
seconds
sign
weeks
years
Temporal.Instant
Constructor
Temporal.Instant()
Experimental
Static methods
compare()
from()
fromEpochMilliseconds()
fromEpochNanoseconds()
Instance methods
add()
equals()
round()
since()
subtract()
toJSON()
toLocaleString()
toString()
toZonedDateTimeISO()
until()
valueOf()
Instance properties
epochMilliseconds
epochNanoseconds
Temporal.Now
Static methods
instant()
plainDateISO()
plainDateTimeISO()
plainTimeISO()
timeZoneId()
zonedDateTimeISO()
Temporal.PlainDate
Constructor
Temporal.PlainDate()
Experimental
Static methods
compare()
from()
Instance methods
add()
equals()
since()
subtract()
toJSON()
toLocaleString()
toPlainDateTime()
toPlainMonthDay()
toPlainYearMonth()
toString()
toZonedDateTime()
until()
valueOf()
with()
withCalendar()
Instance properties
calendarId
day
dayOfWeek
dayOfYear
daysInMonth
daysInWeek
daysInYear
era
eraYear
inLeapYear
month
monthCode
monthsInYear
weekOfYear
year
yearOfWeek
Temporal.PlainDateTime
Constructor
Temporal.PlainDateTime()
Experimental
Static methods
compare()
from()
Instance methods
add()
equals()
round()
since()
subtract()
toJSON()
toLocaleString()
toPlainDate()
toPlainTime()
toString()
toZonedDateTime()
until()
valueOf()
with()
withCalendar()
withPlainTime()
Instance properties
calendarId
day
dayOfWeek
dayOfYear
daysInMonth
daysInWeek
daysInYear
era
eraYear
hour
inLeapYear
microsecond
millisecond
minute
month
monthCode
monthsInYear
nanosecond
second
weekOfYear
year
yearOfWeek
Temporal.PlainMonthDay
Constructor
Temporal.PlainMonthDay()
Experimental
Static methods
from()
Instance methods
equals()
toJSON()
toLocaleString()
toPlainDate()
toString()
valueOf()
with()
Instance properties
calendarId
day
monthCode
Temporal.PlainTime
Constructor
Temporal.PlainTime()
Static methods
compare()
from()
Instance methods
add()
equals()
round()
since()
subtract()
toJSON()
toLocaleString()
toString()
until()
valueOf()
with()
Instance properties
hour
microsecond
millisecond
minute
nanosecond
second
Temporal.PlainYearMonth
Constructor
Temporal.PlainYearMonth()
Experimental
Static methods
compare()
from()
Instance methods
add()
equals()
since()
subtract()
toJSON()
toLocaleString()
toPlainDate()
toString()
until()
valueOf()
with()
Instance properties
calendarId
daysInMonth
daysInYear
era
eraYear
inLeapYear
month
monthCode
monthsInYear
year
Temporal.ZonedDateTime
Constructor
Temporal.ZonedDateTime()
Experimental
Static methods
compare()
from()
Instance methods
add()
equals()
getTimeZoneTransition()
round()
since()
startOfDay()
subtract()
toInstant()
toJSON()
toLocaleString()
toPlainDate()
toPlainDateTime()
toPlainTime()
toString()
until()
valueOf()
with()
withCalendar()
withPlainTime()
withTimeZone()
Instance properties
calendarId
day
dayOfWeek
dayOfYear
daysInMonth
daysInWeek
daysInYear
epochMilliseconds
epochNanoseconds
era
eraYear
hour
hoursInDay
inLeapYear
microsecond
millisecond
minute
month
monthCode
monthsInYear
nanosecond
offset
offsetNanoseconds
second
timeZoneId
weekOfYear
year
yearOfWeek

View file

@ -3,38 +3,66 @@ const std = @import("std");
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const is_wasm_freestanding = target.result.cpu.arch.isWasm() and target.result.os.tag == .freestanding;
// --- Rust C ABI & Pre-built via temporal-rs subpackage --- //
const build_rust = b.option(bool, "build-rust", "Build Rust library from source") orelse false;
const libtemporal = b.dependency("libtemporal", .{
const temporal = b.dependency("temporal", .{
.target = target,
.optimize = optimize,
.@"build-rust" = build_rust,
});
// --- Module: temporalz --- //
// --- Zig Module: temporalz --- //
const mod = b.addModule("temporalz", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
mod.addImport("libtemporal", libtemporal.module("libtemporal"));
mod.addImport("temporal_rs", temporal.module("temporal_rs"));
// --- Step: run --- //
{
const run_step = b.step("run", "Run the test project");
const run_cmd = b.addSystemCommand(&.{
b.graph.zig_exe,
"build",
"run",
b.fmt("-Dtarget={s}", .{try target.result.zigTriple(b.allocator)}),
// --- Zig Executable: temporalz --- //
const exe = b.addExecutable(.{
.name = "temporalz",
.root_module = b.createModule(.{
.root_source_file = if (is_wasm_freestanding)
b.path("example/src/wasm.zig")
else
b.path("example/src/main.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "temporalz", .module = mod },
},
}),
});
run_cmd.setCwd(b.path("test"));
run_cmd.addPassthruArgs();
exe.root_module.link_libc = !is_wasm_freestanding;
exe.rdynamic = is_wasm_freestanding;
b.installArtifact(exe);
// --- Steps: Run --- //
{
const run_step = b.step("run", "Run the app");
switch (target.result.os.tag) {
.freestanding => {
const run_cmd = b.addSystemCommand(&.{ "node", "example/src/main.mjs" });
run_cmd.step.dependOn(b.getInstallStep());
run_step.dependOn(&run_cmd.step);
},
.wasi => {
const run_cmd = b.addSystemCommand(&.{"wasmtime"});
run_cmd.addFileArg(exe.getEmittedBin());
run_cmd.step.dependOn(b.getInstallStep());
run_step.dependOn(&run_cmd.step);
},
else => {
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
},
}
}
// --- Step: docs --- //
// --- Steps: Docs --- //
{
const docs_step = b.step("docs", "Build the temporalz docs");
const docs_obj = b.addObject(.{ .name = "temporalz", .root_module = mod });
@ -47,7 +75,7 @@ pub fn build(b: *std.Build) !void {
}).step);
}
// --- Step: test --- //
// --- Steps: Test --- //
{
const test_step = b.step("test", "Run tests");
const mod_tests = b.addTest(.{
@ -57,7 +85,20 @@ pub fn build(b: *std.Build) !void {
.mode = .simple,
},
});
mod_tests.root_module.link_libc = target.result.os.tag != .freestanding;
mod_tests.root_module.link_libc = !is_wasm_freestanding;
test_step.dependOn(&b.addRunArtifact(mod_tests).step);
if (!is_wasm_freestanding) {
const exe_tests = b.addTest(.{ .root_module = exe.root_module });
test_step.dependOn(&b.addRunArtifact(exe_tests).step);
}
}
// --- Steps: test-262 --- //
{
const test262_step = b.step("test262", "Run test-262 tests");
const run_cmd = b.addSystemCommand(&.{ "node", "test/test262/runner.mjs" });
if (b.args) |args| run_cmd.addArgs(args);
run_cmd.step.dependOn(b.getInstallStep());
test262_step.dependOn(&run_cmd.step);
}
}

View file

@ -1,11 +1,11 @@
.{
.name = .temporalz,
.version = "0.2.4",
.version = "0.2.0",
.fingerprint = 0xd8d79d59acc4faae,
.minimum_zig_version = "0.17.0-dev.1398+cb5635714",
.minimum_zig_version = "0.16.0-dev.2860+9c5460316",
.dependencies = .{
.libtemporal = .{
.path = "lib",
.temporal = .{
.path = "pkg/temporal",
},
},
.paths = .{
@ -14,6 +14,6 @@
"README.md",
"LICENCE",
"src",
"lib",
"pkg",
},
}

View file

@ -3,7 +3,7 @@ const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const is_freestanding = target.result.os.tag == .freestanding;
const is_wasm_freestanding = target.result.cpu.arch.isWasm() and target.result.os.tag == .freestanding;
const temporalz = b.dependency("temporalz", .{
.target = target,
@ -12,18 +12,14 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "temporalz",
.root_module = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.root_source_file = b.path(if (is_wasm_freestanding) "src/wasm.zig" else "src/main.zig"),
.target = target,
.optimize = optimize,
.link_libc = !is_freestanding,
.imports = &.{},
}),
});
exe.root_module.addImport("temporalz", temporalz.module("temporalz"));
exe.rdynamic = is_freestanding;
if (is_freestanding) exe.entry = .disabled;
b.installArtifact(exe);
b.enable_wasmtime = true; // This doesn't work since Zig 0.17.0 release
const run_step = b.step("run", "Run the app");
switch (target.result.os.tag) {
@ -41,7 +37,7 @@ pub fn build(b: *std.Build) void {
else => {
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
run_cmd.addPassthruArgs();
if (b.args) |args| run_cmd.addArgs(args);
run_step.dependOn(&run_cmd.step);
},
}

View file

@ -1,7 +1,8 @@
.{
.name = .temporalz_example,
.version = "0.0.0",
.version = "0.1.2",
.fingerprint = 0x686c9dfc777f9593,
.minimum_zig_version = "0.16.0-dev.2860+9c5460316",
.dependencies = .{
.temporalz = .{
.path = "../",

17
example/src/main.mjs Normal file
View file

@ -0,0 +1,17 @@
import { readFile } from 'fs/promises';
let memory = null;
const buffer = await readFile('zig-out/bin/temporalz.wasm');
const temporalz = await WebAssembly.instantiate(buffer, {
env: {
console(ptr, len) {
const bytes = new Uint8Array(memory.buffer, ptr, len);
const message = new TextDecoder().decode(bytes);
console.log(message);
},
},
});
memory = temporalz.instance.exports.memory;
temporalz.instance.exports._start();

9
example/src/main.zig Normal file
View file

@ -0,0 +1,9 @@
const std = @import("std");
const program = @import("root.zig");
pub fn main(init: std.process.Init) !void {
const allocator = init.arena.allocator();
const io = init.io;
try program.run(allocator, io);
}

482
example/src/root.zig Normal file
View file

@ -0,0 +1,482 @@
const std = @import("std");
const builtin = @import("builtin");
const Temporal = @import("temporalz");
pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
// --- Instant --- //
const instant = try Temporal.Instant.init(1_704_067_200_000_000_000); // 2024-01-01 00:00:00 UTC
defer instant.deinit();
std.log.info(
\\Instant
\\ - milliseconds: {}
\\ - nanoseconds: {}
\\ - toString(): {s}
\\
\\
, .{
instant.epochMilliseconds(),
instant.epochNanoseconds(),
try instant.toString(allocator, .{}),
});
// --- Duration --- //
const dur = try Temporal.Duration.from("PT1H");
defer dur.deinit();
std.log.info(
\\Duration
\\ - nanoseconds: {}
\\ - milliseconds: {}
\\ - seconds: {}
\\ - minutes: {}
\\ - hours: {}
\\ - days: {}
\\ - weeks: {}
\\ - months: {}
\\ - years: {}
\\ - toString(): {s}
\\
\\
, .{
dur.nanoseconds(),
dur.milliseconds(),
dur.seconds(),
dur.minutes(),
dur.hours(),
dur.days(),
dur.weeks(),
dur.months(),
dur.years(),
try dur.toString(allocator, .{}),
});
// --- Now --- //
if (io_optional) |io| {
const now_instant = try Temporal.Now.instant(io);
defer now_instant.deinit();
const now_date = try Temporal.Now.plainDateISO(io);
defer now_date.deinit();
const now_datetime = try Temporal.Now.plainDateTimeISO(io);
const now_time = try Temporal.Now.plainTimeISO(io);
std.log.info(
\\Now
\\ - instant: {s}
\\ - date: {s}
\\ - datetime: {s}
\\ - time: {s}
\\
\\
, .{
try now_instant.toString(allocator, .{}),
try now_date.toString(allocator, .{}),
try now_datetime.toString(allocator, .{}),
try now_time.toString(allocator),
});
}
// --- PlainDate --- //
const date = try Temporal.PlainDate.init(2024, 2, 2);
defer date.deinit();
std.log.info(
\\PlainDate
\\ - year: {}
\\ - month: {}
\\ - day: {}
\\ - toString(): {s}
\\
\\
, .{
date.year(),
date.month(),
date.day(),
try date.toString(allocator, .{}),
});
// --- PlainDateTime --- //
const dt = try Temporal.PlainDateTime.init(2024, 2, 2, 13, 45, 30, 123, 456, 789);
std.log.info(
\\PlainDateTime
\\ - year: {}
\\ - month: {}
\\ - day: {}
\\ - hour: {}
\\ - minute: {}
\\ - second: {}
\\ - toString(): {s}
\\
\\
, .{
dt.year(),
dt.month(),
dt.day(),
dt.hour(),
dt.minute(),
dt.second(),
try dt.toString(allocator, .{}),
});
// --- PlainMonthDay --- //
const md = try Temporal.PlainMonthDay.init(2, 2, null);
std.log.info(
\\PlainMonthDay
\\ - monthCode: {s}
\\ - day: {}
\\ - toString(): {s}
\\
\\
, .{
try md.monthCode(allocator),
md.day(),
try md.toString(allocator),
});
// --- PlainTime --- //
const tm = try Temporal.PlainTime.init(13, 45, 30, 123, 456, 789);
std.log.info(
\\PlainTime
\\ - hour: {}
\\ - minute: {}
\\ - second: {}
\\ - toString(): {s}
\\
\\
, .{
tm.hour(),
tm.minute(),
tm.second(),
try tm.toString(allocator),
});
// --- PlainYearMonth --- //
const ym = try Temporal.PlainYearMonth.init(2024, 2, null);
std.log.info(
\\PlainYearMonth
\\ - year: {}
\\ - month: {}
\\ - toString(): {s}
\\
\\
, .{ ym.year(), ym.month(), try ym.toString(allocator) });
// --- ZonedDateTime --- //
const tz = try Temporal.ZonedDateTime.TimeZone.init("UTC");
// Example: 2024-02-02T13:45:30.123456789Z in nanoseconds since epoch
const zdt_epoch_ns: i128 = 1706881530123456789;
const zdt = try Temporal.ZonedDateTime.fromEpochNanoseconds(zdt_epoch_ns, tz);
defer zdt.deinit();
std.log.info(
\\ZonedDateTime
\\ - year: {}
\\ - month: {}
\\ - day: {}
\\ - hour: {}
\\ - minute: {}
\\ - second: {}
\\ - timeZone: {s}
\\ - toString(): {s}
\\
\\
, .{
zdt.year(),
zdt.month(),
zdt.day(),
zdt.hour(),
zdt.minute(),
zdt.second(),
try zdt.timeZoneId(allocator),
try zdt.toString(allocator, .{}),
});
// ----
// More complex Temporal API examples
// ----
// Duration arithmetic
const dur1 = try Temporal.Duration.from("P1DT2H");
const dur2 = try Temporal.Duration.from("PT30M");
const dur_sum = try dur1.add(dur2);
std.log.info(
\\Duration Arithmetic
\\ - dur1: {s}
\\ - dur2: {s}
\\ - dur1 + dur2: {s}
\\
\\
, .{
try dur1.toString(allocator, .{}),
try dur2.toString(allocator, .{}),
try dur_sum.toString(allocator, .{}),
});
// Instant comparison and arithmetic
const inst1 = try Temporal.Instant.init(1_704_067_200_000_000_000);
const inst2 = try Temporal.Instant.init(1_704_153_600_000_000_000); // +1 day
const inst_diff = try inst2.since(inst1, Temporal.Instant.DifferenceSettings{});
std.log.info(
\\Instant Comparison
\\ - inst1: {s}
\\ - inst2: {s}
\\ - inst2.since(inst1): {s}
\\
\\
, .{
try inst1.toString(allocator, .{}),
try inst2.toString(allocator, .{}),
try inst_diff.toString(allocator, .{}),
});
// PlainDate to PlainDateTime and back
const pd = try Temporal.PlainDate.init(2024, 2, 2);
const pdt = try pd.toPlainDateTime(try Temporal.PlainTime.init(12, 0, 0, 0, 0, 0));
std.log.info(
\\PlainDate/PlainDateTime Conversion
\\ - PlainDate: {s}
\\ - toPlainDateTime(12:00): {s}
\\ - toPlainDate(): {s}
\\
\\
, .{
try pd.toString(allocator, .{}),
try pdt.toString(allocator, .{}),
try (try pdt.toPlainDate()).toString(allocator, .{}),
});
// ZonedDateTime to Instant and back
const zdt2 = try Temporal.ZonedDateTime.fromEpochNanoseconds(1706881530123456789, tz);
const zdt2_inst = try zdt2.toInstant();
const zdt2_from_inst = try Temporal.ZonedDateTime.fromEpochNanoseconds(zdt2_inst.epochNanoseconds(), tz);
std.log.info(
\\ZonedDateTime/Instant Conversion
\\ - ZonedDateTime: {s}
\\ - toInstant(): {s}
\\ - fromEpochNanoseconds(instant): {s}
\\
\\
, .{
try zdt2.toString(allocator, .{}),
try zdt2_inst.toString(allocator, .{}),
try zdt2_from_inst.toString(allocator, .{}),
});
// ----
// Further more complex examples covering more methods
// ----
// Duration: abs, negated, round, subtract, total, valueOf
const dur_neg = dur.negated();
const dur_abs = dur_neg.abs();
const dur_sub = try dur.subtract(dur2);
const dur_rounded = try dur.round(.{ .smallest_unit = Temporal.Duration.Unit.hour });
const dur_total_hours = try dur.total(.{ .unit = Temporal.Duration.Unit.hour });
std.log.info(
\\Duration Advanced
\\ - negated: {s}
\\ - abs: {s}
\\ - subtract dur2: {s}
\\ - round to hour: {s}
\\ - total hours: {d}
\\
\\
, .{
try dur_neg.toString(allocator, .{}),
try dur_abs.toString(allocator, .{}),
try dur_sub.toString(allocator, .{}),
try dur_rounded.toString(allocator, .{}),
dur_total_hours,
});
// Instant: add, subtract, round, equals, valueOf
const inst_add = try inst1.add(@constCast(&dur));
const inst_sub = try inst2.subtract(@constCast(&dur));
const inst_rounded = try inst1.round(.{ .smallest_unit = Temporal.Instant.Unit.second });
const inst_eq = Temporal.Instant.compare(inst1, inst1) == 0;
std.log.info(
\\Instant Advanced
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - round to second: {s}
\\ - inst1 equals inst1: {}
\\
\\
, .{
try inst_add.toString(allocator, .{}),
try inst_sub.toString(allocator, .{}),
try inst_rounded.toString(allocator, .{}),
inst_eq,
});
// PlainDate: add, subtract, with, equals, since, until, withCalendar
const date_added = try date.add(dur);
const date_sub = try date.subtract(dur);
// const date_with = try date.with(.{ .year = 2025 });
const date_eq = date.equals(date);
const date_since = try date.since(date, Temporal.PlainDate.DifferenceSettings{});
const date_until = try date.until(date, Temporal.PlainDate.DifferenceSettings{});
const date_with_cal = try date.withCalendar("iso8601");
std.log.info(
\\PlainDate Advanced
\\ - equals self: {}
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - since self: {s}
\\ - until self: {s}
\\ - withCalendar: {s}
\\ - with year=2025: {{s}}
\\
\\
,
.{
date_eq,
try date_added.toString(allocator, .{}),
try date_sub.toString(allocator, .{}),
try date_since.toString(allocator, .{}),
try date_until.toString(allocator, .{}),
try date_with_cal.toString(allocator, .{}),
// try date_with.toString(allocator, .{}),
},
);
// PlainDateTime: add, subtract, round, with, equals, since, until, withCalendar, withPlainTime
const dt_added = try dt.add(dur);
const dt_sub = try dt.subtract(dur);
const dt_rounded = try dt.round(.{ .smallest_unit = Temporal.PlainDateTime.Unit.minute });
const dt_with = try dt.with(.{ .year = 2025 });
const dt_eq = dt.equals(dt);
const dt_since = try dt.since(dt, Temporal.PlainDateTime.DifferenceSettings{});
const dt_until = try dt.until(dt, Temporal.PlainDateTime.DifferenceSettings{});
const dt_with_cal = try dt.withCalendar("iso8601");
const dt_with_time = try dt.withPlainTime(try Temporal.PlainTime.init(1, 2, 3, 4, 5, 6));
std.log.info(
\\PlainDateTime Advanced
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - round to minute: {s}
\\ - with year=2025: {s}
\\ - equals self: {}
\\ - since self: {s}
\\ - until self: {s}
\\ - withCalendar: {s}
\\ - withPlainTime: {s}
\\
\\
, .{
try dt_added.toString(allocator, .{}),
try dt_sub.toString(allocator, .{}),
try dt_rounded.toString(allocator, .{}),
try dt_with.toString(allocator, .{}),
dt_eq,
try dt_since.toString(allocator, .{}),
try dt_until.toString(allocator, .{}),
try dt_with_cal.toString(allocator, .{}),
try dt_with_time.toString(allocator, .{}),
});
// PlainTime: add, subtract, round, with, equals, since, until
const tm_added = try tm.add(dur);
const tm_sub = try tm.subtract(dur);
const tm_rounded = try tm.round(.{ .smallest_unit = Temporal.PlainTime.Unit.second });
const tm_with = try tm.with(.{ .hour = 1 });
const tm_eq = tm.equals(tm);
const tm_since = try tm.since(tm, Temporal.PlainTime.DifferenceSettings{});
const tm_until = try tm.until(tm, Temporal.PlainTime.DifferenceSettings{});
std.log.info(
\\PlainTime Advanced
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - round to second: {s}
\\ - with hour=1: {s}
\\ - equals self: {}
\\ - since self: {s}
\\ - until self: {s}
\\
\\
, .{
try tm_added.toString(allocator),
try tm_sub.toString(allocator),
try tm_rounded.toString(allocator),
try tm_with.toString(allocator),
tm_eq,
try tm_since.toString(allocator, .{}),
try tm_until.toString(allocator, .{}),
});
// PlainYearMonth: add, subtract, with, equals, since, until, withCalendar
const dur_ym = try Temporal.Duration.from("P1M");
defer dur_ym.deinit();
const ym_added = try ym.add(dur_ym);
const ym_sub = try ym.subtract(dur_ym);
const ym_with = try ym.with(.{ .year = 2025 });
const ym_eq = ym.equals(ym);
const ym_since = try ym.since(ym, Temporal.PlainYearMonth.DifferenceSettings{});
const ym_until = try ym.until(ym, Temporal.PlainYearMonth.DifferenceSettings{});
std.log.info(
\\PlainYearMonth Advanced
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - with year=2025: {s}
\\ - equals self: {}
\\ - since self: {s}
\\ - until self: {s}
\\
\\
, .{
try ym_added.toString(allocator),
try ym_sub.toString(allocator),
try ym_with.toString(allocator),
ym_eq,
try ym_since.toString(allocator, .{}),
try ym_until.toString(allocator, .{}),
});
// ZonedDateTime: add, subtract, round, with, equals, since, until, withCalendar, withPlainTime, withTimeZone
const zdt_added = try zdt.add(dur);
const zdt_sub = try zdt.subtract(dur);
const zdt_rounded = try zdt.round(.{ .smallest_unit = Temporal.ZonedDateTime.Unit.hour });
// const zdt_with = try zdt.with(allocator, .{ .year = 2025 });
const zdt_eq = zdt.equals(zdt);
const zdt_since = try zdt.since(zdt, Temporal.ZonedDateTime.DifferenceSettings{});
const zdt_until = try zdt.until(zdt, Temporal.ZonedDateTime.DifferenceSettings{});
const zdt_with_cal = try zdt.withCalendar("iso8601");
const zdt_with_time = try zdt.withPlainTime(try Temporal.PlainTime.init(1, 2, 3, 4, 5, 6));
const zdt_with_tz = try zdt.withTimeZone(tz);
std.log.info(
\\ZonedDateTime Advanced
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - round to hour: {s}
\\ - with year=2025: {{s}}
\\ - equals self: {}
\\ - since self: {s}
\\ - until self: {s}
\\ - withCalendar: {s}
\\ - withPlainTime: {s}
\\ - withTimeZone: {s}
\\
\\
, .{
try zdt_added.toString(allocator, .{}),
try zdt_sub.toString(allocator, .{}),
try zdt_rounded.toString(allocator, .{}),
// try zdt_with.toString(allocator, .{}),
zdt_eq,
try zdt_since.toString(allocator, .{}),
try zdt_until.toString(allocator, .{}),
try zdt_with_cal.toString(allocator, .{}),
try zdt_with_time.toString(allocator, .{}),
try zdt_with_tz.toString(allocator, .{}),
});
}
extern fn consoleLog(ptr: [*]u8, len: u32) void;
pub fn logFn(comptime message_level: std.log.Level, comptime scope: @TypeOf(.enum_literal), comptime format: []const u8, args: anytype) void {
if (builtin.os.tag == .freestanding) {
const prefix = if (scope == .default) "" else "(" ++ @tagName(scope) ++ ") ";
const formatted = std.fmt.allocPrint(std.heap.wasm_allocator, prefix ++ format, args) catch return;
consoleLog(formatted.ptr, formatted.len);
}
std.log.defaultLog(message_level, scope, format, args);
}
pub const std_options: std.Options = .{
.logFn = logFn,
};

842
example/src/wasm.zig Normal file
View file

@ -0,0 +1,842 @@
const std = @import("std");
const program = @import("root.zig");
const Temporal = @import("temporalz");
export fn _start() void {
const allocator = std.heap.page_allocator;
program.run(allocator, null) catch {};
}
const wasm_allocator = std.heap.wasm_allocator;
const PolyfillError = error{InvalidHandle};
var instants_init = false;
var durations_init = false;
var instants: std.ArrayList(?Temporal.Instant) = .empty;
var durations: std.ArrayList(?Temporal.Duration) = .empty;
var plain_dates_init = false;
var plain_dates: std.ArrayList(?Temporal.PlainDate) = .empty;
var last_error: ?[]u8 = null;
fn ensureInstants() void {
if (!instants_init) {
instants = .empty;
instants_init = true;
}
}
fn ensureDurations() void {
if (!durations_init) {
durations = .empty;
durations_init = true;
}
}
fn ensurePlainDates() void {
if (!plain_dates_init) {
plain_dates = .empty;
plain_dates_init = true;
}
}
fn addInstant(inst: Temporal.Instant) u32 {
ensureInstants();
instants.append(wasm_allocator, inst) catch return 0;
return @intCast(instants.items.len);
}
fn getInstant(handle: u32) !Temporal.Instant {
ensureInstants();
if (handle == 0 or handle > instants.items.len) return PolyfillError.InvalidHandle;
return instants.items[handle - 1] orelse PolyfillError.InvalidHandle;
}
fn removeInstant(handle: u32) void {
if (!instants_init or handle == 0 or handle > instants.items.len) return;
if (instants.items[handle - 1]) |inst| {
inst.deinit();
instants.items[handle - 1] = null;
}
}
fn addDuration(dur: Temporal.Duration) u32 {
ensureDurations();
durations.append(wasm_allocator, dur) catch return 0;
return @intCast(durations.items.len);
}
fn getDuration(handle: u32) !Temporal.Duration {
ensureDurations();
if (handle == 0 or handle > durations.items.len) return PolyfillError.InvalidHandle;
return durations.items[handle - 1] orelse PolyfillError.InvalidHandle;
}
fn removeDuration(handle: u32) void {
if (!durations_init or handle == 0 or handle > durations.items.len) return;
if (durations.items[handle - 1]) |dur| {
dur.deinit();
durations.items[handle - 1] = null;
}
}
fn addPlainDate(date: Temporal.PlainDate) u32 {
ensurePlainDates();
plain_dates.append(wasm_allocator, date) catch return 0;
return @intCast(plain_dates.items.len);
}
fn getPlainDate(handle: u32) !Temporal.PlainDate {
ensurePlainDates();
if (handle == 0 or handle > plain_dates.items.len) return PolyfillError.InvalidHandle;
return plain_dates.items[handle - 1] orelse PolyfillError.InvalidHandle;
}
fn removePlainDate(handle: u32) void {
if (!plain_dates_init or handle == 0 or handle > plain_dates.items.len) return;
if (plain_dates.items[handle - 1]) |date| {
date.deinit();
plain_dates.items[handle - 1] = null;
}
}
fn clearLastError() void {
if (last_error) |msg| {
wasm_allocator.free(msg);
last_error = null;
}
}
fn setLastError(err: anyerror) void {
clearLastError();
const msg = std.fmt.allocPrint(wasm_allocator, "{s}", .{@errorName(err)}) catch return;
last_error = msg;
}
fn setLastErrorMessage(msg: []const u8) void {
clearLastError();
const owned = wasm_allocator.alloc(u8, msg.len) catch return;
std.mem.copyForwards(u8, owned, msg);
last_error = owned;
}
fn packPtrLen(ptr: [*]u8, len: usize) u64 {
const ptr_u32: u32 = @intCast(@intFromPtr(ptr));
const len_u32: u32 = @intCast(len);
return (@as(u64, ptr_u32) << 32) | @as(u64, len_u32);
}
fn unpackI128Hi(value: i128) i64 {
const bits: u128 = @bitCast(value);
const hi_bits: u64 = @intCast(bits >> 64);
return @bitCast(hi_bits);
}
fn unpackI128Lo(value: i128) u64 {
const bits: u128 = @bitCast(value);
return @intCast(bits & 0xFFFFFFFFFFFFFFFF);
}
fn joinI128(hi: i64, lo: u64) i128 {
const hi_bits: u64 = @bitCast(hi);
const value: u128 = (@as(u128, hi_bits) << 64) | @as(u128, lo);
return @bitCast(value);
}
fn unitFromCode(code: u8) ?Temporal.Duration.Unit {
return switch (code) {
1 => .nanosecond,
2 => .microsecond,
3 => .millisecond,
4 => .second,
5 => .minute,
6 => .hour,
7 => .day,
8 => .week,
9 => .month,
10 => .year,
11 => .auto,
else => null,
};
}
fn roundingModeFromCode(code: u8) ?Temporal.Duration.RoundingMode {
return switch (code) {
1 => .ceil,
2 => .floor,
3 => .expand,
4 => .trunc,
5 => .half_ceil,
6 => .half_floor,
7 => .half_expand,
8 => .half_trunc,
9 => .half_even,
else => null,
};
}
export fn temporalz_last_error_ptr() usize {
return if (last_error) |msg| @intFromPtr(msg.ptr) else 0;
}
export fn temporalz_last_error_len() usize {
return if (last_error) |msg| msg.len else 0;
}
export fn temporalz_last_error_clear() void {
clearLastError();
}
export fn temporalz_alloc(len: usize) usize {
clearLastError();
const buf = wasm_allocator.alloc(u8, len) catch |err| {
setLastError(err);
return 0;
};
return @intFromPtr(buf.ptr);
}
export fn temporalz_free(ptr: usize, len: usize) void {
if (ptr == 0 or len == 0) return;
const slice = @as([*]u8, @ptrFromInt(ptr))[0..len];
wasm_allocator.free(slice);
}
export fn temporalz_string_free(ptr: usize, len: usize) void {
temporalz_free(ptr, len);
}
export fn temporalz_instant_from_utf8(ptr: [*]const u8, len: usize) u32 {
clearLastError();
const text = ptr[0..len];
const inst = Temporal.Instant.from(text) catch |err| {
setLastError(err);
return 0;
};
return addInstant(inst);
}
export fn temporalz_instant_from_epoch_milliseconds(epoch_ms: i64) u32 {
clearLastError();
const inst = Temporal.Instant.fromEpochMilliseconds(epoch_ms) catch |err| {
setLastError(err);
return 0;
};
return addInstant(inst);
}
export fn temporalz_instant_from_epoch_nanoseconds_parts(hi: i64, lo: u64) u32 {
clearLastError();
const epoch_ns = joinI128(hi, lo);
const inst = Temporal.Instant.fromEpochNanoseconds(epoch_ns) catch |err| {
setLastError(err);
return 0;
};
return addInstant(inst);
}
export fn temporalz_instant_epoch_milliseconds(handle: u32) i64 {
clearLastError();
const inst = getInstant(handle) catch |err| {
setLastError(err);
return 0;
};
return inst.epochMilliseconds();
}
export fn temporalz_instant_epoch_nanoseconds_hi(handle: u32) i64 {
clearLastError();
const inst = getInstant(handle) catch |err| {
setLastError(err);
return 0;
};
return unpackI128Hi(inst.epochNanoseconds());
}
export fn temporalz_instant_epoch_nanoseconds_lo(handle: u32) u64 {
clearLastError();
const inst = getInstant(handle) catch |err| {
setLastError(err);
return 0;
};
return unpackI128Lo(inst.epochNanoseconds());
}
export fn temporalz_instant_to_string(handle: u32) u64 {
clearLastError();
const inst = getInstant(handle) catch |err| {
setLastError(err);
return 0;
};
const text = inst.toString(wasm_allocator, .{}) catch |err| {
setLastError(err);
return 0;
};
return packPtrLen(text.ptr, text.len);
}
export fn temporalz_instant_add(handle: u32, duration_handle: u32) u32 {
clearLastError();
const inst = getInstant(handle) catch |err| {
setLastError(err);
return 0;
};
var dur = getDuration(duration_handle) catch |err| {
setLastError(err);
return 0;
};
const res = inst.add(&dur) catch |err| {
setLastError(err);
return 0;
};
return addInstant(res);
}
export fn temporalz_instant_subtract(handle: u32, duration_handle: u32) u32 {
clearLastError();
const inst = getInstant(handle) catch |err| {
setLastError(err);
return 0;
};
var dur = getDuration(duration_handle) catch |err| {
setLastError(err);
return 0;
};
const res = inst.subtract(&dur) catch |err| {
setLastError(err);
return 0;
};
return addInstant(res);
}
export fn temporalz_instant_compare(handle_a: u32, handle_b: u32) i32 {
clearLastError();
const a = getInstant(handle_a) catch |err| {
setLastError(err);
return 0;
};
const b = getInstant(handle_b) catch |err| {
setLastError(err);
return 0;
};
return @intCast(Temporal.Instant.compare(a, b));
}
export fn temporalz_instant_equals(handle_a: u32, handle_b: u32) u8 {
clearLastError();
const a = getInstant(handle_a) catch |err| {
setLastError(err);
return 0;
};
const b = getInstant(handle_b) catch |err| {
setLastError(err);
return 0;
};
return if (Temporal.Instant.equals(a, b)) 1 else 0;
}
export fn temporalz_instant_round(
handle: u32,
smallest_unit: u8,
rounding_mode: u8,
rounding_increment: u32,
) u32 {
clearLastError();
const inst = getInstant(handle) catch |err| {
setLastError(err);
return 0;
};
var opts = Temporal.Instant.RoundingOptions{};
if (smallest_unit != 255) {
opts.smallest_unit = unitFromCode(smallest_unit) orelse {
setLastErrorMessage("Invalid smallestUnit");
return 0;
};
}
if (rounding_mode != 255) {
opts.rounding_mode = roundingModeFromCode(rounding_mode) orelse {
setLastErrorMessage("Invalid roundingMode");
return 0;
};
}
if (rounding_increment != 0) {
opts.rounding_increment = rounding_increment;
}
const res = inst.round(opts) catch |err| {
setLastError(err);
return 0;
};
return addInstant(res);
}
export fn temporalz_instant_destroy(handle: u32) void {
removeInstant(handle);
}
export fn temporalz_duration_from_utf8(ptr: [*]const u8, len: usize) u32 {
clearLastError();
const text = ptr[0..len];
const dur = Temporal.Duration.from(text) catch |err| {
setLastError(err);
return 0;
};
return addDuration(dur);
}
export fn temporalz_duration_from_parts(
mask: u32,
years: i64,
months: i64,
weeks: i64,
days: i64,
hours: i64,
minutes: i64,
seconds: i64,
milliseconds: i64,
microseconds: f64,
nanoseconds: f64,
) u32 {
clearLastError();
var partial = Temporal.Duration.PartialDuration{};
if ((mask & 0x1) != 0) partial.years = years;
if ((mask & 0x2) != 0) partial.months = months;
if ((mask & 0x4) != 0) partial.weeks = weeks;
if ((mask & 0x8) != 0) partial.days = days;
if ((mask & 0x10) != 0) partial.hours = hours;
if ((mask & 0x20) != 0) partial.minutes = minutes;
if ((mask & 0x40) != 0) partial.seconds = seconds;
if ((mask & 0x80) != 0) partial.milliseconds = milliseconds;
if ((mask & 0x100) != 0) partial.microseconds = microseconds;
if ((mask & 0x200) != 0) partial.nanoseconds = nanoseconds;
const dur = Temporal.Duration.from(partial) catch |err| {
setLastError(err);
return 0;
};
return addDuration(dur);
}
export fn temporalz_duration_init(
years: i64,
months: i64,
weeks: i64,
days: i64,
hours: i64,
minutes: i64,
seconds: i64,
milliseconds: i64,
microseconds: f64,
nanoseconds: f64,
) u32 {
clearLastError();
const dur = Temporal.Duration.init(
years,
months,
weeks,
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds,
) catch |err| {
setLastError(err);
return 0;
};
return addDuration(dur);
}
export fn temporalz_duration_to_string(handle: u32) u64 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
const text = dur.toString(wasm_allocator, .{}) catch |err| {
setLastError(err);
return 0;
};
return packPtrLen(text.ptr, text.len);
}
export fn temporalz_duration_years(handle: u32) i64 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return dur.years();
}
export fn temporalz_duration_months(handle: u32) i64 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return dur.months();
}
export fn temporalz_duration_weeks(handle: u32) i64 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return dur.weeks();
}
export fn temporalz_duration_days(handle: u32) i64 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return dur.days();
}
export fn temporalz_duration_hours(handle: u32) i64 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return dur.hours();
}
export fn temporalz_duration_minutes(handle: u32) i64 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return dur.minutes();
}
export fn temporalz_duration_seconds(handle: u32) i64 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return dur.seconds();
}
export fn temporalz_duration_milliseconds(handle: u32) i64 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return dur.milliseconds();
}
export fn temporalz_duration_microseconds(handle: u32) f64 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return dur.microseconds();
}
export fn temporalz_duration_nanoseconds(handle: u32) f64 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return dur.nanoseconds();
}
export fn temporalz_duration_sign(handle: u32) i32 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return switch (dur.sign()) {
.positive => 1,
.zero => 0,
.negative => -1,
};
}
export fn temporalz_duration_blank(handle: u32) u8 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return if (dur.blank()) 1 else 0;
}
export fn temporalz_duration_abs(handle: u32) u32 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return addDuration(dur.abs());
}
export fn temporalz_duration_negated(handle: u32) u32 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return addDuration(dur.negated());
}
export fn temporalz_duration_add(handle_a: u32, handle_b: u32) u32 {
clearLastError();
const a = getDuration(handle_a) catch |err| {
setLastError(err);
return 0;
};
const b = getDuration(handle_b) catch |err| {
setLastError(err);
return 0;
};
const res = a.add(b) catch |err| {
setLastError(err);
return 0;
};
return addDuration(res);
}
export fn temporalz_duration_subtract(handle_a: u32, handle_b: u32) u32 {
clearLastError();
const a = getDuration(handle_a) catch |err| {
setLastError(err);
return 0;
};
const b = getDuration(handle_b) catch |err| {
setLastError(err);
return 0;
};
const res = a.subtract(b) catch |err| {
setLastError(err);
return 0;
};
return addDuration(res);
}
export fn temporalz_duration_compare(handle_a: u32, handle_b: u32) i32 {
clearLastError();
const a = getDuration(handle_a) catch |err| {
setLastError(err);
return 0;
};
const b = getDuration(handle_b) catch |err| {
setLastError(err);
return 0;
};
const res = a.compare(b, .{}) catch |err| {
setLastError(err);
return 0;
};
return @intCast(res);
}
export fn temporalz_duration_total(handle: u32, unit_code: u8) f64 {
clearLastError();
const unit = unitFromCode(unit_code) orelse {
setLastErrorMessage("Invalid unit");
return 0;
};
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
return dur.total(.{ .unit = unit }) catch |err| {
setLastError(err);
return 0;
};
}
export fn temporalz_duration_round(
handle: u32,
smallest_unit: u8,
largest_unit: u8,
rounding_mode: u8,
rounding_increment: u32,
) u32 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
var opts = Temporal.Duration.RoundingOptions{};
if (smallest_unit != 255) {
opts.smallest_unit = unitFromCode(smallest_unit) orelse {
setLastErrorMessage("Invalid smallestUnit");
return 0;
};
}
if (largest_unit != 255) {
opts.largest_unit = unitFromCode(largest_unit) orelse {
setLastErrorMessage("Invalid largestUnit");
return 0;
};
}
if (rounding_mode != 255) {
opts.rounding_mode = roundingModeFromCode(rounding_mode) orelse {
setLastErrorMessage("Invalid roundingMode");
return 0;
};
}
if (rounding_increment != 0) {
opts.rounding_increment = rounding_increment;
}
const res = dur.round(opts) catch |err| {
setLastError(err);
return 0;
};
return addDuration(res);
}
export fn temporalz_duration_compare_plain_date(handle_a: u32, handle_b: u32, date_handle: u32) i32 {
clearLastError();
const a = getDuration(handle_a) catch |err| {
setLastError(err);
return 0;
};
const b = getDuration(handle_b) catch |err| {
setLastError(err);
return 0;
};
const date = getPlainDate(date_handle) catch |err| {
setLastError(err);
return 0;
};
const res = a.compare(b, .{ .relative_to = .{ .plain_date = date } }) catch |err| {
setLastError(err);
return 0;
};
return @intCast(res);
}
export fn temporalz_duration_total_plain_date(handle: u32, unit_code: u8, date_handle: u32) f64 {
clearLastError();
const unit = unitFromCode(unit_code) orelse {
setLastErrorMessage("Invalid unit");
return 0;
};
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
const date = getPlainDate(date_handle) catch |err| {
setLastError(err);
return 0;
};
return dur.total(.{ .unit = unit, .relative_to = .{ .plain_date = date } }) catch |err| {
setLastError(err);
return 0;
};
}
export fn temporalz_duration_round_plain_date(
handle: u32,
smallest_unit: u8,
largest_unit: u8,
rounding_mode: u8,
rounding_increment: u32,
date_handle: u32,
) u32 {
clearLastError();
const dur = getDuration(handle) catch |err| {
setLastError(err);
return 0;
};
const date = getPlainDate(date_handle) catch |err| {
setLastError(err);
return 0;
};
var opts = Temporal.Duration.RoundingOptions{};
if (smallest_unit != 255) {
opts.smallest_unit = unitFromCode(smallest_unit) orelse {
setLastErrorMessage("Invalid smallestUnit");
return 0;
};
}
if (largest_unit != 255) {
opts.largest_unit = unitFromCode(largest_unit) orelse {
setLastErrorMessage("Invalid largestUnit");
return 0;
};
}
if (rounding_mode != 255) {
opts.rounding_mode = roundingModeFromCode(rounding_mode) orelse {
setLastErrorMessage("Invalid roundingMode");
return 0;
};
}
if (rounding_increment != 0) {
opts.rounding_increment = rounding_increment;
}
opts.relative_to = .{ .plain_date = date };
const res = dur.round(opts) catch |err| {
setLastError(err);
return 0;
};
return addDuration(res);
}
export fn temporalz_plain_date_from_utf8(ptr: [*]const u8, len: usize) u32 {
clearLastError();
const text = ptr[0..len];
const date = Temporal.PlainDate.from(text) catch |err| {
setLastError(err);
return 0;
};
return addPlainDate(date);
}
export fn temporalz_plain_date_init(year: i32, month: u8, day: u8) u32 {
clearLastError();
const date = Temporal.PlainDate.init(year, month, day) catch |err| {
setLastError(err);
return 0;
};
return addPlainDate(date);
}
export fn temporalz_plain_date_to_string(handle: u32) u64 {
clearLastError();
const date = getPlainDate(handle) catch |err| {
setLastError(err);
return 0;
};
const text = date.toString(wasm_allocator, .{}) catch |err| {
setLastError(err);
return 0;
};
return packPtrLen(text.ptr, text.len);
}
export fn temporalz_plain_date_destroy(handle: u32) void {
removePlainDate(handle);
}
export fn temporalz_duration_destroy(handle: u32) void {
removeDuration(handle);
}
extern fn console(ptr: [*]u8, len: u32) void;
fn logFn(comptime _: anytype, comptime _: anytype, comptime format: []const u8, args: anytype) void {
const formatted = std.fmt.allocPrint(std.heap.wasm_allocator, format, args) catch return;
console(formatted.ptr, formatted.len);
}
pub const std_options: std.Options = .{ .logFn = logFn };

View file

@ -1,144 +0,0 @@
const std = @import("std");
const targets = @import("targets.zig");
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const force_build_rust = b.option(bool, "build-rust", "Always build Rust library from source") orelse false;
const arch_str = @tagName(target.result.cpu.arch);
const os_str = @tagName(target.result.os.tag);
const abi = target.result.abi;
const target_triple = if (abi == .none)
b.fmt("{s}-{s}", .{ arch_str, os_str })
else
b.fmt("{s}-{s}-{s}", .{ arch_str, os_str, @tagName(abi) });
const prebuilt_name = targets.prebuiltName(b, target);
const lib_name = if (target.result.os.tag == .windows and abi == .msvc)
"temporal_capi.lib"
else
"libtemporal_capi.a";
// --- Module --- //
const is_freestanding = target.result.os.tag == .freestanding;
const mod = b.addModule("libtemporal", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
.link_libc = !is_freestanding,
});
const temporal_rs = b.dependency("temporal_rs", .{
.target = target,
.optimize = optimize,
});
const translated = b.addTranslateC(.{
.root_source_file = b.path("src/lib.h"),
.target = target,
.optimize = optimize,
.link_libc = false,
});
translated.addIncludePath(temporal_rs.path("temporal_capi/bindings/c"));
translated.addIncludePath(b.path("src/stubs/c_headers"));
mod.addImport("lib", translated.createModule());
// --- Rust Misc Deps --- //
if (target.result.os.tag == .windows) mod.linkSystemLibrary("userenv", .{});
const unwind_stubs = b.addLibrary(.{ .linkage = .static, .name = "unwind_stubs", .root_module = b.createModule(.{
.root_source_file = b.path("src/stubs/unwind.zig"),
.target = target,
.optimize = optimize,
}) });
mod.linkLibrary(unwind_stubs);
// --- Steps: update prebuilt dependency hashes --- //
{
const update_step = b.step("update", "Fetch prebuilt packages and update build.zig.zon");
addPrebuiltDependencyFetches(b, update_step);
}
// --- Static lib resolution (prebuilt or source) --- //
var selected_lib_file: std.Build.LazyPath = undefined;
if (!force_build_rust and targets.isDeclared(prebuilt_name)) {
const prebuilt_dep = b.lazyDependency(prebuilt_name, .{}) orelse {
return;
};
// std.log.info("using prebuilt libtemporal for {s}", .{prebuilt_name});
selected_lib_file = prebuilt_dep.path(lib_name);
} else {
std.log.info("building libtemporal from source for {s}, requires Rust toolchain", .{target_triple});
const build_crab = @import("build_crab");
var zig_target = target.result;
if (zig_target.os.tag == .windows) zig_target.abi = .gnu;
const rust_target_str: []const u8 = if (zig_target.cpu.arch == .arm and zig_target.os.tag == .linux)
switch (zig_target.abi) {
.gnueabihf, .eabihf => "armv7-unknown-linux-gnueabihf",
.gnueabi, .eabi => "armv7-unknown-linux-gnueabi",
.musleabihf => "armv7-unknown-linux-musleabihf",
.musleabi => "armv7-unknown-linux-musleabi",
else => "armv7-unknown-linux-gnueabihf",
}
else blk: {
const rust_target = build_crab.rust.Target.fromZig(zig_target) catch
@panic("unable to convert target triple to Rust");
break :blk b.fmt("{f}", .{rust_target});
};
const build_dir = build_crab.addCargoBuild(
b,
.{
.manifest_path = b.path("Cargo.toml"),
.cargo_args = if (optimize == .Debug) &.{} else &.{"--release"},
.rust_target = .{ .value = rust_target_str },
},
.{
.optimize = .ReleaseSafe,
},
);
selected_lib_file = build_dir.path(b, lib_name);
}
mod.addObjectFile(selected_lib_file);
// --- Install Step (for publishing) --- //
const install_lib = b.addInstallFile(selected_lib_file, b.fmt("lib/{s}/{s}", .{ prebuilt_name, lib_name }));
b.getInstallStep().dependOn(&install_lib.step);
}
fn addPrebuiltDependencyFetches(b: *std.Build, parent: *std.Build.Step) void {
var prev_save: ?*std.Build.Step = null;
inline for (targets.config.targets) |target_triple| {
const url = targets.releaseUrl(b, target_triple);
const fetch = b.addSystemCommand(&.{ b.graph.zig_exe, "fetch", url });
fetch.setName(b.fmt("fetch {s}", .{target_triple}));
fetch.setCwd(b.path("."));
fetch.has_side_effects = true;
fetch.expectExitCode(0);
_ = fetch.captureStdErr(.{});
const save = b.addSystemCommand(&.{
b.graph.zig_exe,
"fetch",
b.fmt("--save={s}", .{target_triple}),
url,
});
save.setName(b.fmt("save {s}", .{target_triple}));
save.setCwd(b.path("."));
save.has_side_effects = true;
save.expectExitCode(0);
_ = save.captureStdErr(.{});
save.step.dependOn(&fetch.step);
if (prev_save) |prev| {
save.step.dependOn(prev);
}
parent.dependOn(&save.step);
prev_save = &save.step;
}
}

View file

@ -1,127 +0,0 @@
.{
.name = .libtemporal,
.version = "0.2.4",
.fingerprint = 0xded01f16f20c2a64,
.dependencies = .{
.temporal_rs = .{
.url = "git+https://github.com/boa-dev/temporal?ref=v0.2.4#a5cebbcce231552bf6ed985d7ea13b0c7b195f02",
.hash = "N-V-__8AALjnOQBiCk4NffYgEewZ5v9qlLlDyXO22FIyzNdf",
},
.build_crab = .{
.url = "git+https://github.com/nurulhudaapon/build.crab?ref=zig-dev#69a630f8fa9ccca37a8ba2e898e7934e3b5b8fe2",
.hash = "build_crab-0.2.1-U0id_zfKAAAvOuam-kPYKMuEQpHuEBjrP96uQCVj94yr",
},
.@"aarch64-ios" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/aarch64-ios.tar.gz",
.hash = "N-V-__8AAJAyaADZvWvrmaGR5reVCH4y8JZ3-Gfxu_9-pcHB",
.lazy = true,
},
.@"aarch64-linux-android" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/aarch64-linux-android.tar.gz",
.hash = "N-V-__8AAKYEkwCQonhHp5MAYaRE8IFcWN493Y2a5nqWJmF7",
.lazy = true,
},
.@"aarch64-linux-gnu" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/aarch64-linux-gnu.tar.gz",
.hash = "N-V-__8AAGSQjQDYfN0voDb4c1sCM374u570U8hcEJYoAoTc",
.lazy = true,
},
.@"aarch64-linux-musl" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/aarch64-linux-musl.tar.gz",
.hash = "N-V-__8AAE7bjwA2arkXXgbgaMe8oHdmJEez8y2XFeCUvSnn",
.lazy = true,
},
.@"aarch64-macos" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/aarch64-macos.tar.gz",
.hash = "N-V-__8AAFBxZwC9MEuiOD8EihBoSl_00IDUJnpQsjmnpkmK",
.lazy = true,
},
.@"aarch64-windows-gnu" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/aarch64-windows-gnu.tar.gz",
.hash = "N-V-__8AADKDagD1bmYDywq4IZPBo2la8m1xzSObPCsxyfmW",
.lazy = true,
},
.@"arm-linux-gnueabihf" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/arm-linux-gnueabihf.tar.gz",
.hash = "N-V-__8AAIAAfgDYWro4rWudgosfdPK1tzxLe77uoRBtL4rl",
.lazy = true,
},
.@"loongarch64-linux-gnu" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/loongarch64-linux-gnu.tar.gz",
.hash = "N-V-__8AAEKptADVBZFKw7ZKvLurwzp_WA-FD-OwZFgEMf4q",
.lazy = true,
},
.@"powerpc64le-linux-gnu" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/powerpc64le-linux-gnu.tar.gz",
.hash = "N-V-__8AAKwdfQDZIHVuhOtUOs9tKx-RJCM_1HnX-FwGA0l2",
.lazy = true,
},
.@"riscv64-linux-gnu" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/riscv64-linux-gnu.tar.gz",
.hash = "N-V-__8AAPBiogBQe_5VZhzDgpZrfwuzfj_54IyUFK2igsQo",
.lazy = true,
},
.@"s390x-linux-gnu" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/s390x-linux-gnu.tar.gz",
.hash = "N-V-__8AAEiKkwC4qkNJoOuzgxHuS_q46SIbqITuODu9Hz3Q",
.lazy = true,
},
.@"wasm32-freestanding" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/wasm32-freestanding.tar.gz",
.hash = "N-V-__8AACjsTwB3jX1mva0svtTn39kCz5aabikQbczLJlp9",
.lazy = true,
},
.@"wasm32-wasi" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/wasm32-wasi.tar.gz",
.hash = "N-V-__8AAPbTQADoTDaLXmk3KlebN5pZWX-eXhD6BLPJuxpt",
.lazy = true,
},
.@"x86-linux-gnu" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/x86-linux-gnu.tar.gz",
.hash = "N-V-__8AALzUbwBdOV8TmU7vPbofrSgkCz70GG0SwvHZGWEZ",
.lazy = true,
},
.@"x86-windows-gnu" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/x86-windows-gnu.tar.gz",
.hash = "N-V-__8AAAgSYQAjy_QNLkxQurUPnbT8s4fNjunaYgPQjiwB",
.lazy = true,
},
.@"x86_64-freebsd" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/x86_64-freebsd.tar.gz",
.hash = "N-V-__8AAJAFkQCAz3khARx91vZb6HMPqV3oBdmJM8kaxd9Y",
.lazy = true,
},
.@"x86_64-linux-gnu" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/x86_64-linux-gnu.tar.gz",
.hash = "N-V-__8AACAdiQB3WUysJXS42gsJZdpzna_04l6omEQGzJZa",
.lazy = true,
},
.@"x86_64-linux-musl" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/x86_64-linux-musl.tar.gz",
.hash = "N-V-__8AAGhKiwDlW7Ecy5CJf7-PEGSdDgr4VnCNLkl9cery",
.lazy = true,
},
.@"x86_64-macos" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/x86_64-macos.tar.gz",
.hash = "N-V-__8AAHDyZwCPo6HVOYeFWas2bcTqi67vJuxoL2huROlC",
.lazy = true,
},
.@"x86_64-netbsd" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/x86_64-netbsd.tar.gz",
.hash = "N-V-__8AAL7_lgBmD0lfXqzAxRdjDiPLi6bgLvnVVbQszw3p",
.lazy = true,
},
.@"x86_64-windows-gnu" = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.4/x86_64-windows-gnu.tar.gz",
.hash = "N-V-__8AAD5eTQDfQ9ddNZh3g8e6SaA9CnVSQRMozhHs_jWt",
.lazy = true,
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"targets.zon",
"targets.zig",
"src",
},
}

View file

@ -1,18 +0,0 @@
#include "AnyCalendarKind.h"
#include "Calendar.h"
#include "Duration.h"
#include "ErrorKind.h"
#include "I128Nanoseconds.h"
#include "Instant.h"
#include "OwnedRelativeTo.h"
#include "ParsedDate.h"
#include "ParsedDateTime.h"
#include "ParsedZonedDateTime.h"
#include "PlainDate.h"
#include "PlainDateTime.h"
#include "PlainMonthDay.h"
#include "PlainTime.h"
#include "PlainYearMonth.h"
#include "RelativeTo.h"
#include "TimeZone.h"
#include "ZonedDateTime.h"

View file

@ -1 +0,0 @@
pub const c = @import("lib");

View file

@ -1,57 +0,0 @@
const std = @import("std");
const builtin = @import("builtin");
pub const config = @import("targets.zon");
const manifest = @import("build.zig.zon");
/// Zig `-Dtarget` triple for the host platform's prebuilt dependency name.
pub fn depName() []const u8 {
const triple = targetTripleFromBuiltin();
if (!isDeclared(triple)) {
@compileError(std.fmt.comptimePrint(
"no prebuilt libtemporal for host {s}",
.{triple},
));
}
return triple;
}
pub fn prebuiltName(b: *std.Build, target: std.Build.ResolvedTarget) []const u8 {
const arch = @tagName(target.result.cpu.arch);
const os = target.result.os.tag;
const abi = target.result.abi;
if (os == .wasi and (abi == .musl or abi == .none))
return b.fmt("{s}-wasi", .{arch});
if (abi == .none)
return b.fmt("{s}-{s}", .{ arch, @tagName(os) });
return b.fmt("{s}-{s}-{s}", .{ arch, @tagName(os), @tagName(abi) });
}
pub fn isDeclared(target_triple: []const u8) bool {
inline for (config.targets) |supported| {
if (std.mem.eql(u8, supported, target_triple)) {
return comptime @hasField(@TypeOf(manifest.dependencies), supported);
}
}
return false;
}
pub fn releaseUrl(b: *std.Build, target_triple: []const u8) []const u8 {
return b.fmt(
"https://github.com/nurulhudaapon/temporalz/releases/download/v{s}/{s}.tar.gz",
.{ config.version, target_triple },
);
}
fn targetTripleFromBuiltin() []const u8 {
if (builtin.os.tag == .wasi and (builtin.abi == .musl or builtin.abi == .none))
return std.fmt.comptimePrint("{s}-wasi", .{@tagName(builtin.cpu.arch)});
const abi = builtin.abi;
return if (abi == .none)
std.fmt.comptimePrint("{s}-{s}", .{ @tagName(builtin.cpu.arch), @tagName(builtin.os.tag) })
else
std.fmt.comptimePrint("{s}-{s}-{s}", .{ @tagName(builtin.cpu.arch), @tagName(builtin.os.tag), @tagName(abi) });
}

View file

@ -1,26 +0,0 @@
.{
.version = "0.2.4",
.targets = .{
"x86_64-macos",
"aarch64-macos",
"x86_64-linux-gnu",
"aarch64-linux-gnu",
"x86-linux-gnu",
"arm-linux-gnueabihf",
"loongarch64-linux-gnu",
"powerpc64le-linux-gnu",
"riscv64-linux-gnu",
"s390x-linux-gnu",
"x86_64-windows-gnu",
"aarch64-windows-gnu",
"x86-windows-gnu",
"x86_64-freebsd",
"x86_64-netbsd",
"wasm32-freestanding",
"wasm32-wasi",
"x86_64-linux-musl",
"aarch64-linux-musl",
"aarch64-linux-android",
"aarch64-ios",
},
}

View file

@ -16,9 +16,9 @@ checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
[[package]]
name = "calendrical_calculations"
version = "0.2.4"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5abbd6eeda6885048d357edc66748eea6e0268e3dd11f326fff5bd248d779c26"
checksum = "3a0b39595c6ee54a8d0900204ba4c401d0ab4eb45adaf07178e8d017541529e7"
dependencies = [
"core_maths",
"displaydoc",
@ -45,9 +45,9 @@ dependencies = [
[[package]]
name = "diplomat"
version = "0.15.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7935649d00000f5c5d735448ad3dc07b9738160727017914cf42138b8e8e6611"
checksum = "9adb46b05e2f53dcf6a7dfc242e4ce9eb60c369b6b6eb10826a01e93167f59c6"
dependencies = [
"diplomat_core",
"proc-macro2",
@ -57,15 +57,15 @@ dependencies = [
[[package]]
name = "diplomat-runtime"
version = "0.15.1"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "970ac38ad677632efcee6d517e783958da9bc78ec206d8d5e35b459ffc5e4864"
checksum = "0569bd3caaf13829da7ee4e83dbf9197a0e1ecd72772da6d08f0b4c9285c8d29"
[[package]]
name = "diplomat_core"
version = "0.15.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf41b94101a4bce993febaf0098092b0bb31deaf0ecaf6e0a2562465f61b383"
checksum = "51731530ed7f2d4495019abc7df3744f53338e69e2863a6a64ae91821c763df1"
dependencies = [
"proc-macro2",
"quote",
@ -88,9 +88,9 @@ dependencies = [
[[package]]
name = "icu_calendar"
version = "2.2.1"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2b2acc6263f494f1df50685b53ff8e57869e47d5c6fe39c23d518ae9a4f3e45"
checksum = "d6f0e52e009b6b16ba9c0693578796f2dd4aaa59a7f8f920423706714a89ac4e"
dependencies = [
"calendrical_calculations",
"displaydoc",
@ -104,19 +104,18 @@ dependencies = [
[[package]]
name = "icu_calendar_data"
version = "2.2.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "118577bcf3a0fa7c6ac0a7d6e951814da84ee56b9b1f68fb4d8d10b08cefaf4d"
checksum = "527f04223b17edfe0bd43baf14a0cb1b017830db65f3950dc00224860a9a446d"
[[package]]
name = "icu_collections"
version = "2.2.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
dependencies = [
"displaydoc",
"potential_utf",
"utf8_iter",
"yoke",
"zerofrom",
"zerovec",
@ -124,9 +123,9 @@ dependencies = [
[[package]]
name = "icu_locale"
version = "2.2.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5a396343c7208121dc86e35623d3dfe19814a7613cfd14964994cdc9c9a2e26"
checksum = "532b11722e350ab6bf916ba6eb0efe3ee54b932666afec989465f9243fe6dd60"
dependencies = [
"icu_collections",
"icu_locale_core",
@ -139,9 +138,9 @@ dependencies = [
[[package]]
name = "icu_locale_core"
version = "2.2.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
dependencies = [
"displaydoc",
"litemap",
@ -153,15 +152,15 @@ dependencies = [
[[package]]
name = "icu_locale_data"
version = "2.2.0"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5fdcc9ac77c6d74ff5cf6e65ef3181d6af32003b16fce3a77fb451d2f695993"
checksum = "1c5f1d16b4c3a2642d3a719f18f6b06070ab0aef246a6418130c955ae08aa831"
[[package]]
name = "icu_provider"
version = "2.2.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
dependencies = [
"displaydoc",
"icu_locale_core",
@ -317,22 +316,22 @@ dependencies = [
[[package]]
name = "temporal_capi"
version = "0.2.3"
version = "0.2.0"
dependencies = [
"temporal_capi 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"temporal_capi 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"temporal_rs",
]
[[package]]
name = "temporal_capi"
version = "0.2.3"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a2a1f001e756a9f5f2d175a9965c4c0b3a054f09f30de3a75ab49765f2deb36"
checksum = "64a85237ba1a9512ac9217a71fdbeed3295bb97e72aa0e3cd005d42dc92eeb55"
dependencies = [
"diplomat",
"diplomat-runtime",
"icu_calendar",
"icu_locale_core",
"icu_locale",
"num-traits",
"temporal_rs",
"timezone_provider",
@ -341,14 +340,13 @@ dependencies = [
[[package]]
name = "temporal_rs"
version = "0.2.3"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a902a45282e5175186b21d355efc92564601efe6e2d92818dc9e333d50bd4de"
checksum = "654b89203889c8b90b96d275d1296c56df5f0ffee127213730c1b9895b69b33e"
dependencies = [
"calendrical_calculations",
"core_maths",
"icu_calendar",
"icu_locale_core",
"icu_locale",
"ixdtf",
"num-traits",
"timezone_provider",
@ -358,9 +356,9 @@ dependencies = [
[[package]]
name = "timezone_provider"
version = "0.2.3"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c48f9b04628a2b813051e4dfe97c65281e49625eabd09ec343190e31e399a8c2"
checksum = "838a6ce9f08d07a637682a7dda441b97dc34e4aaf0dbfd9ca3d7eaf6fe1e8495"
dependencies = [
"combine",
"jiff-tzdb",
@ -372,9 +370,9 @@ dependencies = [
[[package]]
name = "tinystr"
version = "0.8.3"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
dependencies = [
"displaydoc",
"serde_core",
@ -396,12 +394,6 @@ version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "utf8_iter"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "writeable"
version = "0.6.2"
@ -410,9 +402,9 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
[[package]]
name = "yoke"
version = "0.8.2"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
dependencies = [
"stable_deref_trait",
"yoke-derive",
@ -421,9 +413,9 @@ dependencies = [
[[package]]
name = "yoke-derive"
version = "0.8.2"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
dependencies = [
"proc-macro2",
"quote",
@ -454,19 +446,18 @@ dependencies = [
[[package]]
name = "zerotrie"
version = "0.2.4"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
dependencies = [
"displaydoc",
"zerovec",
]
[[package]]
name = "zerovec"
version = "0.11.6"
version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
dependencies = [
"serde",
"yoke",
@ -476,9 +467,9 @@ dependencies = [
[[package]]
name = "zerovec-derive"
version = "0.11.3"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
dependencies = [
"proc-macro2",
"quote",

View file

@ -1,15 +1,15 @@
[package]
name = "temporal_capi"
version = "0.2.3"
version = "0.2.0"
edition = "2024"
[dependencies.temporal_capi]
version = "0.2.3"
version = "0.2.0"
default-features = false
features = ["compiled_data"]
[dependencies.temporal_rs]
version = "0.2.3"
version = "0.2.0"
default-features = false
features = ["float64_representable_durations"]

89
pkg/temporal/build.zig Normal file
View file

@ -0,0 +1,89 @@
const std = @import("std");
pub fn build(b: *std.Build) !void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const force_build_rust = b.option(bool, "build-rust", "Always build Rust library from source") orelse false;
const arch_str = @tagName(target.result.cpu.arch);
const os_str = @tagName(target.result.os.tag);
const abi = target.result.abi;
const target_triple = if (abi == .none)
b.fmt("{s}-{s}", .{ arch_str, os_str })
else
b.fmt("{s}-{s}-{s}", .{ arch_str, os_str, @tagName(abi) });
const lib_name = if (target.result.os.tag == .windows and abi == .msvc)
"temporal_capi.lib"
else
"libtemporal_capi.a";
const prebuilt_lib_path = b.fmt("{s}/{s}", .{ target_triple, lib_name });
// --- Pre-built resolution --- //
var prebuilt_lib_file: ?std.Build.LazyPath = null;
var selected_lib_file: std.Build.LazyPath = undefined;
if (!force_build_rust) {
const libtemporal_dep = b.lazyDependency("libtemporal", .{});
if (libtemporal_dep) |dep| {
const lib_file_candidate = dep.path(prebuilt_lib_path);
const lib_full_path = lib_file_candidate.getPath(b);
if (std.Io.Dir.cwd().openFile(b.graph.io, lib_full_path, .{})) |lib_check_file| {
lib_check_file.close(b.graph.io);
prebuilt_lib_file = lib_file_candidate;
} else |_| {}
}
}
if (prebuilt_lib_file) |plf| {
// std.debug.print("Using pre-built temporal_capi library from downloaded artifact at: {s}\n", .{prebuilt_lib_path});
selected_lib_file = plf;
} else {
// std.debug.print("building from source: {s}\n", .{prebuilt_lib_path});
const build_crab = @import("build_crab");
const build_dir = build_crab.addCargoBuild(
b,
.{
.manifest_path = b.path("Cargo.toml"),
.cargo_args = if (optimize == .Debug) &.{} else &.{"--release"},
},
.{
.target = target,
.optimize = .ReleaseSafe,
},
);
selected_lib_file = build_dir.path(b, lib_name);
}
// --- Install Step (for publishing) --- //
const install_lib = b.addInstallFile(selected_lib_file, b.fmt("lib/{s}/{s}", .{ target_triple, lib_name }));
b.getInstallStep().dependOn(&install_lib.step);
// --- Zig Module --- //
const mod = b.addModule("temporal_rs", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
// Add Headers
const temporal_rs_git = b.dependency("temporal_rs", .{
.target = target,
.optimize = optimize,
});
mod.addIncludePath(temporal_rs_git.path("temporal_capi/bindings/c"));
mod.addIncludePath(b.path("src/stubs/c_headers"));
// Add Object/Library
mod.addObjectFile(selected_lib_file);
// --- Rust Misc Deps --- //
if (target.result.os.tag == .windows) mod.linkSystemLibrary("userenv", .{});
const unwind_stubs = b.addLibrary(.{ .linkage = .static, .name = "unwind_stubs", .root_module = b.createModule(.{
.root_source_file = b.path("src/stubs/unwind.zig"),
.target = target,
.optimize = optimize,
}) });
mod.linkLibrary(unwind_stubs);
}

View file

@ -0,0 +1,26 @@
.{
.name = .temporal,
.version = "0.2.0",
.fingerprint = 0xd5dcf3f41df6b117,
.minimum_zig_version = "0.16.0-dev.2565+684032671",
.dependencies = .{
.temporal_rs = .{
.url = "git+https://github.com/boa-dev/temporal?ref=v0.2.0#ad01ef6f6147345f35a6614bf942a83af14098dd",
.hash = "N-V-__8AAN1tOQBrOGLjyyZop7RoeAqcozA7dKIZKD30hcom",
},
.libtemporal = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.0/libtemporal.tar.gz",
.hash = "N-V-__8AAHgP2AWLC4ZLTr_3hWf6xtgtBI5moBrWDWg5kzSD",
.lazy = true,
},
.build_crab = .{
.url = "git+https://github.com/nurulhudaapon/build.crab?ref=zig-dev#1aabc836472d318e9756a43b17853aadc4599800",
.hash = "build_crab-0.2.1-U0id_2LFAABPaq1t9eBZ3p0aA87c-HkKZPYCrCVcgvt6",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

20
pkg/temporal/src/root.zig Normal file
View file

@ -0,0 +1,20 @@
pub const c = @cImport({
@cInclude("AnyCalendarKind.h");
@cInclude("Calendar.h");
@cInclude("Duration.h");
@cInclude("ErrorKind.h");
@cInclude("I128Nanoseconds.h");
@cInclude("Instant.h");
@cInclude("OwnedRelativeTo.h");
@cInclude("ParsedDate.h");
@cInclude("ParsedDateTime.h");
@cInclude("ParsedZonedDateTime.h");
@cInclude("PlainDate.h");
@cInclude("PlainDateTime.h");
@cInclude("PlainMonthDay.h");
@cInclude("PlainTime.h");
@cInclude("PlainYearMonth.h");
@cInclude("RelativeTo.h");
@cInclude("TimeZone.h");
@cInclude("ZonedDateTime.h");
});

View file

@ -8,8 +8,7 @@ const ZonedDateTime = @import("ZonedDateTime.zig");
/// The `Temporal.Duration` object represents a difference between two time points, which can be used in date/time arithmetic.
/// It is fundamentally represented as a combination of years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, and nanoseconds values.
///
/// See: [Temporal.Duration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration
const Duration = @This();
_inner: *abi.c.Duration,
@ -41,8 +40,7 @@ pub const RoundingOptions = struct {
/// Partial duration specification for creating Duration objects.
/// This is a wrapper around the C API type to avoid exposing C types directly.
///
/// See: [Temporal.Duration.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/from)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/from
pub const PartialDuration = struct {
years: ?i64 = null,
months: ?i64 = null,
@ -57,8 +55,7 @@ pub const PartialDuration = struct {
};
/// Relative-to context for duration operations, used for balancing and calendar-aware math.
///
/// See: [Temporal.Duration#calendar_durations](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration#calendar_durations)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration#calendar_durations
pub const RelativeTo = union(enum) {
plain_date: PlainDate,
plain_date_time: PlainDateTime,
@ -81,8 +78,7 @@ pub const CompareOptions = struct {
/// Construct a Duration from years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, and nanoseconds.
/// Equivalent to `Temporal.Duration()` constructor.
///
/// See: [Temporal.Duration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/Duration)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/Duration
pub fn init(
years_val: i64,
months_val: i64,
@ -168,122 +164,105 @@ fn isTimeWithinRange(self: Duration) bool {
}
/// Returns the number of years in the duration.
///
/// See: [Temporal.Duration.years](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/years)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/years
pub fn years(self: Duration) i64 {
return abi.c.temporal_rs_Duration_years(self._inner);
}
/// Returns the number of months in the duration.
///
/// See: [Temporal.Duration.months](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/months)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/months
pub fn months(self: Duration) i64 {
return abi.c.temporal_rs_Duration_months(self._inner);
}
/// Returns the number of weeks in the duration.
///
/// See: [Temporal.Duration.weeks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/weeks)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/weeks
pub fn weeks(self: Duration) i64 {
return abi.c.temporal_rs_Duration_weeks(self._inner);
}
/// Returns the number of days in the duration.
///
/// See: [Temporal.Duration.days](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/days)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/days
pub fn days(self: Duration) i64 {
return abi.c.temporal_rs_Duration_days(self._inner);
}
/// Returns the number of hours in the duration.
///
/// See: [Temporal.Duration.hours](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/hours)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/hours
pub fn hours(self: Duration) i64 {
return abi.c.temporal_rs_Duration_hours(self._inner);
}
/// Returns the number of minutes in the duration.
///
/// See: [Temporal.Duration.minutes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/minutes)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/minutes
pub fn minutes(self: Duration) i64 {
return abi.c.temporal_rs_Duration_minutes(self._inner);
}
/// Returns the number of seconds in the duration.
///
/// See: [Temporal.Duration.seconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/seconds)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/seconds
pub fn seconds(self: Duration) i64 {
return abi.c.temporal_rs_Duration_seconds(self._inner);
}
/// Returns the number of milliseconds in the duration.
///
/// See: [Temporal.Duration.milliseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/milliseconds)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/milliseconds
pub fn milliseconds(self: Duration) i64 {
return abi.c.temporal_rs_Duration_milliseconds(self._inner);
}
/// Returns the number of microseconds in the duration.
///
/// See: [Temporal.Duration.microseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/microseconds)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/microseconds
pub fn microseconds(self: Duration) f64 {
return abi.c.temporal_rs_Duration_microseconds(self._inner);
}
/// Returns the number of nanoseconds in the duration.
///
/// See: [Temporal.Duration.nanoseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/nanoseconds)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/nanoseconds
pub fn nanoseconds(self: Duration) f64 {
return abi.c.temporal_rs_Duration_nanoseconds(self._inner);
}
/// Returns the sign of the duration: positive (1), zero (0), or negative (-1).
///
/// See: [Temporal.Duration.sign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/sign)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/sign
pub fn sign(self: Duration) Sign {
return abi.from.sign(abi.c.temporal_rs_Duration_sign(self._inner));
}
/// Returns true if the duration is zero (all fields are zero), false otherwise.
///
/// See: [Temporal.Duration.blank](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/blank)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/blank
pub fn blank(self: Duration) bool {
return abi.c.temporal_rs_Duration_is_zero(self._inner);
}
/// Returns a new Duration with the absolute value (all components positive).
///
/// See: [Temporal.Duration.abs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/abs)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/abs
pub fn abs(self: Duration) Duration {
const ptr: *abi.c.Duration = abi.c.temporal_rs_Duration_abs(self._inner) orelse unreachable;
return .{ ._inner = ptr };
}
/// Returns a new Duration with all components negated (sign reversed).
///
/// See: [Temporal.Duration.negated](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/negated)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/negated
pub fn negated(self: Duration) Duration {
const ptr: *abi.c.Duration = abi.c.temporal_rs_Duration_negated(self._inner) orelse unreachable;
return .{ ._inner = ptr };
}
/// Returns a new Duration with the sum of this duration and another (balanced as needed).
///
/// See: [Temporal.Duration.add](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/add)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/add
pub fn add(self: Duration, other: Duration) !Duration {
return wrapDuration(abi.c.temporal_rs_Duration_add(self._inner, other._inner));
}
/// Returns a new Duration with the difference between this duration and another (balanced as needed).
///
/// See: [Temporal.Duration.subtract](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/subtract)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/subtract
pub fn subtract(self: Duration, other: Duration) !Duration {
return wrapDuration(abi.c.temporal_rs_Duration_subtract(self._inner, other._inner));
}
/// Returns a new Duration rounded to the given smallest/largest unit and/or balanced.
///
/// See: [Temporal.Duration.round](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/round)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/round
pub fn round(self: Duration, options: RoundingOptions) !Duration {
const rel = if (options.relative_to) |r| abi.to.durRelativeTo(r) else abi.c.RelativeTo{ .date = null, .zoned = null };
return wrapDuration(abi.c.temporal_rs_Duration_round(self._inner, abi.to.durRoundingOpts(options), rel));
@ -295,8 +274,7 @@ fn roundWithProvider(self: Duration, options: RoundingOptions, relative_to: Rela
}
/// Compares two durations, returning -1, 0, or 1 if this duration is shorter, equal, or longer than the other.
///
/// See: [Temporal.Duration.compare](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/compare)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/compare
pub fn compare(self: Duration, other: Duration, options: CompareOptions) !i8 {
const rel = if (options.relative_to) |r| abi.to.durRelativeTo(r) else abi.c.RelativeTo{ .date = null, .zoned = null };
const res = abi.c.temporal_rs_Duration_compare(self._inner, other._inner, rel);
@ -310,8 +288,7 @@ fn compareWithProvider(self: Duration, other: Duration, relative_to: RelativeTo,
}
/// Returns the total value of the duration in the specified unit.
///
/// See: [Temporal.Duration.total](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/total)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/total
pub fn total(self: Duration, options: TotalOptions) !f64 {
const rel = if (options.relative_to) |r| abi.to.durRelativeTo(r) else abi.c.RelativeTo{ .date = null, .zoned = null };
const res = abi.c.temporal_rs_Duration_total(self._inner, abi.to.unit(options.unit).?, rel);
@ -326,8 +303,7 @@ fn totalWithProvider(self: Duration, options: TotalOptions, provider: *const abi
}
/// Returns a string representing this duration in the ISO 8601 format.
///
/// See: [Temporal.Duration.toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toString)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toString
pub fn toString(self: Duration, allocator: std.mem.Allocator, options: ToStringRoundingOptions) ![]u8 {
var write = abi.DiplomatWrite.init(allocator);
defer write.deinit();
@ -339,16 +315,13 @@ pub fn toString(self: Duration, allocator: std.mem.Allocator, options: ToStringR
}
/// Returns a string representing this duration in the ISO 8601 format (same as toString). Intended for JSON serialization.
///
/// See: [Temporal.Duration.toJSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toJSON)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toJSON
pub fn toJSON(self: Duration, allocator: std.mem.Allocator) ![]u8 {
return self.toString(allocator, .{});
}
/// Returns a string with a language-sensitive representation of this duration.
/// Not implemented.
///
/// See: [Temporal.Duration.toLocaleString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toLocaleString)
/// Returns a string with a language-sensitive representation of this duration. Not implemented.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toLocaleString
pub fn toLocaleString(self: Duration, allocator: std.mem.Allocator) ![]u8 {
_ = self;
_ = allocator;
@ -366,6 +339,8 @@ pub fn deinit(self: Duration) void {
abi.c.temporal_rs_Duration_destroy(self._inner);
}
// --- Helpers -----------------------------------------------------------------
inline fn handleVoidResult(res: anytype) !void {
_ = try abi.extractResult(res);
}
@ -376,6 +351,8 @@ fn wrapDuration(res: anytype) !Duration {
return .{ ._inner = ptr.? };
}
// --- Aliases and enums ------------------------------------------
const OptionU8 = abi.c.OptionU8;
const OptionU32 = abi.c.OptionU32;
const OptionI64 = abi.c.OptionI64;
@ -384,6 +361,8 @@ const Precision = abi.c.Precision;
const Unit_option = abi.c.Unit_option;
const RoundingMode_option = abi.c.RoundingMode_option;
// --- Tests -------------------------------------------------------------------
test init {
// Create a simple duration: 1 hour, 30 minutes
const dur = try Duration.init(0, 0, 0, 0, 1, 30, 0, 0, 0, 0);
@ -687,6 +666,7 @@ test nanoseconds {
const ns = dur.nanoseconds();
try std.testing.expect(ns > 499 and ns < 501);
}
test sign {
const pos = try Duration.from("P1Y");
defer pos.deinit();

View file

@ -3,12 +3,10 @@ const abi = @import("abi.zig");
const t = @import("temporal.zig");
const Duration = @import("Duration.zig");
const ZonedDateTime = @import("ZonedDateTime.zig");
/// The `Temporal.Instant` object represents a unique point in time, with nanosecond precision.
/// It is fundamentally represented as the number of nanoseconds since the Unix epoch (midnight at the beginning of January 1, 1970, UTC), without any time zone or calendar system.
///
/// See: [Temporal.Instant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant
const Instant = @This();
_inner: *abi.c.Instant,
@ -27,8 +25,7 @@ pub const DifferenceSettings = t.DifferenceSettings;
pub const TimeZone = t.TimeZone;
/// Options for Instant.toString().
///
/// See: [Temporal.Instant.toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toString)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toString
pub const ToStringOptions = struct {
/// Either an integer from 0 to 9, or null for "auto".
/// If null (auto), trailing zeros are removed from the fractional seconds.
@ -49,31 +46,26 @@ pub const ToStringOptions = struct {
};
/// Construct an Instant from epoch nanoseconds (Temporal.Instant.fromEpochNanoseconds).
///
/// See: [Temporal.Instant.fromEpochNanoseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/fromEpochNanoseconds)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/fromEpochNanoseconds
pub fn init(epoch_ns: i128) !Instant {
return fromEpochNanoseconds(epoch_ns);
}
/// Construct an Instant from epoch milliseconds (Temporal.Instant.fromEpochMilliseconds).
///
/// See: [Temporal.Instant.fromEpochMilliseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/fromEpochMilliseconds)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/fromEpochMilliseconds
pub fn fromEpochMilliseconds(epoch_ms: i64) !Instant {
return wrapInstant(abi.c.temporal_rs_Instant_from_epoch_milliseconds(epoch_ms));
}
/// Construct an Instant from epoch nanoseconds (Temporal.Instant.fromEpochNanoseconds).
///
/// See: [Temporal.Instant.fromEpochNanoseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/fromEpochNanoseconds)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/fromEpochNanoseconds
pub fn fromEpochNanoseconds(epoch_ns: i128) !Instant {
const parts = abi.toI128Nanoseconds(epoch_ns);
return wrapInstant(abi.c.temporal_rs_Instant_try_new(parts));
}
/// Parse an RFC 9557 string (Temporal.Instant.from) or from another Temporal.Instant.
///
/// See: [Temporal.Instant.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/from)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/from
pub fn from(info: anytype) !Instant {
const T = @TypeOf(info);
@ -109,59 +101,51 @@ inline fn fromUtf8(text: []const u8) !Instant {
}
/// Returns a new Instant representing this instant moved forward by a given Duration.
///
/// See: [Temporal.Instant.add](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/add)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/add
pub fn add(self: Instant, duration: *Duration) !Instant {
return wrapInstant(abi.c.temporal_rs_Instant_add(self._inner, duration._inner));
}
/// Returns a new Instant representing this instant moved backward by a given Duration.
///
/// See: [Temporal.Instant.subtract](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/subtract)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/subtract
pub fn subtract(self: Instant, duration: *Duration) !Instant {
return wrapInstant(abi.c.temporal_rs_Instant_subtract(self._inner, duration._inner));
}
/// Returns a Duration representing the difference from this instant until another instant.
///
/// See: [Temporal.Instant.until](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/until)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/until
pub fn until(self: Instant, other: Instant, settings: DifferenceSettings) !Duration {
const ptr = (try abi.extractResult(abi.c.temporal_rs_Instant_until(self._inner, other._inner, abi.to.diffsettings(settings)))) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
/// Returns a Duration representing the difference from another instant until this instant.
///
/// See: [Temporal.Instant.since](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/since)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/since
pub fn since(self: Instant, other: Instant, settings: DifferenceSettings) !Duration {
const ptr = (try abi.extractResult(abi.c.temporal_rs_Instant_since(self._inner, other._inner, abi.to.diffsettings(settings)))) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
/// Returns a new Instant rounded to the given unit.
///
/// See: [Temporal.Instant.round](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/round)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/round
pub fn round(self: Instant, options: RoundingOptions) !Instant {
return wrapInstant(abi.c.temporal_rs_Instant_round(self._inner, abi.to.roundingOpts(options)));
}
/// Compares two Instants, returning -1, 0, or 1 if the first is before, equal, or after the second.
///
/// See: [Temporal.Instant.compare](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/compare)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/compare
pub fn compare(a: Instant, b: Instant) i8 {
return abi.c.temporal_rs_Instant_compare(a._inner, b._inner);
}
/// Returns true if two Instants are equal (same epoch nanoseconds).
///
/// See: [Temporal.Instant.equals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/equals)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/equals
pub fn equals(a: Instant, b: Instant) bool {
return abi.c.temporal_rs_Instant_equals(a._inner, b._inner);
}
/// Returns a string representing this instant in the RFC 9557 format, optionally using a time zone.
///
/// See: [Temporal.Instant.toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toString)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toString
pub fn toString(self: Instant, allocator: std.mem.Allocator, opts: ToStringOptions) ![]u8 {
const zone_opt = if (opts.time_zone) |tz| abi.toTimeZoneOption(tz._inner) else abi.toTimeZoneOption(null);
const rounding = optsToRounding(opts);
@ -190,22 +174,19 @@ fn toStringWithProvider(self: Instant, allocator: std.mem.Allocator, provider: *
}
/// Returns a string representing this instant in the RFC 9557 format (same as toString). Intended for JSON serialization.
///
/// See: [Temporal.Instant.toJSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toJSON)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toJSON
pub fn toJSON(self: Instant, allocator: std.mem.Allocator) ![]u8 {
return self.toString(allocator, .{});
}
/// Returns a string with a language-sensitive representation of this instant.
///
/// See: [Temporal.Instant.toLocaleString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toLocaleString)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toLocaleString
pub fn toLocaleString(self: Instant, allocator: std.mem.Allocator) ![]u8 {
return self.toString(allocator, .{});
}
/// Returns a ZonedDateTime representing this instant in the specified time zone using the ISO 8601 calendar system.
///
/// See: [Temporal.Instant.toZonedDateTimeISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toZonedDateTimeISO)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toZonedDateTimeISO
pub fn toZonedDateTimeISO(self: Instant, zone: TimeZone) !ZonedDateTime {
const ptr = (try abi.extractResult(abi.c.temporal_rs_Instant_to_zoned_date_time_iso(self._inner, zone._inner))) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
@ -224,15 +205,13 @@ fn clone(self: Instant) Instant {
}
/// Returns the number of milliseconds since the Unix epoch for this instant.
///
/// See: [Temporal.Instant.epochMilliseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/epochMilliseconds)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/epochMilliseconds
pub fn epochMilliseconds(self: Instant) i64 {
return abi.c.temporal_rs_Instant_epoch_milliseconds(self._inner);
}
/// Returns the number of nanoseconds since the Unix epoch for this instant.
///
/// See: [Temporal.Instant.epochNanoseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/epochNanoseconds)
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/epochNanoseconds
pub fn epochNanoseconds(self: Instant) i128 {
return abi.fromI128Nanoseconds(abi.c.temporal_rs_Instant_epoch_nanoseconds(self._inner));
}
@ -242,6 +221,8 @@ pub fn deinit(self: Instant) void {
abi.c.temporal_rs_Instant_destroy(self._inner);
}
// --- Helpers -----------------------------------------------------------------
fn wrapInstant(res: anytype) !Instant {
const ptr = (try abi.extractResult(res)) orelse return abi.TemporalError.Generic;
return .{
@ -279,6 +260,18 @@ fn optsToRounding(opts: ToStringOptions) abi.c.ToStringRoundingOptions {
};
}
// --- Forward declarations -----------------------------------------------------
const ZonedDateTime = struct {
_inner: *abi.c.ZonedDateTime,
pub fn deinit(self: ZonedDateTime) void {
abi.c.temporal_rs_ZonedDateTime_destroy(self._inner);
}
};
// --- Tests -------------------------------------------------------------------
test init {
const epoch_ns: i128 = 1_704_067_200_000_000_000; // 2024-01-01T00:00:00Z
const inst = try Instant.init(epoch_ns);
@ -526,17 +519,7 @@ test toJSON {
}
test toZonedDateTimeISO {
const inst = try Instant.fromEpochMilliseconds(1704067200000);
defer inst.deinit();
const zdt = try inst.toZonedDateTimeISO(try TimeZone.init("UTC"));
defer zdt.deinit();
try std.testing.expectEqual(@as(i32, 2024), zdt.year());
try std.testing.expectEqual(@as(u8, 1), zdt.month());
try std.testing.expectEqual(@as(u8, 1), zdt.day());
try std.testing.expectEqual(@as(u8, 0), zdt.hour());
try std.testing.expectEqual(@as(i128, 1_704_067_200_000_000_000), zdt.epochNanoseconds());
if (true) return error.SkipZigTest;
}
test epochMilliseconds {

View file

@ -3,15 +3,13 @@ const Instant = @import("Instant.zig");
const PlainDate = @import("PlainDate.zig");
const PlainDateTime = @import("PlainDateTime.zig");
const PlainTime = @import("PlainTime.zig");
const SystemTimeZone = @import("SystemTimeZone.zig");
const ZonedDateTime = @import("ZonedDateTime.zig");
const abi = @import("abi.zig");
/// # Temporal.Now
///
/// The `Temporal.Now` namespace object contains static methods for getting the current time in various formats.
///
/// See: [Temporal.Now](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now)
/// - [MDN Temporal.Now](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now)
///
/// ## Description
///
@ -31,7 +29,7 @@ const Now = @This();
/// Returns the current time as a [`Temporal.Instant`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant) object.
///
/// See: [Temporal.Now.instant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/instant)
/// See: [MDN Temporal.Now.instant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/instant)
pub fn instant(io: std.Io) !Instant {
const ns = std.Io.Timestamp.now(io, .real).nanoseconds;
return Instant.fromEpochNanoseconds(ns);
@ -39,80 +37,102 @@ pub fn instant(io: std.Io) !Instant {
/// Returns the current date as a [`Temporal.PlainDate`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDate) object, in the ISO 8601 calendar and the specified time zone.
///
/// When `time_zone_like` is null, the system time zone is used.
///
/// See: [Temporal.Now.plainDateISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/plainDateISO)
pub fn plainDateISO(allocator: std.mem.Allocator, io: std.Io, time_zone_like: ?[]const u8) !PlainDate {
const time_zone = try resolveTimeZone(allocator, io, time_zone_like);
const now = try instant(io);
defer now.deinit();
const ptr = (try abi.extractResult(abi.c.temporal_rs_PlainDate_from_epoch_nanoseconds(
abi.toI128Nanoseconds(now.epochNanoseconds()),
abi.to.toTimeZone(time_zone),
))) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
/// See: [MDN Temporal.Now.plainDateISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/plainDateISO)
pub fn plainDateISO(io: std.Io) !PlainDate {
const now = currentParts(io);
return PlainDate.init(now.year, now.month, now.day);
}
/// Returns the current date and time as a [`Temporal.PlainDateTime`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime) object, in the ISO 8601 calendar and the specified time zone.
///
/// When `time_zone_like` is null, the system time zone is used.
///
/// See: [Temporal.Now.plainDateTimeISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/plainDateTimeISO)
pub fn plainDateTimeISO(allocator: std.mem.Allocator, io: std.Io, time_zone_like: ?[]const u8) !PlainDateTime {
const time_zone = try resolveTimeZone(allocator, io, time_zone_like);
const now = try instant(io);
defer now.deinit();
const ptr = (try abi.extractResult(abi.c.temporal_rs_PlainDateTime_from_epoch_nanoseconds(
abi.toI128Nanoseconds(now.epochNanoseconds()),
abi.to.toTimeZone(time_zone),
))) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
/// See: [MDN Temporal.Now.plainDateTimeISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/plainDateTimeISO)
pub fn plainDateTimeISO(io: std.Io) !PlainDateTime {
const now = currentParts(io);
return PlainDateTime.init(
now.year,
now.month,
now.day,
now.hour,
now.minute,
now.second,
now.millisecond,
now.microsecond,
now.nanosecond,
);
}
/// Returns the current time as a [`Temporal.PlainTime`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime) object, in the specified time zone.
///
/// When `time_zone_like` is null, the system time zone is used.
///
/// See: [Temporal.Now.plainTimeISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/plainTimeISO)
pub fn plainTimeISO(allocator: std.mem.Allocator, io: std.Io, time_zone_like: ?[]const u8) !PlainTime {
const zdt = try zonedDateTimeISO(allocator, io, time_zone_like);
defer zdt.deinit();
return zdt.toPlainTime();
/// See: [MDN Temporal.Now.plainTimeISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/plainTimeISO)
pub fn plainTimeISO(io: std.Io) !PlainTime {
const now = currentParts(io);
return PlainTime.init(
now.hour,
now.minute,
now.second,
now.millisecond,
now.microsecond,
now.nanosecond,
);
}
/// Returns a time zone identifier representing the system's current time zone.
///
/// The caller owns the returned slice and must free it with `allocator`.
///
/// See: [Temporal.Now.timeZoneId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/timeZoneId)
pub fn timeZoneId(allocator: std.mem.Allocator, io: std.Io) ![]const u8 {
const time_zone = try SystemTimeZone.timeZone(allocator, io);
var write = abi.DiplomatWrite.init(allocator);
defer write.deinit();
abi.c.temporal_rs_TimeZone_identifier(time_zone._inner, &write.inner);
return try write.toOwnedSlice();
/// See: [MDN Temporal.Now.timeZoneId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/timeZoneId)
pub fn timeZoneId() []const u8 {
return "UTC";
}
/// Returns the current date and time as a [`Temporal.ZonedDateTime`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime) object, in the ISO 8601 calendar and the specified time zone.
///
/// When `time_zone_like` is null, the system time zone is used.
///
/// See: [Temporal.Now.zonedDateTimeISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/zonedDateTimeISO)
pub fn zonedDateTimeISO(allocator: std.mem.Allocator, io: std.Io, time_zone_like: ?[]const u8) !ZonedDateTime {
const now = try instant(io);
defer now.deinit();
const time_zone = try resolveTimeZone(allocator, io, time_zone_like);
return ZonedDateTime.fromEpochNanoseconds(now.epochNanoseconds(), time_zone);
/// See: [MDN Temporal.Now.zonedDateTimeISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/zonedDateTimeISO)
pub fn zonedDateTimeISO() !ZonedDateTime {
return error.TemporalNotImplemented;
}
fn resolveTimeZone(allocator: std.mem.Allocator, io: std.Io, time_zone_like: ?[]const u8) !ZonedDateTime.TimeZone {
if (time_zone_like) |id| return ZonedDateTime.TimeZone.init(id);
return SystemTimeZone.timeZone(allocator, io);
const CurrentParts = struct {
year: i32,
month: u8,
day: u8,
hour: u8,
minute: u8,
second: u8,
millisecond: u16,
microsecond: u16,
nanosecond: u16,
};
fn currentParts(io: std.Io) CurrentParts {
const ns = std.Io.Timestamp.now(io, .real).nanoseconds;
const seconds: i64 = @intCast(@divTrunc(ns, 1_000_000_000));
const subsec_nanos_u64: u64 = @intCast(@rem(ns, 1_000_000_000));
const days_since_epoch: u64 = @intCast(@divTrunc(seconds, std.time.epoch.secs_per_day));
const secs_of_day: u64 = @intCast(@mod(seconds, std.time.epoch.secs_per_day));
const epoch_day = std.time.epoch.EpochDay{ .day = @intCast(days_since_epoch) };
const year_day = epoch_day.calculateYearDay();
const month_day = year_day.calculateMonthDay();
const day_seconds = std.time.epoch.DaySeconds{ .secs = @intCast(secs_of_day) };
const millisecond: u16 = @intCast(subsec_nanos_u64 / 1_000_000);
const microsecond: u16 = @intCast((subsec_nanos_u64 / 1_000) % 1_000);
const nanosecond: u16 = @intCast(subsec_nanos_u64 % 1_000);
return .{
.year = @intCast(year_day.year),
.month = @intCast(month_day.month.numeric()),
.day = @intCast(month_day.day_index + 1),
.hour = @intCast(day_seconds.getHoursIntoDay()),
.minute = @intCast(day_seconds.getMinutesIntoHour()),
.second = @intCast(day_seconds.getSecondsIntoMinute()),
.millisecond = millisecond,
.microsecond = microsecond,
.nanosecond = nanosecond,
};
}
// ---------- Tests ---------------------
test instant {
const io = std.testing.io;
const inst = try instant(io);
@ -122,62 +142,31 @@ test instant {
test plainDateISO {
const io = std.testing.io;
const date = try plainDateISO(std.testing.allocator, io, null);
defer date.deinit();
const date = try plainDateISO(io);
try std.testing.expect(date.year() >= 1970);
try std.testing.expect(date.month() >= 1 and date.month() <= 12);
try std.testing.expect(date.day() >= 1 and date.day() <= 31);
}
test plainDateTimeISO {
const io = std.testing.io;
var dt = try plainDateTimeISO(std.testing.allocator, io, null);
defer dt.deinit();
const dt = try plainDateTimeISO(io);
try std.testing.expect(dt.year() >= 1970);
try std.testing.expect(dt.month() >= 1 and dt.month() <= 12);
try std.testing.expect(dt.day() >= 1 and dt.day() <= 31);
try std.testing.expect(dt.hour() < 24);
try std.testing.expect(dt.minute() < 60);
}
test plainTimeISO {
const io = std.testing.io;
const t = try plainTimeISO(std.testing.allocator, io, null);
const t = try plainTimeISO(io);
try std.testing.expect(t.hour() < 24);
try std.testing.expect(t.minute() < 60);
try std.testing.expect(t.second() < 60);
}
test timeZoneId {
const io = std.testing.io;
const tz = try timeZoneId(std.testing.allocator, io);
defer std.testing.allocator.free(tz);
try std.testing.expect(tz.len > 0);
_ = try ZonedDateTime.TimeZone.init(tz);
const tz = timeZoneId();
try std.testing.expectEqualStrings("UTC", tz);
}
test zonedDateTimeISO {
const io = std.testing.io;
const zdt = try zonedDateTimeISO(std.testing.allocator, io, null);
defer zdt.deinit();
try std.testing.expect(zdt.epochNanoseconds() > 0);
const tz = try zdt.timeZoneId(std.testing.allocator);
defer std.testing.allocator.free(tz);
const expected_tz = try timeZoneId(std.testing.allocator, io);
defer std.testing.allocator.free(expected_tz);
try std.testing.expectEqualStrings(expected_tz, tz);
}
test "plainDateISO with explicit time zone" {
const io = std.testing.io;
const date = try plainDateISO(std.testing.allocator, io, "UTC");
defer date.deinit();
const zdt = try zonedDateTimeISO(std.testing.allocator, io, "UTC");
defer zdt.deinit();
const plain = try zdt.toPlainDate();
defer plain.deinit();
try std.testing.expect(date.equals(plain));
try std.testing.expectError(error.TemporalNotImplemented, zonedDateTimeISO());
}

View file

@ -13,7 +13,8 @@ const Duration = @import("Duration.zig");
///
/// The `Temporal.PlainDate` object represents a calendar date (year, month, day) with no time or time zone.
///
/// See: [Temporal.PlainDate](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDate)
/// The `Temporal.PlainDate` object represents a calendar date (year, month, day) with no time or time zone.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDate
const PlainDate = @This();
/// Internal pointer to the underlying C PlainDate object.
@ -54,22 +55,6 @@ pub const ToZonedDateTimeOptions = struct {
plain_time: ?PlainTime = null,
};
/// Options for `with()` method.
pub const WithOptions = struct {
/// Year value to override.
year: ?i32 = null,
/// Month value to override.
month: ?u8 = null,
/// Calendar-specific month code to override.
month_code: ?[]const u8 = null,
/// Day value to override.
day: ?u8 = null,
/// Era value to override.
era: ?[]const u8 = null,
/// Era year value to override.
era_year: ?i32 = null,
};
/// Creates a new PlainDate from the given ISO year, month, and day.
pub fn init(year_val: i32, month_val: u8, day_val: u8) !PlainDate {
return calInit(year_val, month_val, day_val, "iso8601");
@ -152,28 +137,11 @@ pub fn since(self: PlainDate, other: PlainDate, settings: DifferenceSettings) !D
return .{ ._inner = ptr };
}
/// Returns a new PlainDate with some fields replaced.
pub fn with(self: PlainDate, fields: WithOptions) !PlainDate {
const partial_date = abi.c.PartialDate{
.year = if (fields.year) |y| abi.toOption(abi.c.OptionI32, y) else .{ .is_ok = false },
.month = if (fields.month) |m| abi.toOption(abi.c.OptionU8, m) else .{ .is_ok = false },
.day = if (fields.day) |d| abi.toOption(abi.c.OptionU8, d) else .{ .is_ok = false },
.month_code = if (fields.month_code) |mc| abi.toDiplomatStringView(mc) else .{ .data = null, .len = 0 },
.era = if (fields.era) |e| abi.toDiplomatStringView(e) else .{ .data = null, .len = 0 },
.era_year = if (fields.era_year) |ey| abi.toOption(abi.c.OptionI32, ey) else .{ .is_ok = false },
.calendar = abi.c.AnyCalendarKind_Iso,
};
const overflow = abi.c.ArithmeticOverflow_option{
.is_ok = true,
.unnamed_0 = .{ .ok = abi.c.ArithmeticOverflow_Constrain },
};
return wrapPlainDate(abi.c.temporal_rs_PlainDate_with(
self._inner,
partial_date,
overflow,
));
/// Returns a new PlainDate with some fields replaced (not implemented).
pub fn with(self: PlainDate, fields: anytype) !PlainDate {
_ = self;
_ = fields;
return error.TemporalNotImplemented;
}
/// Returns a new PlainDate with a different calendar.
@ -558,13 +526,7 @@ test with {
const date = try PlainDate.init(2024, 3, 15);
defer date.deinit();
try std.testing.expectError(error.TypeError, date.with(.{}));
const changed = try date.with(.{ .year = 2025, .month = 4, .day = 16 });
defer changed.deinit();
try std.testing.expectEqual(@as(i32, 2025), changed.year());
try std.testing.expectEqual(@as(u8, 4), changed.month());
try std.testing.expectEqual(@as(u8, 16), changed.day());
try std.testing.expectError(error.TemporalNotImplemented, date.with(.{}));
}
test withCalendar {

View file

@ -11,7 +11,9 @@ const Duration = @import("Duration.zig");
///
/// The `Temporal.PlainDateTime` object represents a calendar date and wall-clock time, but no time zone or offset.
///
/// See: [Temporal.PlainDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime)
/// - [MDN Temporal.PlainDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime)
/// The `Temporal.PlainDateTime` object represents a calendar date and wall-clock time, but no time zone or offset.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime
const PlainDateTime = @This();
/// Internal pointer to the underlying C PlainDateTime object.
@ -545,6 +547,7 @@ fn wrapPlainDateTime(res: anytype) !PlainDateTime {
return .{ ._inner = ptr };
}
// ---------- Tests ---------------------
test init {
const dt = try PlainDateTime.init(2024, 1, 15, 14, 30, 45, 123, 456, 789);
try std.testing.expectEqual(@as(i32, 2024), dt.year());

View file

@ -8,7 +8,7 @@ const PlainDate = @import("PlainDate.zig");
///
/// The `Temporal.PlainMonthDay` object represents a month and day in a calendar, with no year or time.
///
/// See: [Temporal.PlainMonthDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay)
/// - [MDN Temporal.PlainMonthDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay)
const PlainMonthDay = @This();
_inner: *abi.c.PlainMonthDay,
@ -39,8 +39,7 @@ fn wrapPlainMonthDay(result: anytype) !PlainMonthDay {
/// Creates a new PlainMonthDay from the given month, day, and optional calendar.
/// Equivalent to the Temporal.PlainMonthDay constructor.
///
/// See: [Temporal.PlainMonthDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/PlainMonthDay)
/// See [MDN Temporal.PlainMonthDay() constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/PlainMonthDay)
pub fn init(month_val: u8, day_val: u8, calendar: ?[]const u8) !PlainMonthDay {
const cal_kind = if (calendar) |cal| blk: {
const cal_view = abi.toDiplomatStringView(cal);
@ -61,8 +60,7 @@ pub fn init(month_val: u8, day_val: u8, calendar: ?[]const u8) !PlainMonthDay {
}
/// Parses a PlainMonthDay from a string.
///
/// See: [Temporal.PlainMonthDay.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/from)
/// See [MDN Temporal.PlainMonthDay.from()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/from)
pub fn from(s: []const u8) !PlainMonthDay {
return fromUtf8(s);
}
@ -79,16 +77,14 @@ fn fromUtf16(utf16: []const u16) !PlainMonthDay {
// Comparison
/// Returns true if this PlainMonthDay is equal to another (same date and calendar).
///
/// See: [Temporal.PlainMonthDay.equals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/equals)
/// See [MDN Temporal.PlainMonthDay.prototype.equals()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/equals)
pub fn equals(self: PlainMonthDay, other: PlainMonthDay) bool {
return abi.c.temporal_rs_PlainMonthDay_equals(self._inner, other._inner);
}
// Property accessors
/// Returns the calendar identifier used to interpret the internal ISO 8601 date.
///
/// See: [Temporal.PlainMonthDay.calendarId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/calendarId)
/// See [MDN Temporal.PlainMonthDay.prototype.calendarId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/calendarId)
pub fn calendarId(self: PlainMonthDay, allocator: std.mem.Allocator) ![]u8 {
const calendar_ptr = abi.c.temporal_rs_PlainMonthDay_calendar(self._inner) orelse return error.TemporalError;
const cal_id_view = abi.c.temporal_rs_Calendar_identifier(calendar_ptr);
@ -96,15 +92,13 @@ pub fn calendarId(self: PlainMonthDay, allocator: std.mem.Allocator) ![]u8 {
}
/// Returns the 1-based day index in the month of this date.
///
/// See: [Temporal.PlainMonthDay.day](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/day)
/// See [MDN Temporal.PlainMonthDay.prototype.day](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/day)
pub fn day(self: PlainMonthDay) u8 {
return abi.c.temporal_rs_PlainMonthDay_day(self._inner);
}
/// Returns the calendar-specific string representing the month of this date.
///
/// See: [Temporal.PlainMonthDay.monthCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/monthCode)
/// See [MDN Temporal.PlainMonthDay.prototype.monthCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/monthCode)
pub fn monthCode(self: PlainMonthDay, allocator: std.mem.Allocator) ![]const u8 {
var write = abi.DiplomatWrite.init(allocator);
defer write.deinit();
@ -115,8 +109,7 @@ pub fn monthCode(self: PlainMonthDay, allocator: std.mem.Allocator) ![]const u8
// Modification
/// Returns a new PlainMonthDay with some fields replaced by new values.
///
/// See: [Temporal.PlainMonthDay.with](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/with)
/// See [MDN Temporal.PlainMonthDay.prototype.with()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/with)
pub fn with(self: PlainMonthDay, options: WithOptions) !PlainMonthDay {
// Build month_code view
const month_code_view = if (options.month_code) |mc|
@ -149,8 +142,7 @@ pub fn with(self: PlainMonthDay, options: WithOptions) !PlainMonthDay {
// Conversion
/// Returns a PlainDate representing this month-day and a supplied year in the same calendar system.
///
/// See: [Temporal.PlainMonthDay.toPlainDate](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toPlainDate)
/// See [MDN Temporal.PlainMonthDay.prototype.toPlainDate()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toPlainDate)
pub fn toPlainDate(self: PlainMonthDay, year: i32) !PlainDate {
const partial_date = abi.c.PartialDate_option{
.is_ok = true,
@ -175,8 +167,7 @@ pub fn toPlainDate(self: PlainMonthDay, year: i32) !PlainDate {
// String conversions
/// Returns a string representing this month-day in RFC 9557 format.
///
/// See: [Temporal.PlainMonthDay.toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toString)
/// See [MDN Temporal.PlainMonthDay.prototype.toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toString)
pub fn toString(self: PlainMonthDay, allocator: std.mem.Allocator) ![]u8 {
return toStringWithOptions(self, allocator, .{});
}
@ -193,27 +184,26 @@ fn toStringWithOptions(self: PlainMonthDay, allocator: std.mem.Allocator, option
}
/// Returns a string representing this month-day in RFC 9557 format (ISO 8601).
///
/// See: [Temporal.PlainMonthDay.toJSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toJSON)
/// See [MDN Temporal.PlainMonthDay.prototype.toJSON()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toJSON)
pub fn toJSON(self: PlainMonthDay, allocator: std.mem.Allocator) ![]u8 {
return toString(self, allocator);
}
/// Returns a language-sensitive string representation of this month-day.
///
/// See: [Temporal.PlainMonthDay.toLocaleString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toLocaleString)
/// See [MDN Temporal.PlainMonthDay.prototype.toLocaleString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toLocaleString)
pub fn toLocaleString(self: PlainMonthDay, allocator: std.mem.Allocator) ![]u8 {
return toString(self, allocator);
}
/// Throws an error; valueOf() is not supported for PlainMonthDay.
///
/// See: [Temporal.PlainMonthDay.valueOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/valueOf)
/// See [MDN Temporal.PlainMonthDay.prototype.valueOf()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/valueOf)
pub fn valueOf(self: PlainMonthDay) !void {
_ = self;
return error.ValueError;
}
// ---------- Tests ---------------------
test init {
const md = try init(12, 25, null);
try std.testing.expectEqual(@as(u8, 25), md.day());

View file

@ -8,7 +8,7 @@ const Duration = @import("Duration.zig");
///
/// The `Temporal.PlainTime` object represents a wall-clock time, with no date or time zone.
///
/// See: [Temporal.PlainTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime)
/// - [MDN Temporal.PlainTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime)
const PlainTime = @This();
_inner: *abi.c.PlainTime,
@ -45,26 +45,18 @@ pub fn init(
microsecond_val: u16,
nanosecond_val: u16,
) !PlainTime {
if (hour_val > 23 or minute_val > 59 or second_val > 59 or
millisecond_val > 999 or microsecond_val > 999 or nanosecond_val > 999)
{
return abi.TemporalError.RangeError;
}
var buf: [18]u8 = undefined;
const s = std.fmt.bufPrint(&buf, "{d:0>2}:{d:0>2}:{d:0>2}.{d:0>3}{d:0>3}{d:0>3}", .{
return wrapPlainTime(abi.c.temporal_rs_PlainTime_try_new(
hour_val,
minute_val,
second_val,
millisecond_val,
microsecond_val,
nanosecond_val,
}) catch unreachable;
return from(s);
));
}
/// Parses a PlainTime from a string.
///
/// See: [Temporal.PlainTime.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/from)
/// See [MDN Temporal.PlainTime.from()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/from)
pub fn from(s: []const u8) !PlainTime {
return fromUtf8(s);
}
@ -81,36 +73,31 @@ fn fromUtf16(utf16: []const u16) !PlainTime {
/// Compares two PlainTime instances by their time values.
/// Returns -1, 0, or 1 if the first is before, equal, or after the second.
///
/// See: [Temporal.PlainTime.compare](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/compare)
/// See [MDN Temporal.PlainTime.compare()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/compare)
pub fn compare(a: PlainTime, b: PlainTime) i8 {
return abi.c.temporal_rs_PlainTime_compare(a._inner, b._inner);
}
/// Returns true if this PlainTime is equal to another (same time values).
///
/// See: [Temporal.PlainTime.equals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/equals)
/// See [MDN Temporal.PlainTime.prototype.equals()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/equals)
pub fn equals(self: PlainTime, other: PlainTime) bool {
return abi.c.temporal_rs_PlainTime_equals(self._inner, other._inner);
}
/// Returns a new PlainTime moved forward by the given duration, wrapping around the clock if necessary.
///
/// See: [Temporal.PlainTime.add](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/add)
/// See [MDN Temporal.PlainTime.prototype.add()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/add)
pub fn add(self: PlainTime, duration: Duration) !PlainTime {
return wrapPlainTime(abi.c.temporal_rs_PlainTime_add(self._inner, duration._inner));
}
/// Returns a new PlainTime moved backward by the given duration, wrapping around the clock if necessary.
///
/// See: [Temporal.PlainTime.subtract](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/subtract)
/// See [MDN Temporal.PlainTime.prototype.subtract()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/subtract)
pub fn subtract(self: PlainTime, duration: Duration) !PlainTime {
return wrapPlainTime(abi.c.temporal_rs_PlainTime_subtract(self._inner, duration._inner));
}
/// Returns the duration from this PlainTime to another.
///
/// See: [Temporal.PlainTime.until](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/until)
/// See [MDN Temporal.PlainTime.prototype.until()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/until)
pub fn until(self: PlainTime, other: PlainTime, options: DifferenceSettings) !Duration {
const settings = abi.to.diffsettings(options);
const result = abi.c.temporal_rs_PlainTime_until(self._inner, other._inner, settings);
@ -119,8 +106,7 @@ pub fn until(self: PlainTime, other: PlainTime, options: DifferenceSettings) !Du
}
/// Returns the duration from another PlainTime to this one.
///
/// See: [Temporal.PlainTime.since](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/since)
/// See [MDN Temporal.PlainTime.prototype.since()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/since)
pub fn since(self: PlainTime, other: PlainTime, options: DifferenceSettings) !Duration {
const settings = abi.to.diffsettings(options);
const result = abi.c.temporal_rs_PlainTime_since(self._inner, other._inner, settings);
@ -130,59 +116,51 @@ pub fn since(self: PlainTime, other: PlainTime, options: DifferenceSettings) !Du
// Rounding
/// Returns a new PlainTime rounded to the given unit and options.
///
/// See: [Temporal.PlainTime.round](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/round)
/// See [MDN Temporal.PlainTime.prototype.round()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/round)
pub fn round(self: PlainTime, options: RoundOptions) !PlainTime {
return wrapPlainTime(abi.c.temporal_rs_PlainTime_round(self._inner, abi.to.roundingOpts(options)));
}
// Property accessors
/// Returns the hour component of this time (0-23).
///
/// See: [Temporal.PlainTime.hour](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/hour)
/// See [MDN Temporal.PlainTime.prototype.hour](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/hour)
pub fn hour(self: PlainTime) u8 {
return abi.c.temporal_rs_PlainTime_hour(self._inner);
}
/// Returns the minute component of this time (0-59).
///
/// See: [Temporal.PlainTime.minute](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/minute)
/// See [MDN Temporal.PlainTime.prototype.minute](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/minute)
pub fn minute(self: PlainTime) u8 {
return abi.c.temporal_rs_PlainTime_minute(self._inner);
}
/// Returns the second component of this time (0-59).
///
/// See: [Temporal.PlainTime.second](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/second)
/// See [MDN Temporal.PlainTime.prototype.second](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/second)
pub fn second(self: PlainTime) u8 {
return abi.c.temporal_rs_PlainTime_second(self._inner);
}
/// Returns the millisecond component of this time (0-999).
///
/// See: [Temporal.PlainTime.millisecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/millisecond)
/// See [MDN Temporal.PlainTime.prototype.millisecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/millisecond)
pub fn millisecond(self: PlainTime) u16 {
return abi.c.temporal_rs_PlainTime_millisecond(self._inner);
}
/// Returns the microsecond component of this time (0-999).
///
/// See: [Temporal.PlainTime.microsecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/microsecond)
/// See [MDN Temporal.PlainTime.prototype.microsecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/microsecond)
pub fn microsecond(self: PlainTime) u16 {
return abi.c.temporal_rs_PlainTime_microsecond(self._inner);
}
/// Returns the nanosecond component of this time (0-999).
///
/// See: [Temporal.PlainTime.nanosecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/nanosecond)
/// See [MDN Temporal.PlainTime.prototype.nanosecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/nanosecond)
pub fn nanosecond(self: PlainTime) u16 {
return abi.c.temporal_rs_PlainTime_nanosecond(self._inner);
}
// Modification
/// Returns a new PlainTime with some fields replaced by new values.
///
/// See: [Temporal.PlainTime.with](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/with)
/// See [MDN Temporal.PlainTime.prototype.with()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/with)
pub fn with(self: PlainTime, options: WithOptions) !PlainTime {
const partial = abi.c.PartialTime{
.hour = abi.toOption(abi.c.OptionU8, options.hour),
@ -201,8 +179,7 @@ pub fn with(self: PlainTime, options: WithOptions) !PlainTime {
// String conversions
/// Returns a string representing this PlainTime in RFC 9557 format.
///
/// See: [Temporal.PlainTime.toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/toString)
/// See [MDN Temporal.PlainTime.prototype.toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/toString)
pub fn toString(self: PlainTime, allocator: std.mem.Allocator) ![]u8 {
return toStringWithOptions(self, allocator, .{});
}
@ -224,29 +201,28 @@ fn toStringWithOptions(self: PlainTime, allocator: std.mem.Allocator, options: t
}
/// Returns a string representing this PlainTime in RFC 9557 format (ISO 8601).
///
/// See: [Temporal.PlainTime.toJSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/toJSON)
/// See [MDN Temporal.PlainTime.prototype.toJSON()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/toJSON)
pub fn toJSON(self: PlainTime, allocator: std.mem.Allocator) ![]u8 {
return toString(self, allocator);
}
/// Returns a language-sensitive string representation of this PlainTime.
///
/// See: [Temporal.PlainTime.toLocaleString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/toLocaleString)
/// See [MDN Temporal.PlainTime.prototype.toLocaleString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/toLocaleString)
pub fn toLocaleString(self: PlainTime, allocator: std.mem.Allocator) ![]u8 {
// For now, just use toString - locale-specific formatting would require more work
return toString(self, allocator);
}
/// Throws an error; valueOf() is not supported for PlainTime.
///
/// See: [Temporal.PlainTime.valueOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/valueOf)
/// See [MDN Temporal.PlainTime.prototype.valueOf()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/valueOf)
pub fn valueOf(self: PlainTime) !void {
_ = self;
// PlainTime should not be used in arithmetic/comparison operations implicitly
return error.ValueError;
}
// ---------- Tests ---------------------
test init {
{
const time = try init(14, 30, 45, 123, 456, 789);

View file

@ -9,7 +9,7 @@ const Duration = @import("Duration.zig");
///
/// The `Temporal.PlainYearMonth` object represents a particular month in a specific year, with no day or time.
///
/// See: [Temporal.PlainYearMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth)
/// - [MDN Temporal.PlainYearMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth)
const PlainYearMonth = @This();
_inner: *abi.c.PlainYearMonth,
@ -47,8 +47,7 @@ fn wrapPlainYearMonth(result: anytype) !PlainYearMonth {
/// Creates a new PlainYearMonth from the given year, month, and optional calendar.
/// Equivalent to the Temporal.PlainYearMonth constructor.
///
/// See: [Temporal.PlainYearMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/PlainYearMonth)
/// See [MDN Temporal.PlainYearMonth() constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/PlainYearMonth)
pub fn init(year_val: i32, month_val: u8, calendar: ?[]const u8) !PlainYearMonth {
const cal_kind = if (calendar) |cal| blk: {
const cal_view = abi.toDiplomatStringView(cal);
@ -69,8 +68,7 @@ pub fn init(year_val: i32, month_val: u8, calendar: ?[]const u8) !PlainYearMonth
}
/// Parses a PlainYearMonth from a string.
///
/// See: [Temporal.PlainYearMonth.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/from)
/// See [MDN Temporal.PlainYearMonth.from()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/from)
pub fn from(s: []const u8) !PlainYearMonth {
return fromUtf8(s);
}
@ -88,39 +86,34 @@ fn fromUtf16(utf16: []const u16) !PlainYearMonth {
// Comparison
/// Compares two PlainYearMonth instances by their ISO date values.
/// Returns -1, 0, or 1 if the first is before, equal, or after the second.
///
/// See: [Temporal.PlainYearMonth.compare](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/compare)
/// See [MDN Temporal.PlainYearMonth.compare()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/compare)
pub fn compare(a: PlainYearMonth, b: PlainYearMonth) i8 {
return abi.c.temporal_rs_PlainYearMonth_compare(a._inner, b._inner);
}
/// Returns true if this PlainYearMonth is equal to another (same ISO date and calendar).
///
/// See: [Temporal.PlainYearMonth.equals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/equals)
/// See [MDN Temporal.PlainYearMonth.prototype.equals()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/equals)
pub fn equals(self: PlainYearMonth, other: PlainYearMonth) bool {
return abi.c.temporal_rs_PlainYearMonth_equals(self._inner, other._inner);
}
// Arithmetic
/// Returns a new PlainYearMonth moved forward by the given duration.
///
/// See: [Temporal.PlainYearMonth.add](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/add)
/// See [MDN Temporal.PlainYearMonth.prototype.add()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/add)
pub fn add(self: PlainYearMonth, duration: Duration) !PlainYearMonth {
const overflow = abi.c.ArithmeticOverflow_Constrain;
return wrapPlainYearMonth(abi.c.temporal_rs_PlainYearMonth_add(self._inner, duration._inner, overflow));
}
/// Returns a new PlainYearMonth moved backward by the given duration.
///
/// See: [Temporal.PlainYearMonth.subtract](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/subtract)
/// See [MDN Temporal.PlainYearMonth.prototype.subtract()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/subtract)
pub fn subtract(self: PlainYearMonth, duration: Duration) !PlainYearMonth {
const overflow = abi.c.ArithmeticOverflow_Constrain;
return wrapPlainYearMonth(abi.c.temporal_rs_PlainYearMonth_subtract(self._inner, duration._inner, overflow));
}
/// Returns the duration from this PlainYearMonth to another.
///
/// See: [Temporal.PlainYearMonth.until](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/until)
/// See [MDN Temporal.PlainYearMonth.prototype.until()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/until)
pub fn until(self: PlainYearMonth, other: PlainYearMonth, options: DifferenceSettings) !Duration {
const settings = abi.to.diffsettings(options);
const result = abi.c.temporal_rs_PlainYearMonth_until(self._inner, other._inner, settings);
@ -129,8 +122,7 @@ pub fn until(self: PlainYearMonth, other: PlainYearMonth, options: DifferenceSet
}
/// Returns the duration from another PlainYearMonth to this one.
///
/// See: [Temporal.PlainYearMonth.since](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/since)
/// See [MDN Temporal.PlainYearMonth.prototype.since()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/since)
pub fn since(self: PlainYearMonth, other: PlainYearMonth, options: DifferenceSettings) !Duration {
const settings = abi.to.diffsettings(options);
const result = abi.c.temporal_rs_PlainYearMonth_since(self._inner, other._inner, settings);
@ -140,8 +132,7 @@ pub fn since(self: PlainYearMonth, other: PlainYearMonth, options: DifferenceSet
// Property accessors
/// Returns the calendar identifier used to interpret the internal ISO 8601 date.
///
/// See: [Temporal.PlainYearMonth.calendarId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/calendarId)
/// See [MDN Temporal.PlainYearMonth.prototype.calendarId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/calendarId)
pub fn calendarId(self: PlainYearMonth, allocator: std.mem.Allocator) ![]u8 {
const calendar_ptr = abi.c.temporal_rs_PlainYearMonth_calendar(self._inner) orelse return error.TemporalError;
const cal_id_view = abi.c.temporal_rs_Calendar_identifier(calendar_ptr);
@ -149,22 +140,19 @@ pub fn calendarId(self: PlainYearMonth, allocator: std.mem.Allocator) ![]u8 {
}
/// Returns the year of this year-month relative to the calendar's epoch.
///
/// See: [Temporal.PlainYearMonth.year](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/year)
/// See [MDN Temporal.PlainYearMonth.prototype.year](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/year)
pub fn year(self: PlainYearMonth) i32 {
return abi.c.temporal_rs_PlainYearMonth_year(self._inner);
}
/// Returns the 1-based month index in the year of this year-month.
///
/// See: [Temporal.PlainYearMonth.month](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/month)
/// See [MDN Temporal.PlainYearMonth.prototype.month](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/month)
pub fn month(self: PlainYearMonth) u8 {
return abi.c.temporal_rs_PlainYearMonth_month(self._inner);
}
/// Returns the calendar-specific string representing the month of this year-month.
///
/// See: [Temporal.PlainYearMonth.monthCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/monthCode)
/// See [MDN Temporal.PlainYearMonth.prototype.monthCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/monthCode)
pub fn monthCode(self: PlainYearMonth, allocator: std.mem.Allocator) ![]const u8 {
var write = abi.DiplomatWrite.init(allocator);
defer write.deinit();
@ -174,36 +162,31 @@ pub fn monthCode(self: PlainYearMonth, allocator: std.mem.Allocator) ![]const u8
}
/// Returns the number of days in the month of this year-month.
///
/// See: [Temporal.PlainYearMonth.daysInMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/daysInMonth)
/// See [MDN Temporal.PlainYearMonth.prototype.daysInMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/daysInMonth)
pub fn daysInMonth(self: PlainYearMonth) u16 {
return abi.c.temporal_rs_PlainYearMonth_days_in_month(self._inner);
}
/// Returns the number of days in the year of this year-month.
///
/// See: [Temporal.PlainYearMonth.daysInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/daysInYear)
/// See [MDN Temporal.PlainYearMonth.prototype.daysInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/daysInYear)
pub fn daysInYear(self: PlainYearMonth) u16 {
return abi.c.temporal_rs_PlainYearMonth_days_in_year(self._inner);
}
/// Returns the number of months in the year of this year-month.
///
/// See: [Temporal.PlainYearMonth.monthsInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/monthsInYear)
/// See [MDN Temporal.PlainYearMonth.prototype.monthsInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/monthsInYear)
pub fn monthsInYear(self: PlainYearMonth) u16 {
return abi.c.temporal_rs_PlainYearMonth_months_in_year(self._inner);
}
/// Returns true if this year-month is in a leap year.
///
/// See: [Temporal.PlainYearMonth.inLeapYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/inLeapYear)
/// See [MDN Temporal.PlainYearMonth.prototype.inLeapYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/inLeapYear)
pub fn inLeapYear(self: PlainYearMonth) bool {
return abi.c.temporal_rs_PlainYearMonth_in_leap_year(self._inner);
}
/// Returns the calendar-specific era of this year-month, or null if not applicable.
///
/// See: [Temporal.PlainYearMonth.era](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/era)
/// See [MDN Temporal.PlainYearMonth.prototype.era](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/era)
pub fn era(self: PlainYearMonth, allocator: std.mem.Allocator) !?[]const u8 {
var write = abi.DiplomatWrite.init(allocator);
defer write.deinit();
@ -215,8 +198,7 @@ pub fn era(self: PlainYearMonth, allocator: std.mem.Allocator) !?[]const u8 {
}
/// Returns the year of this year-month within the era, or null if not applicable.
///
/// See: [Temporal.PlainYearMonth.eraYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/eraYear)
/// See [MDN Temporal.PlainYearMonth.prototype.eraYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/eraYear)
pub fn eraYear(self: PlainYearMonth) ?i32 {
const result = abi.c.temporal_rs_PlainYearMonth_era_year(self._inner);
if (!result.is_ok) return null;
@ -225,8 +207,7 @@ pub fn eraYear(self: PlainYearMonth) ?i32 {
// Modification
/// Returns a new PlainYearMonth with some fields replaced by new values.
///
/// See: [Temporal.PlainYearMonth.with](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/with)
/// See [MDN Temporal.PlainYearMonth.prototype.with()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/with)
pub fn with(self: PlainYearMonth, options: WithOptions) !PlainYearMonth {
// Build month_code view
const month_code_view = if (options.month_code) |mc|
@ -259,8 +240,7 @@ pub fn with(self: PlainYearMonth, options: WithOptions) !PlainYearMonth {
// Conversion
/// Returns a PlainDate representing this year-month and a supplied day in the same calendar system.
///
/// See: [Temporal.PlainYearMonth.toPlainDate](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toPlainDate)
/// See [MDN Temporal.PlainYearMonth.prototype.toPlainDate()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toPlainDate)
pub fn toPlainDate(self: PlainYearMonth, day: u8) !PlainDate {
const partial_date = abi.c.PartialDate_option{
.is_ok = true,
@ -285,8 +265,7 @@ pub fn toPlainDate(self: PlainYearMonth, day: u8) !PlainDate {
// String conversions
/// Returns a string representing this year-month in RFC 9557 format.
///
/// See: [Temporal.PlainYearMonth.toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toString)
/// See [MDN Temporal.PlainYearMonth.prototype.toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toString)
pub fn toString(self: PlainYearMonth, allocator: std.mem.Allocator) ![]u8 {
return toStringWithOptions(self, allocator, .{});
}
@ -303,27 +282,26 @@ fn toStringWithOptions(self: PlainYearMonth, allocator: std.mem.Allocator, optio
}
/// Returns a JSON string representing this year-month.
///
/// See: [Temporal.PlainYearMonth.toJSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toJSON)
/// See [MDN Temporal.PlainYearMonth.prototype.toJSON()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toJSON)
pub fn toJSON(self: PlainYearMonth, allocator: std.mem.Allocator) ![]u8 {
return toString(self, allocator);
}
/// Returns a locale-sensitive string representing this year-month.
///
/// See: [Temporal.PlainYearMonth.toLocaleString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toLocaleString)
/// See [MDN Temporal.PlainYearMonth.prototype.toLocaleString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toLocaleString)
pub fn toLocaleString(self: PlainYearMonth, allocator: std.mem.Allocator) ![]u8 {
return toString(self, allocator);
}
/// Throws a TypeError, as PlainYearMonth objects cannot be converted to primitive values.
///
/// See: [Temporal.PlainYearMonth.valueOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/valueOf)
/// See [MDN Temporal.PlainYearMonth.prototype.valueOf()](https://developer.mozilla
pub fn valueOf(self: PlainYearMonth) !void {
_ = self;
return error.ValueError;
}
// ---------- Tests ---------------------
test init {
const ym = try init(2024, 12, null);
try std.testing.expectEqual(@as(i32, 2024), ym.year());
@ -452,43 +430,6 @@ test until {
try std.testing.expectEqual(@as(i64, 6), dur.months());
}
test calendarId {
const ym = try from("2021-07-01[u-ca=gregory]");
const cal_id = try ym.calendarId(std.testing.allocator);
defer std.testing.allocator.free(cal_id);
try std.testing.expectEqualStrings("gregory", cal_id);
}
test year {
const ym = try from("2021-07");
try std.testing.expectEqual(@as(i32, 2021), ym.year());
}
test month {
const ym = try from("2021-07");
try std.testing.expectEqual(@as(u8, 7), ym.month());
}
test monthCode {
const ym = try from("2021-07");
const month_code = try ym.monthCode(std.testing.allocator);
defer std.testing.allocator.free(month_code);
try std.testing.expectEqualStrings("M07", month_code);
}
test era {
const ym = try from("2021-07-01[u-ca=gregory]");
const maybe_era = try ym.era(std.testing.allocator);
const era_value = maybe_era orelse return error.TestUnexpectedResult;
defer std.testing.allocator.free(era_value);
try std.testing.expectEqualStrings("ce", era_value);
}
test eraYear {
const ym = try from("2021-07-01[u-ca=gregory]");
try std.testing.expectEqual(@as(?i32, 2021), ym.eraYear());
}
test with {
// Test modifying year
const ym1 = try init(2024, 6, null);

View file

@ -1,68 +0,0 @@
const builtin = @import("builtin");
const std = @import("std");
const ZonedDateTime = @import("ZonedDateTime.zig");
const zoneinfo_marker = "zoneinfo/";
/// Returns the host environment's current time zone identifier.
///
/// Resolution order:
/// 1. `TZ` environment variable (when set and non-empty)
/// 2. Unix: `/etc/localtime` symlink target under `zoneinfo/`
/// 3. `"UTC"`
///
/// The caller owns the returned slice.
pub fn identifier(allocator: std.mem.Allocator, io: std.Io) ![]const u8 {
if (tzFromEnv(allocator)) |tz| return tz;
if (detectFromPlatform(allocator, io)) |tz| return tz;
return try allocator.dupe(u8, "UTC");
}
/// Returns a `TimeZone` for the host environment's current time zone.
pub fn timeZone(allocator: std.mem.Allocator, io: std.Io) !ZonedDateTime.TimeZone {
const id = try identifier(allocator, io);
defer allocator.free(id);
return ZonedDateTime.TimeZone.init(id);
}
fn tzFromEnv(allocator: std.mem.Allocator) ?[]const u8 {
if (!builtin.link_libc) return null;
const value = std.c.getenv("TZ") orelse return null;
const tz = std.mem.span(value);
if (tz.len == 0) return null;
return allocator.dupe(u8, tz) catch null;
}
fn detectFromPlatform(allocator: std.mem.Allocator, io: std.Io) ?[]const u8 {
return switch (builtin.os.tag) {
.linux, .macos, .freebsd, .openbsd, .netbsd, .dragonfly => detectFromEtcLocaltime(allocator, io) catch null,
else => null,
};
}
fn detectFromEtcLocaltime(allocator: std.mem.Allocator, io: std.Io) ![]const u8 {
var target_buf: [std.fs.max_path_bytes]u8 = undefined;
const len = std.Io.Dir.readLinkAbsolute(io, "/etc/localtime", &target_buf) catch return error.NotFound;
const target = target_buf[0..len];
const idx = std.mem.lastIndexOf(u8, target, zoneinfo_marker) orelse return error.NotFound;
return try allocator.dupe(u8, target[idx + zoneinfo_marker.len ..]);
}
test identifier {
const io = std.testing.io;
const tz = try identifier(std.testing.allocator, io);
defer std.testing.allocator.free(tz);
try std.testing.expect(tz.len > 0);
_ = try ZonedDateTime.TimeZone.init(tz);
}
test timeZone {
const io = std.testing.io;
_ = try timeZone(std.testing.allocator, io);
}

View file

@ -13,21 +13,27 @@ const ZonedDateTime = @This();
_inner: *abi.c.ZonedDateTime,
/// The unit of time used for rounding and difference calculations.
/// See [MDN Temporal.ZonedDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime) for details.
pub const Unit = t.Unit;
/// The rounding mode used for rounding operations.
/// See [MDN Temporal.ZonedDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime) for details.
pub const RoundingMode = t.RoundingMode;
/// The sign of a duration or difference.
/// See [MDN Temporal.ZonedDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime) for details.
pub const Sign = t.Sign;
/// Options for difference calculations between ZonedDateTime instances.
/// See [MDN Temporal.ZonedDateTime#instance_methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime#instance_methods) for details.
pub const DifferenceSettings = t.DifferenceSettings;
/// Options for rounding ZonedDateTime instances.
/// See [MDN Temporal.ZonedDateTime#instance_methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime#instance_methods) for details.
pub const RoundOptions = t.RoundingOptions;
/// Represents a time zone, identified by an IANA time zone identifier or a fixed offset.
/// See [MDN Temporal.ZonedDateTime#time-zones-and-offsets](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime#time-zones-and-offsets).
pub const TimeZone = struct {
_inner: abi.c.TimeZone,
@ -41,6 +47,7 @@ pub const TimeZone = struct {
};
/// Disambiguation options for resolving ambiguous local times (e.g., during DST transitions).
/// See [MDN Temporal.ZonedDateTime#ambiguity-and-gaps-from-local-time-to-utc-time](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime#ambiguity-and-gaps-from-local-time-to-utc-time).
pub const Disambiguation = enum {
compatible,
earlier,
@ -49,6 +56,7 @@ pub const Disambiguation = enum {
};
/// Options for resolving offset ambiguity when parsing ZonedDateTime from a string.
/// See [MDN Temporal.ZonedDateTime#offset-ambiguity](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime#offset-ambiguity).
pub const OffsetDisambiguation = enum {
use_offset,
prefer_offset,
@ -57,6 +65,7 @@ pub const OffsetDisambiguation = enum {
};
/// Controls how the calendar is displayed in string output.
/// See [MDN Temporal.ZonedDateTime#rfc-9557-format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime#rfc-9557-format).
pub const CalendarDisplay = enum {
auto,
always,
@ -65,12 +74,14 @@ pub const CalendarDisplay = enum {
};
/// Controls how the offset is displayed in string output.
/// See [MDN Temporal.ZonedDateTime#rfc-9557-format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime#rfc-9557-format).
pub const DisplayOffset = enum {
auto,
never,
};
/// Controls how the time zone is displayed in string output.
/// See [MDN Temporal.ZonedDateTime#rfc-9557-format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime#rfc-9557-format).
pub const DisplayTimeZone = enum {
auto,
never,
@ -78,8 +89,7 @@ pub const DisplayTimeZone = enum {
};
/// Options for formatting ZonedDateTime as a string.
///
/// See: [Temporal.ZonedDateTime.toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toString#parameters)
/// See [MDN Temporal.ZonedDateTime#rfc-9557-format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime#rfc-9557-format).
pub const ToStringOptions = struct {
fractional_second_digits: ?u8 = null,
smallest_unit: ?Unit = null,
@ -89,49 +99,35 @@ pub const ToStringOptions = struct {
time_zone_name: DisplayTimeZone = .auto,
};
/// Options for `with()` method.
///
/// See: [Temporal.ZonedDateTime.with](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/with#parameters)
pub const WithOptions = struct {
year: ?i32 = null,
month: ?u8 = null,
month_code: ?[]const u8 = null,
day: ?u8 = null,
era: ?[]const u8 = null,
era_year: ?i32 = null,
hour: ?u8 = null,
minute: ?u8 = null,
second: ?u8 = null,
millisecond: ?u16 = null,
microsecond: ?u16 = null,
nanosecond: ?u16 = null,
offset: ?[]const u8 = null,
time_zone: ?TimeZone = null,
};
/// Helper function to wrap a C API result into a ZonedDateTime
fn wrapZonedDateTime(result: anytype) !ZonedDateTime {
const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
/// Creates a new ZonedDateTime from the given epoch nanoseconds and time zone.
/// Equivalent to the Temporal.ZonedDateTime constructor.
///
/// See: [Temporal.ZonedDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/ZonedDateTime)
/// See [MDN Temporal.ZonedDateTime() constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/ZonedDateTime)
pub fn init(epoch_ns: i128, time_zone: TimeZone) !ZonedDateTime {
const ns_parts = abi.toI128Nanoseconds(epoch_ns);
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_from_epoch_nanoseconds(ns_parts, abi.to.toTimeZone(time_zone)));
}
/// Creates a new ZonedDateTime from the given epoch milliseconds and time zone.
/// See [MDN Temporal.ZonedDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime)
pub fn fromEpochMilliseconds(epoch_ms: i64, time_zone: TimeZone) !ZonedDateTime {
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_from_epoch_milliseconds(epoch_ms, abi.to.toTimeZone(time_zone)));
}
/// Creates a new ZonedDateTime from the given epoch nanoseconds and time zone.
/// See [MDN Temporal.ZonedDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime)
pub fn fromEpochNanoseconds(epoch_ns: i128, time_zone: TimeZone) !ZonedDateTime {
const ns_parts = abi.toI128Nanoseconds(epoch_ns);
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_from_epoch_nanoseconds(ns_parts, abi.to.toTimeZone(time_zone)));
}
/// Parses a ZonedDateTime from a string, with optional disambiguation and offset options.
///
/// See: [Temporal.ZonedDateTime.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/from)
/// See [MDN Temporal.ZonedDateTime.from()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/from)
pub fn from(s: []const u8, time_zone: ?TimeZone, disambiguation: Disambiguation, offset_disambiguation: OffsetDisambiguation) !ZonedDateTime {
_ = time_zone; // The time zone is parsed from the string
const view = abi.toDiplomatStringView(s);
@ -140,30 +136,26 @@ pub fn from(s: []const u8, time_zone: ?TimeZone, disambiguation: Disambiguation,
/// Compares two ZonedDateTime instances by their instant values.
/// Returns -1, 0, or 1 if the first is before, equal, or after the second.
///
/// See: [Temporal.ZonedDateTime.compare](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/compare)
/// See [MDN Temporal.ZonedDateTime.compare()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/compare)
pub fn compare(a: ZonedDateTime, b: ZonedDateTime) i8 {
return abi.c.temporal_rs_ZonedDateTime_compare_instant(a._inner, b._inner);
}
/// Returns a new ZonedDateTime moved forward by the given duration.
///
/// See: [Temporal.ZonedDateTime.add](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/add)
/// See [MDN Temporal.ZonedDateTime.prototype.add()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/add)
pub fn add(self: ZonedDateTime, duration: Duration) !ZonedDateTime {
const overflow_opt = abi.toOption(abi.c.ArithmeticOverflow_option, null);
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_add(self._inner, duration._inner, overflow_opt));
}
/// Returns true if this ZonedDateTime is equal to another (same instant, time zone, and calendar).
///
/// See: [Temporal.ZonedDateTime.equals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/equals)
/// See [MDN Temporal.ZonedDateTime.prototype.equals()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/equals)
pub fn equals(self: ZonedDateTime, other: ZonedDateTime) bool {
return abi.c.temporal_rs_ZonedDateTime_equals(self._inner, other._inner);
}
/// Returns the first instant after or before this instant at which the time zone's UTC offset changes, or null if none.
///
/// See: [Temporal.ZonedDateTime.getTimeZoneTransition](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/getTimeZoneTransition)
/// See [MDN Temporal.ZonedDateTime.prototype.getTimeZoneTransition()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/getTimeZoneTransition)
pub fn getTimeZoneTransition(self: ZonedDateTime, direction: enum { next, previous }) !?ZonedDateTime {
const dir = switch (direction) {
.next => abi.c.TransitionDirection_Next,
@ -178,15 +170,13 @@ pub fn getTimeZoneTransition(self: ZonedDateTime, direction: enum { next, previo
}
/// Returns a new ZonedDateTime rounded to the given unit and options.
///
/// See: [Temporal.ZonedDateTime.round](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/round)
/// See [MDN Temporal.ZonedDateTime.prototype.round()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/round)
pub fn round(self: ZonedDateTime, options: RoundOptions) !ZonedDateTime {
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_round(self._inner, abi.to.roundingOpts(options)));
}
/// Returns the duration from another ZonedDateTime to this one.
///
/// See: [Temporal.ZonedDateTime.since](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/since)
/// See [MDN Temporal.ZonedDateTime.prototype.since()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/since)
pub fn since(self: ZonedDateTime, other: ZonedDateTime, settings: DifferenceSettings) !Duration {
const ptr = try abi.extractResult(abi.c.temporal_rs_ZonedDateTime_since(self._inner, other._inner, abi.to.diffsettings(settings)));
if (ptr == null) return error.TemporalError;
@ -194,69 +184,60 @@ pub fn since(self: ZonedDateTime, other: ZonedDateTime, settings: DifferenceSett
}
/// Returns a ZonedDateTime representing the start of the day in the time zone.
///
/// See: [Temporal.ZonedDateTime.startOfDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/startOfDay)
/// See [MDN Temporal.ZonedDateTime.prototype.startOfDay()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/startOfDay)
pub fn startOfDay(self: ZonedDateTime) !ZonedDateTime {
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_start_of_day(self._inner));
}
/// Returns a new ZonedDateTime moved backward by the given duration.
///
/// See: [Temporal.ZonedDateTime.subtract](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/subtract)
/// See [MDN Temporal.ZonedDateTime.prototype.subtract()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/subtract)
pub fn subtract(self: ZonedDateTime, duration: Duration) !ZonedDateTime {
const overflow_opt = abi.toOption(abi.c.ArithmeticOverflow_option, null);
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_subtract(self._inner, duration._inner, overflow_opt));
}
/// Returns a new Instant representing the same instant as this ZonedDateTime.
///
/// See: [Temporal.ZonedDateTime.toInstant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toInstant)
/// See [MDN Temporal.ZonedDateTime.prototype.toInstant()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toInstant)
pub fn toInstant(self: ZonedDateTime) !Instant {
const instant_ptr = abi.c.temporal_rs_ZonedDateTime_to_instant(self._inner) orelse return error.TemporalError;
return .{ ._inner = instant_ptr };
}
/// Returns a string representing this ZonedDateTime in RFC 9557 format (ISO 8601 with time zone).
///
/// See: [Temporal.ZonedDateTime.toJSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toJSON)
/// See [MDN Temporal.ZonedDateTime.prototype.toJSON()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toJSON)
pub fn toJSON(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
return self.toString(allocator, .{});
}
/// Returns a language-sensitive string representation of this ZonedDateTime.
///
/// See: [Temporal.ZonedDateTime.toLocaleString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toLocaleString)
/// See [MDN Temporal.ZonedDateTime.prototype.toLocaleString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toLocaleString)
pub fn toLocaleString(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
return self.toString(allocator, .{});
}
/// Returns a PlainDate representing the date portion of this ZonedDateTime.
///
/// See: [Temporal.ZonedDateTime.toPlainDate](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainDate)
/// See [MDN Temporal.ZonedDateTime.prototype.toPlainDate()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainDate)
pub fn toPlainDate(self: ZonedDateTime) !PlainDate {
const ptr = abi.c.temporal_rs_ZonedDateTime_to_plain_date(self._inner) orelse return error.TemporalError;
return .{ ._inner = ptr };
}
/// Returns a PlainDateTime representing the date and time portions of this ZonedDateTime.
///
/// See: [Temporal.ZonedDateTime.toPlainDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainDateTime)
/// See [MDN Temporal.ZonedDateTime.prototype.toPlainDateTime()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainDateTime)
pub fn toPlainDateTime(self: ZonedDateTime) !PlainDateTime {
const ptr = abi.c.temporal_rs_ZonedDateTime_to_plain_datetime(self._inner) orelse return error.TemporalError;
return .{ ._inner = ptr };
}
/// Returns a PlainTime representing the time portion of this ZonedDateTime.
///
/// See: [Temporal.ZonedDateTime.toPlainTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainTime)
/// See [MDN Temporal.ZonedDateTime.prototype.toPlainTime()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainTime)
pub fn toPlainTime(self: ZonedDateTime) !PlainTime {
const ptr = abi.c.temporal_rs_ZonedDateTime_to_plain_time(self._inner) orelse return error.TemporalError;
return .{ ._inner = ptr };
}
/// Returns a string representing this ZonedDateTime in RFC 9557 format, with options for formatting.
///
/// See: [Temporal.ZonedDateTime.toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toString)
/// See [MDN Temporal.ZonedDateTime.prototype.toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toString)
pub fn toString(self: ZonedDateTime, allocator: std.mem.Allocator, opts: ToStringOptions) ![]u8 {
var write = abi.DiplomatWrite.init(allocator);
defer write.deinit();
@ -275,8 +256,7 @@ pub fn toString(self: ZonedDateTime, allocator: std.mem.Allocator, opts: ToStrin
}
/// Returns the duration from this ZonedDateTime to another.
///
/// See: [Temporal.ZonedDateTime.until](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/until)
/// See [MDN Temporal.ZonedDateTime.prototype.until()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/until)
pub fn until(self: ZonedDateTime, other: ZonedDateTime, settings: DifferenceSettings) !Duration {
const ptr = try abi.extractResult(abi.c.temporal_rs_ZonedDateTime_until(self._inner, other._inner, abi.to.diffsettings(settings)));
if (ptr == null) return error.TemporalError;
@ -284,8 +264,7 @@ pub fn until(self: ZonedDateTime, other: ZonedDateTime, settings: DifferenceSett
}
/// Throws an error; valueOf() is not supported for ZonedDateTime.
///
/// See: [Temporal.ZonedDateTime.valueOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/valueOf)
/// See [MDN Temporal.ZonedDateTime.prototype.valueOf()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/valueOf)
pub fn valueOf(_: ZonedDateTime) !void {
return error.ValueOfNotSupported;
}
@ -294,26 +273,13 @@ pub fn valueOf(_: ZonedDateTime) !void {
/// See [MDN Temporal.ZonedDateTime.prototype.with()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/with)
pub fn with(self: ZonedDateTime, allocator: std.mem.Allocator, fields: anytype) !ZonedDateTime {
_ = allocator;
const partial = abi.toPartialZonedDateTime(fields);
const disambiguation = abi.toOption(abi.c.Disambiguation_option, abi.to.toDisambiguation(Disambiguation.compatible));
const offset_option = abi.toOption(abi.c.OffsetDisambiguation_option, abi.to.toOffsetDisambiguation(OffsetDisambiguation.prefer_offset));
const overflow = abi.c.ArithmeticOverflow_option{
.is_ok = true,
.unnamed_0 = .{ .ok = abi.c.ArithmeticOverflow_Constrain },
};
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_with(
self._inner,
partial,
disambiguation,
offset_option,
overflow,
));
_ = fields;
_ = self;
return error.TemporalNoteImplemented; // Need PartialZonedDateTime mapping
}
/// Returns a new ZonedDateTime interpreted in the new calendar system.
///
/// See: [Temporal.ZonedDateTime.withCalendar](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withCalendar)
/// See [MDN Temporal.ZonedDateTime.prototype.withCalendar()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withCalendar)
pub fn withCalendar(self: ZonedDateTime, calendar: []const u8) !ZonedDateTime {
const cal_view = abi.toDiplomatStringView(calendar);
const cal_result = abi.c.temporal_rs_AnyCalendarKind_parse_temporal_calendar_string(cal_view);
@ -324,24 +290,21 @@ pub fn withCalendar(self: ZonedDateTime, calendar: []const u8) !ZonedDateTime {
}
/// Returns a new ZonedDateTime with the time part replaced by the new time.
///
/// See: [Temporal.ZonedDateTime.withPlainTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withPlainTime)
/// See [MDN Temporal.ZonedDateTime.prototype.withPlainTime()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withPlainTime)
pub fn withPlainTime(self: ZonedDateTime, time: ?PlainTime) !ZonedDateTime {
const time_ptr = if (time) |tt| tt._inner else null;
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_with_plain_time(self._inner, time_ptr));
}
/// Returns a new ZonedDateTime representing the same instant in a new time zone.
///
/// See: [Temporal.ZonedDateTime.withTimeZone](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withTimeZone)
/// See [MDN Temporal.ZonedDateTime.prototype.withTimeZone()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withTimeZone)
pub fn withTimeZone(self: ZonedDateTime, time_zone: TimeZone) !ZonedDateTime {
return wrapZonedDateTime(abi.c.temporal_rs_ZonedDateTime_with_timezone(self._inner, abi.to.toTimeZone(time_zone)));
}
// Property accessors
/// Returns the calendar identifier used to interpret the internal ISO 8601 date.
///
/// See: [Temporal.ZonedDateTime.calendarId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/calendarId)
/// See [MDN Temporal.ZonedDateTime.prototype.calendarId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/calendarId)
pub fn calendarId(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
const calendar_ptr = abi.c.temporal_rs_ZonedDateTime_calendar(self._inner) orelse return error.TemporalError;
const cal_id_view = abi.c.temporal_rs_Calendar_identifier(calendar_ptr);
@ -349,65 +312,56 @@ pub fn calendarId(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
}
/// Returns the 1-based day index in the month of this date.
///
/// See: [Temporal.ZonedDateTime.day](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/day)
/// See [MDN Temporal.ZonedDateTime.prototype.day](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/day)
pub fn day(self: ZonedDateTime) u8 {
return abi.c.temporal_rs_ZonedDateTime_day(self._inner);
}
/// Returns the 1-based day index in the week of this date.
///
/// See: [Temporal.ZonedDateTime.dayOfWeek](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/dayOfWeek)
/// See [MDN Temporal.ZonedDateTime.prototype.dayOfWeek](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/dayOfWeek)
pub fn dayOfWeek(self: ZonedDateTime) u16 {
return abi.c.temporal_rs_ZonedDateTime_day_of_week(self._inner);
}
/// Returns the 1-based day index in the year of this date.
///
/// See: [Temporal.ZonedDateTime.dayOfYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/dayOfYear)
/// See [MDN Temporal.ZonedDateTime.prototype.dayOfYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/dayOfYear)
pub fn dayOfYear(self: ZonedDateTime) u16 {
return abi.c.temporal_rs_ZonedDateTime_day_of_year(self._inner);
}
/// Returns the number of days in the month of this date.
///
/// See: [Temporal.ZonedDateTime.daysInMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInMonth)
/// See [MDN Temporal.ZonedDateTime.prototype.daysInMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInMonth)
pub fn daysInMonth(self: ZonedDateTime) u16 {
return abi.c.temporal_rs_ZonedDateTime_days_in_month(self._inner);
}
/// Returns the number of days in the week of this date.
///
/// See: [Temporal.ZonedDateTime.daysInWeek](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInWeek)
/// See [MDN Temporal.ZonedDateTime.prototype.daysInWeek](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInWeek)
pub fn daysInWeek(self: ZonedDateTime) u16 {
return abi.c.temporal_rs_ZonedDateTime_days_in_week(self._inner);
}
/// Returns the number of days in the year of this date.
///
/// See: [Temporal.ZonedDateTime.daysInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInYear)
/// See [MDN Temporal.ZonedDateTime.prototype.daysInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInYear)
pub fn daysInYear(self: ZonedDateTime) u16 {
return abi.c.temporal_rs_ZonedDateTime_days_in_year(self._inner);
}
/// Returns the number of milliseconds since the Unix epoch to this instant.
///
/// See: [Temporal.ZonedDateTime.epochMilliseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/epochMilliseconds)
/// See [MDN Temporal.ZonedDateTime.prototype.epochMilliseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/epochMilliseconds)
pub fn epochMilliseconds(self: ZonedDateTime) i64 {
return abi.c.temporal_rs_ZonedDateTime_epoch_milliseconds(self._inner);
}
/// Returns the number of nanoseconds since the Unix epoch to this instant.
///
/// See: [Temporal.ZonedDateTime.epochNanoseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/epochNanoseconds)
/// See [MDN Temporal.ZonedDateTime.prototype.epochNanoseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/epochNanoseconds)
pub fn epochNanoseconds(self: ZonedDateTime) i128 {
const parts = abi.c.temporal_rs_ZonedDateTime_epoch_nanoseconds(self._inner);
return abi.fromI128Nanoseconds(parts);
}
/// Returns the calendar-specific era of this date, or null if not applicable.
///
/// See: [Temporal.ZonedDateTime.era](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/era)
/// See [MDN Temporal.ZonedDateTime.prototype.era](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/era)
pub fn era(self: ZonedDateTime, allocator: std.mem.Allocator) !?[]u8 {
var write = abi.DiplomatWrite.init(allocator);
defer write.deinit();
@ -421,66 +375,57 @@ pub fn era(self: ZonedDateTime, allocator: std.mem.Allocator) !?[]u8 {
}
/// Returns the year of this date within the era, or null if not applicable.
///
/// See: [Temporal.ZonedDateTime.eraYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/eraYear)
/// See [MDN Temporal.ZonedDateTime.prototype.eraYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/eraYear)
pub fn eraYear(self: ZonedDateTime) ?i32 {
const result = abi.c.temporal_rs_ZonedDateTime_era_year(self._inner);
return abi.fromOption(result);
}
/// Returns the hour component of this time (0-23).
///
/// See: [Temporal.ZonedDateTime.hour](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/hour)
/// See [MDN Temporal.ZonedDateTime.prototype.hour](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/hour)
pub fn hour(self: ZonedDateTime) u8 {
return abi.c.temporal_rs_ZonedDateTime_hour(self._inner);
}
/// Returns the number of hours in the day of this date in the time zone.
///
/// See: [Temporal.ZonedDateTime.hoursInDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/hoursInDay)
/// See [MDN Temporal.ZonedDateTime.prototype.hoursInDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/hoursInDay)
pub fn hoursInDay(self: ZonedDateTime) !f64 {
const result = abi.c.temporal_rs_ZonedDateTime_hours_in_day(self._inner);
return try abi.extractResult(result);
}
/// Returns true if this date is in a leap year.
///
/// See: [Temporal.ZonedDateTime.inLeapYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/inLeapYear)
/// See [MDN Temporal.ZonedDateTime.prototype.inLeapYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/inLeapYear)
pub fn inLeapYear(self: ZonedDateTime) bool {
return abi.c.temporal_rs_ZonedDateTime_in_leap_year(self._inner);
}
/// Returns the microsecond component of this time (0-999).
///
/// See: [Temporal.ZonedDateTime.microsecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/microsecond)
/// See [MDN Temporal.ZonedDateTime.prototype.microsecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/microsecond)
pub fn microsecond(self: ZonedDateTime) u16 {
return abi.c.temporal_rs_ZonedDateTime_microsecond(self._inner);
}
/// Returns the millisecond component of this time (0-999).
///
/// See: [Temporal.ZonedDateTime.millisecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/millisecond)
/// See [MDN Temporal.ZonedDateTime.prototype.millisecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/millisecond)
pub fn millisecond(self: ZonedDateTime) u16 {
return abi.c.temporal_rs_ZonedDateTime_millisecond(self._inner);
}
/// Returns the minute component of this time (0-59).
///
/// See: [Temporal.ZonedDateTime.minute](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/minute)
/// See [MDN Temporal.ZonedDateTime.prototype.minute](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/minute)
pub fn minute(self: ZonedDateTime) u8 {
return abi.c.temporal_rs_ZonedDateTime_minute(self._inner);
}
/// Returns the 1-based month index in the year of this date.
///
/// See: [Temporal.ZonedDateTime.month](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/month)
/// See [MDN Temporal.ZonedDateTime.prototype.month](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/month)
pub fn month(self: ZonedDateTime) u8 {
return abi.c.temporal_rs_ZonedDateTime_month(self._inner);
}
/// Returns the calendar-specific string representing the month of this date.
///
/// See: [Temporal.ZonedDateTime.monthCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/monthCode)
/// See [MDN Temporal.ZonedDateTime.prototype.monthCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/monthCode)
pub fn monthCode(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
var write = abi.DiplomatWrite.init(allocator);
defer write.deinit();
@ -489,22 +434,19 @@ pub fn monthCode(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
}
/// Returns the number of months in the year of this date.
///
/// See: [Temporal.ZonedDateTime.monthsInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/monthsInYear)
/// See [MDN Temporal.ZonedDateTime.prototype.monthsInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/monthsInYear)
pub fn monthsInYear(self: ZonedDateTime) u16 {
return abi.c.temporal_rs_ZonedDateTime_months_in_year(self._inner);
}
/// Returns the nanosecond component of this time (0-999).
///
/// See: [Temporal.ZonedDateTime.nanosecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/nanosecond)
/// See [MDN Temporal.ZonedDateTime.prototype.nanosecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/nanosecond)
pub fn nanosecond(self: ZonedDateTime) u16 {
return abi.c.temporal_rs_ZonedDateTime_nanosecond(self._inner);
}
/// Returns the offset used to interpret the internal instant, as a string (±HH:mm).
///
/// See: [Temporal.ZonedDateTime.offset](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/offset)
/// See [MDN Temporal.ZonedDateTime.prototype.offset](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/offset)
pub fn offset(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
var write = abi.DiplomatWrite.init(allocator);
defer write.deinit();
@ -514,22 +456,19 @@ pub fn offset(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
}
/// Returns the offset used to interpret the internal instant, as a number of nanoseconds.
///
/// See: [Temporal.ZonedDateTime.offsetNanoseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/offsetNanoseconds)
/// See [MDN Temporal.ZonedDateTime.prototype.offsetNanoseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/offsetNanoseconds)
pub fn offsetNanoseconds(self: ZonedDateTime) i64 {
return abi.c.temporal_rs_ZonedDateTime_offset_nanoseconds(self._inner);
}
/// Returns the second component of this time (0-59).
///
/// See: [Temporal.ZonedDateTime.second](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/second)
/// See [MDN Temporal.ZonedDateTime.prototype.second](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/second)
pub fn second(self: ZonedDateTime) u8 {
return abi.c.temporal_rs_ZonedDateTime_second(self._inner);
}
/// Returns the time zone identifier used to interpret the internal instant.
///
/// See: [Temporal.ZonedDateTime.timeZoneId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/timeZoneId)
/// See [MDN Temporal.ZonedDateTime.prototype.timeZoneId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/timeZoneId)
pub fn timeZoneId(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
const tz = abi.c.temporal_rs_ZonedDateTime_timezone(self._inner);
var write = abi.DiplomatWrite.init(allocator);
@ -541,23 +480,20 @@ pub fn timeZoneId(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
}
/// Returns the 1-based week index in the year of this date, or null if not defined.
///
/// See: [Temporal.ZonedDateTime.weekOfYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/weekOfYear)
/// See [MDN Temporal.ZonedDateTime.prototype.weekOfYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/weekOfYear)
pub fn weekOfYear(self: ZonedDateTime) ?u8 {
const result = abi.c.temporal_rs_ZonedDateTime_week_of_year(self._inner);
return abi.fromOption(result);
}
/// Returns the year of this date relative to the calendar's epoch.
///
/// See: [Temporal.ZonedDateTime.year](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/year)
/// See [MDN Temporal.ZonedDateTime.prototype.year](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/year)
pub fn year(self: ZonedDateTime) i32 {
return abi.c.temporal_rs_ZonedDateTime_year(self._inner);
}
/// Returns the year to be paired with the weekOfYear of this date, or null if not defined.
///
/// See: [Temporal.ZonedDateTime.yearOfWeek](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/yearOfWeek)
/// See [MDN Temporal.ZonedDateTime.prototype.yearOfWeek](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/yearOfWeek)
pub fn yearOfWeek(self: ZonedDateTime) ?i32 {
const result = abi.c.temporal_rs_ZonedDateTime_year_of_week(self._inner);
return abi.fromOption(result);
@ -574,12 +510,7 @@ pub fn deinit(self: ZonedDateTime) void {
abi.c.temporal_rs_ZonedDateTime_destroy(self._inner);
}
/// Helper function to wrap a C API result into a ZonedDateTime
fn wrapZonedDateTime(result: anytype) !ZonedDateTime {
const ptr = (try abi.extractResult(result)) orelse return abi.TemporalError.Generic;
return .{ ._inner = ptr };
}
// ---------- Tests ---------------------
test init {
const tz = try TimeZone.init("America/New_York");
const zdt = try init(0, tz);
@ -731,11 +662,7 @@ test add {
}
test getTimeZoneTransition {
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
try std.testing.expectEqual(@as(?ZonedDateTime, null), try zdt.getTimeZoneTransition(.next));
try std.testing.expectEqual(@as(?ZonedDateTime, null), try zdt.getTimeZoneTransition(.previous));
if (true) return error.SkipZigTest; // getTimeZoneTransition() not properly implemented in underlying library
}
test round {
@ -829,14 +756,7 @@ test valueOf {
test with {
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
const result = try zdt.with(std.testing.allocator, .{ .year = 2022, .month = 2, .day = 3, .hour = 4 });
defer result.deinit();
try std.testing.expectEqual(@as(i32, 2022), result.year());
try std.testing.expectEqual(@as(u8, 2), result.month());
try std.testing.expectEqual(@as(u8, 3), result.day());
try std.testing.expectEqual(@as(u8, 4), result.hour());
try std.testing.expectError(error.TemporalNoteImplemented, zdt.with(std.testing.allocator, .{}));
}
test withCalendar {
@ -881,12 +801,6 @@ test calendarId {
try std.testing.expect(cal_id.len > 0);
}
test day {
const zdt = try from("2021-01-02T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
try std.testing.expectEqual(@as(u8, 2), zdt.day());
}
test dayOfWeek {
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
@ -954,12 +868,6 @@ test eraYear {
}
}
test hour {
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
try std.testing.expectEqual(@as(u8, 12), zdt.hour());
}
test hoursInDay {
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
@ -984,24 +892,6 @@ test microsecond {
try std.testing.expect(us >= 0 and us < 1000);
}
test millisecond {
const zdt = try from("2021-01-01T12:00:00.123456789+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
try std.testing.expectEqual(@as(u16, 123), zdt.millisecond());
}
test minute {
const zdt = try from("2021-01-01T12:34:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
try std.testing.expectEqual(@as(u8, 34), zdt.minute());
}
test month {
const zdt = try from("2021-07-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
try std.testing.expectEqual(@as(u8, 7), zdt.month());
}
test monthCode {
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
@ -1024,12 +914,7 @@ test nanosecond {
}
test offset {
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
const off = try zdt.offset(std.testing.allocator);
defer std.testing.allocator.free(off);
try std.testing.expectEqualStrings("+00:00", off);
if (true) return error.SkipZigTest; // offset() throws RangeError with UTC timezone
}
test offsetNanoseconds {
@ -1039,21 +924,6 @@ test offsetNanoseconds {
try std.testing.expectEqual(@as(i64, 0), off_ns);
}
test second {
const zdt = try from("2021-01-01T12:34:56+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
try std.testing.expectEqual(@as(u8, 56), zdt.second());
}
test timeZoneId {
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
const id = try zdt.timeZoneId(std.testing.allocator);
defer std.testing.allocator.free(id);
try std.testing.expectEqualStrings("UTC", id);
}
test weekOfYear {
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
@ -1063,12 +933,6 @@ test weekOfYear {
}
}
test year {
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();
try std.testing.expectEqual(@as(i32, 2021), zdt.year());
}
test yearOfWeek {
const zdt = try from("2021-01-01T12:00:00+00:00[UTC]", null, .compatible, .reject);
defer zdt.deinit();

View file

@ -1,6 +1,6 @@
const std = @import("std");
pub const c = @import("libtemporal").c;
pub const c = @import("temporal_rs").c;
pub const to_string_rounding_options_auto: c.ToStringRoundingOptions = .{
.precision = .{ .is_minute = false, .precision = toOption(c.OptionU8, null) },
@ -90,85 +90,6 @@ pub fn toTimeZoneOption(maybe_value: ?c.TimeZone) c.TimeZone_option {
return toOption(c.TimeZone_option, maybe_value);
}
pub fn toPartialZonedDateTime(fields: anytype) c.PartialZonedDateTime {
return .{
.date = .{
.year = toI32OptionField(fields, "year"),
.month = toU8OptionField(fields, "month"),
.month_code = toStringViewField(fields, "month_code"),
.day = toU8OptionField(fields, "day"),
.era = toStringViewField(fields, "era"),
.era_year = toI32OptionField(fields, "era_year"),
.calendar = c.AnyCalendarKind_Iso,
},
.time = .{
.hour = toU8OptionField(fields, "hour"),
.minute = toU8OptionField(fields, "minute"),
.second = toU8OptionField(fields, "second"),
.millisecond = toU16OptionField(fields, "millisecond"),
.microsecond = toU16OptionField(fields, "microsecond"),
.nanosecond = toU16OptionField(fields, "nanosecond"),
},
.offset = toOptionStringViewField(fields, "offset"),
.timezone = toTimeZoneOptionField(fields, "time_zone"),
};
}
fn toI32OptionField(fields: anytype, comptime name: []const u8) c.OptionI32 {
return toOption(c.OptionI32, intField(i32, fields, name));
}
fn toU8OptionField(fields: anytype, comptime name: []const u8) c.OptionU8 {
return toOption(c.OptionU8, intField(u8, fields, name));
}
fn toU16OptionField(fields: anytype, comptime name: []const u8) c.OptionU16 {
return toOption(c.OptionU16, intField(u16, fields, name));
}
fn intField(comptime Int: type, fields: anytype, comptime name: []const u8) ?Int {
if (!@hasField(@TypeOf(fields), name)) return null;
const value = @field(fields, name);
return switch (@typeInfo(@TypeOf(value))) {
.optional => if (value) |payload| @as(Int, @intCast(payload)) else null,
else => @as(Int, @intCast(value)),
};
}
fn toStringViewField(fields: anytype, comptime name: []const u8) c.DiplomatStringView {
if (stringField(fields, name)) |value| return toDiplomatStringView(value);
return .{ .data = null, .len = 0 };
}
fn toOptionStringViewField(fields: anytype, comptime name: []const u8) c.OptionStringView {
if (stringField(fields, name)) |value| {
return .{ .is_ok = true, .unnamed_0 = .{ .ok = toDiplomatStringView(value) } };
}
return .{ .is_ok = false };
}
fn stringField(fields: anytype, comptime name: []const u8) ?[]const u8 {
if (!@hasField(@TypeOf(fields), name)) return null;
const value = @field(fields, name);
return switch (@typeInfo(@TypeOf(value))) {
.optional => value,
else => value,
};
}
fn toTimeZoneOptionField(fields: anytype, comptime name: []const u8) c.TimeZone_option {
if (!@hasField(@TypeOf(fields), name)) return .{ .is_ok = false };
const value = @field(fields, name);
const maybe_time_zone = switch (@typeInfo(@TypeOf(value))) {
.optional => if (value) |payload| payload._inner else null,
else => value._inner,
};
return toOption(c.TimeZone_option, maybe_time_zone);
}
/// Convert a Zig `?Unit` to a Rust `Option<Unit>`.
pub fn toUnitOption(maybe_value: ?c.Unit) c.Unit_option {
return toOption(c.Unit_option, maybe_value);

View file

@ -4,49 +4,49 @@ const Temporal = @This();
/// The `Temporal.Duration` object represents a difference between two time points, which can be used in date/time arithmetic.
/// It is fundamentally represented as a combination of years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, and nanoseconds values.
///
/// See: [Temporal.Duration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration)
/// - [MDN Temporal.Duration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration)
pub const Duration = @import("Duration.zig");
/// The `Temporal.Instant` object represents a unique point in time, with nanosecond precision.
/// It is fundamentally represented as the number of nanoseconds since the Unix epoch (midnight at the beginning of January 1, 1970, UTC), without any time zone or calendar system.
///
/// See: [Temporal.Instant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant)
/// - [MDN Temporal.Instant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant)
pub const Instant = @import("Instant.zig");
/// The `Temporal.Now` namespace object contains static methods for getting the current time in various formats.
/// All properties and methods are static.
///
/// See: [Temporal.Now](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now)
/// - [MDN Temporal.Now](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now)
pub const Now = @import("Now.zig");
/// The `Temporal.PlainDate` object represents a calendar date (year, month, day) with no time or time zone.
///
/// See: [Temporal.PlainDate](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDate)
/// - [MDN Temporal.PlainDate](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDate)
pub const PlainDate = @import("PlainDate.zig");
/// The `Temporal.PlainDateTime` object represents a calendar date and wall-clock time, but no time zone or offset.
///
/// See: [Temporal.PlainDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime)
/// - [MDN Temporal.PlainDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime)
pub const PlainDateTime = @import("PlainDateTime.zig");
/// The `Temporal.PlainMonthDay` object represents a month and day in a calendar, with no year or time.
///
/// See: [Temporal.PlainMonthDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay)
/// - [MDN Temporal.PlainMonthDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay)
pub const PlainMonthDay = @import("PlainMonthDay.zig");
/// The `Temporal.PlainTime` object represents a wall-clock time, with no date or time zone.
///
/// See: [Temporal.PlainTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime)
/// - [MDN Temporal.PlainTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime)
pub const PlainTime = @import("PlainTime.zig");
/// The `Temporal.PlainYearMonth` object represents a particular month in a specific year, with no day or time.
///
/// See: [Temporal.PlainYearMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth)
/// - [MDN Temporal.PlainYearMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth)
pub const PlainYearMonth = @import("PlainYearMonth.zig");
/// The `Temporal.ZonedDateTime` object represents an exact time, including a time zone and calendar.
///
/// See: [Temporal.ZonedDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime)
/// - [MDN Temporal.ZonedDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime)
pub const ZonedDateTime = @import("ZonedDateTime.zig");
test Temporal {
@ -227,7 +227,6 @@ test PlainDate {
"ToStringOptions",
"CalendarDisplay",
"ToZonedDateTimeOptions",
"WithOptions",
"Unit",
"RoundingMode",
"Sign",
@ -502,7 +501,6 @@ test ZonedDateTime {
"DisplayOffset",
"DisplayTimeZone",
"ToStringOptions",
"WithOptions",
};
try assertDecls(ZonedDateTime, checks);
@ -526,10 +524,10 @@ fn assertDecls(comptime T: type, checks: anytype) !void {
var hasField = false;
if (typeInfo == .@"struct") {
const struct_info = typeInfo.@"struct";
inline for (struct_info.field_names) |field_name| {
inline for (struct_info.fields) |field| {
// Check both camelCase and snake_case
if (std.mem.eql(u8, field_name, check) or
std.mem.eql(u8, field_name, camelToSnakeCase(check)))
if (std.mem.eql(u8, field.name, check) or
std.mem.eql(u8, field.name, camelToSnakeCase(check)))
{
hasField = true;
break;
@ -548,39 +546,39 @@ fn assertDecls(comptime T: type, checks: anytype) !void {
const struct_info = typeInfo.@"struct";
// Check declarations
inline for (struct_info.decl_names) |decl_name| {
inline for (struct_info.decls) |decl| {
// Allow deinit as extraneous
if (comptime std.mem.eql(u8, decl_name, "deinit")) continue;
if (comptime std.mem.eql(u8, decl.name, "deinit")) continue;
var found = false;
inline for (checks) |check| {
if (std.mem.eql(u8, decl_name, check)) {
if (std.mem.eql(u8, decl.name, check)) {
found = true;
break;
}
}
if (!found) {
std.log.err("Extraneous {s} decl: {s}", .{ @typeName(T), decl_name });
std.log.err("Extraneous {s} decl: {s}", .{ @typeName(T), decl.name });
try std.testing.expect(false);
}
}
// Check fields (properties)
inline for (struct_info.field_names) |field_name| {
inline for (struct_info.fields) |field| {
// Allow internal fields (starting with underscore)
if (comptime std.mem.startsWith(u8, field_name, "_")) continue;
if (comptime std.mem.startsWith(u8, field.name, "_")) continue;
var found = false;
inline for (checks) |check| {
if (std.mem.eql(u8, field_name, camelToSnakeCase(check))) {
if (std.mem.eql(u8, field.name, camelToSnakeCase(check))) {
found = true;
break;
}
}
if (!found) {
std.log.err("Extraneous {s} field: {s}", .{ @typeName(T), field_name });
std.log.err("Extraneous {s} field: {s}", .{ @typeName(T), field.name });
try std.testing.expect(false);
}
}

View file

@ -1,4 +1,11 @@
/// # Temporal Types and Utilities
///
/// This file defines core types and options used throughout the Temporal API implementation.
///
/// - [MDN Temporal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal)
/// ## Unit
/// Time unit for Temporal operations (e.g., nanosecond, second, day, year).
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal
pub const Unit = enum {
auto,
nanosecond,
@ -83,11 +90,9 @@ pub const TimeZone = struct {
_inner: abi.c.TimeZone,
/// Initialize a TimeZone from an identifier string.
pub fn init(id: []const u8) !TimeZone {
pub fn init(id: []const u8) TimeZone {
const view = abi.toDiplomatStringView(id);
const result = abi.c.temporal_rs_TimeZone_try_from_str(view);
const time_zone = try abi.extractResult(result);
return .{ ._inner = time_zone };
return .{ ._inner = .{ .id = view } };
}
};

View file

@ -20,7 +20,7 @@ pub const std_options = std.Options{
const Allocator = std.mem.Allocator;
const BORDER: [80]u8 = @splat('=');
const BORDER = "=" ** 80;
// use in custom panic handler
var current_test: ?[]const u8 = null;
@ -31,7 +31,6 @@ pub fn main(init: std.process.Init) !void {
const env = Env.init(allocator, init.minimal.environ);
defer env.deinit(allocator);
std.testing.environ = env.environ;
var slowest = SlowTracker.init(allocator, io, 15);
defer slowest.deinit(allocator);
@ -100,13 +99,13 @@ pub fn main(init: std.process.Init) !void {
while (attempt < max_attempts) : (attempt += 1) {
current_test = friendly_name;
std.testing.allocator_instance = .init(std.heap.page_allocator, .{});
std.testing.allocator_instance = .{};
final_result = t.func();
current_test = null;
final_ns_taken = slowest.endTiming(allocator, scope_name, friendly_name);
if (std.testing.allocator_instance.deinit() > 0) {
if (std.testing.allocator_instance.deinit() == .leak) {
leak += 1;
Printer.status(.fail, "\n{s}\n\"{s}\" - Memory Leak\n{s}\n", .{ BORDER, friendly_name, BORDER });
}
@ -150,7 +149,7 @@ pub fn main(init: std.process.Init) !void {
Printer.status(.fail, "\n{s}\n\"{s}\" - {s}\n{s}\n", .{ BORDER, friendly_name, @errorName(err), BORDER });
}
if (@errorReturnTrace()) |trace| {
std.debug.dumpErrorReturnTrace(trace);
std.debug.dumpStackTrace(trace);
}
if (env.fail_first) {
break;
@ -273,9 +272,8 @@ const SlowTracker = struct {
name: []const u8,
};
fn deinit(self: *SlowTracker, allocator: Allocator) void {
var slowest = &self.slowest;
slowest.deinit(allocator);
fn deinit(self: SlowTracker, allocator: Allocator) void {
self.slowest.deinit(allocator);
}
fn startTiming(self: *SlowTracker) void {

View file

@ -1,17 +0,0 @@
import { readFile } from "fs/promises";
let memory = null;
const buffer = await readFile("zig-out/bin/temporalz.wasm");
const temporalz = await WebAssembly.instantiate(buffer, {
env: {
console(ptr, len) {
const bytes = new Uint8Array(memory.buffer, ptr, len);
const message = new TextDecoder().decode(bytes);
console.log(message);
},
},
});
memory = temporalz.instance.exports.memory;
temporalz.instance.exports._start();

View file

@ -1,24 +0,0 @@
const std = @import("std");
const builtin = @import("builtin");
const program = @import("root.zig");
const freestanding = builtin.os.tag == .freestanding;
pub fn main(init: Init) !void {
const allocator = std.heap.page_allocator;
const io = if (freestanding) null else init.io;
try program.run(allocator, io);
}
// -- //
const Init = if (freestanding) std.process.Init.Minimal else std.process.Init;
pub const std_options: std.Options = .{
.logFn = if (freestanding) logFn else std.log.defaultLog,
};
extern fn console(ptr: [*]u8, len: u32) void;
fn logFn(comptime _: anytype, comptime _: anytype, comptime format: []const u8, args: anytype) void {
const formatted = std.fmt.allocPrint(std.heap.wasm_allocator, format, args) catch return;
console(formatted.ptr, formatted.len);
}

View file

@ -1,913 +0,0 @@
const std = @import("std");
const builtin = @import("builtin");
const Temporal = @import("temporalz");
pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
// --- Instant --- //
const instant = try Temporal.Instant.init(1_704_067_200_000_000_000); // 2024-01-01 00:00:00 UTC
defer instant.deinit();
std.log.info(
\\Instant
\\ - milliseconds: {}
\\ - nanoseconds: {}
\\ - toString(): {s}
\\
\\
, .{
instant.epochMilliseconds(),
instant.epochNanoseconds(),
try instant.toString(allocator, .{}),
});
// --- Duration --- //
const dur = try Temporal.Duration.from("PT1H");
defer dur.deinit();
std.log.info(
\\Duration
\\ - nanoseconds: {}
\\ - milliseconds: {}
\\ - seconds: {}
\\ - minutes: {}
\\ - hours: {}
\\ - days: {}
\\ - weeks: {}
\\ - months: {}
\\ - years: {}
\\ - toString(): {s}
\\
\\
, .{
dur.nanoseconds(),
dur.milliseconds(),
dur.seconds(),
dur.minutes(),
dur.hours(),
dur.days(),
dur.weeks(),
dur.months(),
dur.years(),
try dur.toString(allocator, .{}),
});
// --- Now --- //
if (io_optional) |io| {
const now_instant = try Temporal.Now.instant(io);
defer now_instant.deinit();
const now_date = try Temporal.Now.plainDateISO(allocator, io, null);
defer now_date.deinit();
const now_datetime = try Temporal.Now.plainDateTimeISO(allocator, io, null);
const now_time = try Temporal.Now.plainTimeISO(allocator, io, null);
std.log.info(
\\Now
\\ - instant: {s}
\\ - date: {s}
\\ - datetime: {s}
\\ - time: {s}
\\
\\
, .{
try now_instant.toString(allocator, .{}),
try now_date.toString(allocator, .{}),
try now_datetime.toString(allocator, .{}),
try now_time.toString(allocator),
});
}
// --- PlainDate --- //
const date = try Temporal.PlainDate.init(2024, 2, 2);
defer date.deinit();
std.log.info(
\\PlainDate
\\ - year: {}
\\ - month: {}
\\ - day: {}
\\ - toString(): {s}
\\
\\
, .{
date.year(),
date.month(),
date.day(),
try date.toString(allocator, .{}),
});
// --- PlainDateTime --- //
const dt = try Temporal.PlainDateTime.init(2024, 2, 2, 13, 45, 30, 123, 456, 789);
std.log.info(
\\PlainDateTime
\\ - year: {}
\\ - month: {}
\\ - day: {}
\\ - hour: {}
\\ - minute: {}
\\ - second: {}
\\ - toString(): {s}
\\
\\
, .{
dt.year(),
dt.month(),
dt.day(),
dt.hour(),
dt.minute(),
dt.second(),
try dt.toString(allocator, .{}),
});
// --- PlainMonthDay --- //
const md = try Temporal.PlainMonthDay.init(2, 2, null);
std.log.info(
\\PlainMonthDay
\\ - monthCode: {s}
\\ - day: {}
\\ - toString(): {s}
\\
\\
, .{
try md.monthCode(allocator),
md.day(),
try md.toString(allocator),
});
// --- PlainTime --- //
const tm = try Temporal.PlainTime.init(13, 45, 30, 123, 456, 789);
std.log.info(
\\PlainTime
\\ - hour: {}
\\ - minute: {}
\\ - second: {}
\\ - toString(): {s}
\\
\\
, .{
tm.hour(),
tm.minute(),
tm.second(),
try tm.toString(allocator),
});
// --- PlainYearMonth --- //
const ym = try Temporal.PlainYearMonth.init(2024, 2, null);
std.log.info(
\\PlainYearMonth
\\ - year: {}
\\ - month: {}
\\ - toString(): {s}
\\
\\
, .{ ym.year(), ym.month(), try ym.toString(allocator) });
// --- ZonedDateTime --- //
const tz = try Temporal.ZonedDateTime.TimeZone.init("UTC");
// Example: 2024-02-02T13:45:30.123456789Z in nanoseconds since epoch
const zdt_epoch_ns: i128 = 1706881530123456789;
const zdt = try Temporal.ZonedDateTime.fromEpochNanoseconds(zdt_epoch_ns, tz);
defer zdt.deinit();
std.log.info(
\\ZonedDateTime
\\ - year: {}
\\ - month: {}
\\ - day: {}
\\ - hour: {}
\\ - minute: {}
\\ - second: {}
\\ - timeZone: {s}
\\ - toString(): {s}
\\
\\
, .{
zdt.year(),
zdt.month(),
zdt.day(),
zdt.hour(),
zdt.minute(),
zdt.second(),
try zdt.timeZoneId(allocator),
try zdt.toString(allocator, .{}),
});
try runTimeZoneExamples(allocator, io_optional, null);
// ----
// More complex Temporal API examples
// ----
// Duration arithmetic
const dur1 = try Temporal.Duration.from("P1DT2H");
const dur2 = try Temporal.Duration.from("PT30M");
const dur_sum = try dur1.add(dur2);
std.log.info(
\\Duration Arithmetic
\\ - dur1: {s}
\\ - dur2: {s}
\\ - dur1 + dur2: {s}
\\
\\
, .{
try dur1.toString(allocator, .{}),
try dur2.toString(allocator, .{}),
try dur_sum.toString(allocator, .{}),
});
// Instant comparison and arithmetic
const inst1 = try Temporal.Instant.init(1_704_067_200_000_000_000);
const inst2 = try Temporal.Instant.init(1_704_153_600_000_000_000); // +1 day
const inst_diff = try inst2.since(inst1, Temporal.Instant.DifferenceSettings{});
std.log.info(
\\Instant Comparison
\\ - inst1: {s}
\\ - inst2: {s}
\\ - inst2.since(inst1): {s}
\\
\\
, .{
try inst1.toString(allocator, .{}),
try inst2.toString(allocator, .{}),
try inst_diff.toString(allocator, .{}),
});
// PlainDate to PlainDateTime and back
const pd = try Temporal.PlainDate.init(2024, 2, 2);
const pdt = try pd.toPlainDateTime(try Temporal.PlainTime.init(12, 0, 0, 0, 0, 0));
std.log.info(
\\PlainDate/PlainDateTime Conversion
\\ - PlainDate: {s}
\\ - toPlainDateTime(12:00): {s}
\\ - toPlainDate(): {s}
\\
\\
, .{
try pd.toString(allocator, .{}),
try pdt.toString(allocator, .{}),
try (try pdt.toPlainDate()).toString(allocator, .{}),
});
// ZonedDateTime to Instant and back
const zdt2 = try Temporal.ZonedDateTime.fromEpochNanoseconds(1706881530123456789, tz);
const zdt2_inst = try zdt2.toInstant();
const zdt2_from_inst = try Temporal.ZonedDateTime.fromEpochNanoseconds(zdt2_inst.epochNanoseconds(), tz);
std.log.info(
\\ZonedDateTime/Instant Conversion
\\ - ZonedDateTime: {s}
\\ - toInstant(): {s}
\\ - fromEpochNanoseconds(instant): {s}
\\
\\
, .{
try zdt2.toString(allocator, .{}),
try zdt2_inst.toString(allocator, .{}),
try zdt2_from_inst.toString(allocator, .{}),
});
// ----
// Further more complex examples covering more methods
// ----
// Duration: abs, negated, round, subtract, total, valueOf
const dur_neg = dur.negated();
const dur_abs = dur_neg.abs();
const dur_sub = try dur.subtract(dur2);
const dur_rounded = try dur.round(.{ .smallest_unit = Temporal.Duration.Unit.hour });
const dur_total_hours = try dur.total(.{ .unit = Temporal.Duration.Unit.hour });
std.log.info(
\\Duration Advanced
\\ - negated: {s}
\\ - abs: {s}
\\ - subtract dur2: {s}
\\ - round to hour: {s}
\\ - total hours: {d}
\\
\\
, .{
try dur_neg.toString(allocator, .{}),
try dur_abs.toString(allocator, .{}),
try dur_sub.toString(allocator, .{}),
try dur_rounded.toString(allocator, .{}),
dur_total_hours,
});
// Instant: add, subtract, round, equals, valueOf
const inst_add = try inst1.add(@constCast(&dur));
const inst_sub = try inst2.subtract(@constCast(&dur));
const inst_rounded = try inst1.round(.{ .smallest_unit = Temporal.Instant.Unit.second });
const inst_eq = Temporal.Instant.compare(inst1, inst1) == 0;
std.log.info(
\\Instant Advanced
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - round to second: {s}
\\ - inst1 equals inst1: {}
\\
\\
, .{
try inst_add.toString(allocator, .{}),
try inst_sub.toString(allocator, .{}),
try inst_rounded.toString(allocator, .{}),
inst_eq,
});
// PlainDate: add, subtract, with, equals, since, until, withCalendar
const date_added = try date.add(dur);
const date_sub = try date.subtract(dur);
const date_with = try date.with(.{ .year = 2025 });
const date_eq = date.equals(date);
const date_since = try date.since(date, Temporal.PlainDate.DifferenceSettings{});
const date_until = try date.until(date, Temporal.PlainDate.DifferenceSettings{});
const date_with_cal = try date.withCalendar("iso8601");
std.log.info(
\\PlainDate Advanced
\\ - equals self: {}
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - since self: {s}
\\ - until self: {s}
\\ - withCalendar: {s}
\\ - with year=2025: {s}
\\
\\
,
.{
date_eq,
try date_added.toString(allocator, .{}),
try date_sub.toString(allocator, .{}),
try date_since.toString(allocator, .{}),
try date_until.toString(allocator, .{}),
try date_with_cal.toString(allocator, .{}),
try date_with.toString(allocator, .{}),
},
);
// PlainDateTime: add, subtract, round, with, equals, since, until, withCalendar, withPlainTime
const dt_added = try dt.add(dur);
const dt_sub = try dt.subtract(dur);
const dt_rounded = try dt.round(.{ .smallest_unit = Temporal.PlainDateTime.Unit.minute });
const dt_with = try dt.with(.{ .year = 2025 });
const dt_eq = dt.equals(dt);
const dt_since = try dt.since(dt, Temporal.PlainDateTime.DifferenceSettings{});
const dt_until = try dt.until(dt, Temporal.PlainDateTime.DifferenceSettings{});
const dt_with_cal = try dt.withCalendar("iso8601");
const dt_with_time = try dt.withPlainTime(try Temporal.PlainTime.init(1, 2, 3, 4, 5, 6));
std.log.info(
\\PlainDateTime Advanced
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - round to minute: {s}
\\ - with year=2025: {s}
\\ - equals self: {}
\\ - since self: {s}
\\ - until self: {s}
\\ - withCalendar: {s}
\\ - withPlainTime: {s}
\\
\\
, .{
try dt_added.toString(allocator, .{}),
try dt_sub.toString(allocator, .{}),
try dt_rounded.toString(allocator, .{}),
try dt_with.toString(allocator, .{}),
dt_eq,
try dt_since.toString(allocator, .{}),
try dt_until.toString(allocator, .{}),
try dt_with_cal.toString(allocator, .{}),
try dt_with_time.toString(allocator, .{}),
});
// PlainTime: add, subtract, round, with, equals, since, until
const tm_added = try tm.add(dur);
const tm_sub = try tm.subtract(dur);
const tm_rounded = try tm.round(.{ .smallest_unit = Temporal.PlainTime.Unit.second });
const tm_with = try tm.with(.{ .hour = 1 });
const tm_eq = tm.equals(tm);
const tm_since = try tm.since(tm, Temporal.PlainTime.DifferenceSettings{});
const tm_until = try tm.until(tm, Temporal.PlainTime.DifferenceSettings{});
std.log.info(
\\PlainTime Advanced
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - round to second: {s}
\\ - with hour=1: {s}
\\ - equals self: {}
\\ - since self: {s}
\\ - until self: {s}
\\
\\
, .{
try tm_added.toString(allocator),
try tm_sub.toString(allocator),
try tm_rounded.toString(allocator),
try tm_with.toString(allocator),
tm_eq,
try tm_since.toString(allocator, .{}),
try tm_until.toString(allocator, .{}),
});
// PlainYearMonth: add, subtract, with, equals, since, until
const dur_ym = try Temporal.Duration.from("P1M");
defer dur_ym.deinit();
const ym_added = try ym.add(dur_ym);
const ym_sub = try ym.subtract(dur_ym);
const ym_with = try ym.with(.{ .year = 2025 });
const ym_eq = ym.equals(ym);
const ym_since = try ym.since(ym, Temporal.PlainYearMonth.DifferenceSettings{});
const ym_until = try ym.until(ym, Temporal.PlainYearMonth.DifferenceSettings{});
std.log.info(
\\PlainYearMonth Advanced
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - with year=2025: {s}
\\ - equals self: {}
\\ - since self: {s}
\\ - until self: {s}
\\
\\
, .{
try ym_added.toString(allocator),
try ym_sub.toString(allocator),
try ym_with.toString(allocator),
ym_eq,
try ym_since.toString(allocator, .{}),
try ym_until.toString(allocator, .{}),
});
// ZonedDateTime: add, subtract, round, equals, since, until, withCalendar, withPlainTime, withTimeZone
const zdt_added = try zdt.add(dur);
const zdt_sub = try zdt.subtract(dur);
const zdt_rounded = try zdt.round(.{ .smallest_unit = Temporal.ZonedDateTime.Unit.hour });
const zdt_eq = zdt.equals(zdt);
const zdt_since = try zdt.since(zdt, Temporal.ZonedDateTime.DifferenceSettings{});
const zdt_until = try zdt.until(zdt, Temporal.ZonedDateTime.DifferenceSettings{});
const zdt_with_cal = try zdt.withCalendar("iso8601");
const zdt_with_time = try zdt.withPlainTime(try Temporal.PlainTime.init(1, 2, 3, 4, 5, 6));
const zdt_with_tz = try zdt.withTimeZone(tz);
std.log.info(
\\ZonedDateTime Advanced
\\ - add duration: {s}
\\ - subtract duration: {s}
\\ - round to hour: {s}
\\ - equals self: {}
\\ - since self: {s}
\\ - until self: {s}
\\ - withCalendar: {s}
\\ - withPlainTime: {s}
\\ - withTimeZone: {s}
\\
\\
, .{
try zdt_added.toString(allocator, .{}),
try zdt_sub.toString(allocator, .{}),
try zdt_rounded.toString(allocator, .{}),
zdt_eq,
try zdt_since.toString(allocator, .{}),
try zdt_until.toString(allocator, .{}),
try zdt_with_cal.toString(allocator, .{}),
try zdt_with_time.toString(allocator, .{}),
try zdt_with_tz.toString(allocator, .{}),
});
// ----
// API coverage examples for the remaining public methods
// ----
const dur_init = try Temporal.Duration.init(0, 1, 0, 2, 3, 4, 5, 6, 7, 8);
const dur_from_partial = try Temporal.Duration.from(Temporal.Duration.PartialDuration{ .minutes = 90 });
const dur_compare = try dur.compare(dur2, .{});
const dur_locale_supported = dur.toLocaleString(allocator) != error.TemporalNotImplemented;
std.log.info(
\\Duration Coverage
\\ - init: {s}
\\ - from partial: {s}
\\ - compare(dur, dur2): {}
\\ - sign: {s}
\\ - blank: {}
\\ - microseconds: {d}
\\ - toJSON(): {s}
\\ - toLocaleString supported: {}
\\
\\
, .{
try dur_init.toString(allocator, .{}),
try dur_from_partial.toString(allocator, .{}),
dur_compare,
@tagName(dur.sign()),
dur.blank(),
dur.microseconds(),
try dur.toJSON(allocator),
dur_locale_supported,
});
const instant_from_ms = try Temporal.Instant.fromEpochMilliseconds(1_704_067_200_000);
const instant_from_ns = try Temporal.Instant.fromEpochNanoseconds(1_704_067_200_000_000_000);
const instant_from_str = try Temporal.Instant.from("2024-01-01T00:00:00Z");
const instant_until = try inst1.until(inst2, Temporal.Instant.DifferenceSettings{});
const instant_zdt = try inst1.toZonedDateTimeISO(try Temporal.Instant.TimeZone.init("UTC"));
defer instant_zdt.deinit();
std.log.info(
\\Instant Coverage
\\ - fromEpochMilliseconds: {s}
\\ - fromEpochNanoseconds: {s}
\\ - from string: {s}
\\ - equals(from ms, from ns): {}
\\ - until inst2: {s}
\\ - toJSON(): {s}
\\ - toLocaleString(): {s}
\\ - toZonedDateTimeISO(): {s}
\\
\\
, .{
try instant_from_ms.toString(allocator, .{}),
try instant_from_ns.toString(allocator, .{}),
try instant_from_str.toString(allocator, .{}),
Temporal.Instant.equals(instant_from_ms, instant_from_ns),
try instant_until.toString(allocator, .{}),
try inst1.toJSON(allocator),
try inst1.toLocaleString(allocator),
try instant_zdt.toString(allocator, .{}),
});
if (io_optional) |io| {
const now_zdt = try Temporal.Now.zonedDateTimeISO(allocator, io, null);
defer now_zdt.deinit();
const now_tz_id = try Temporal.Now.timeZoneId(allocator, io);
defer allocator.free(now_tz_id);
std.log.info(
\\Now Coverage
\\ - timeZoneId(): {s}
\\ - zonedDateTimeISO(): {s}
\\
\\
, .{
now_tz_id,
try now_zdt.toString(allocator, .{}),
});
}
const date_cal = try Temporal.PlainDate.calInit(2024, 2, 2, "iso8601");
const date_from = try Temporal.PlainDate.from("2024-02-02");
const date_md = try date.toPlainMonthDay();
const date_ym = try date.toPlainYearMonth();
const date_zdt = try date.toZonedDateTime(.{ .time_zone = "UTC", .plain_time = tm });
const date_locale_supported = date.toLocaleString(allocator) != error.TemporalNotImplemented;
const date_valueof_supported = date.valueOf() != error.TemporalValueOfNotSupported;
const date_with_coverage = try date.with(.{ .year = 2025, .month = 3, .day = 4 });
std.log.info(
\\PlainDate Coverage
\\ - calInit: {s}
\\ - from string: {s}
\\ - compare(date, from): {}
\\ - calendarId: {s}
\\ - dayOfWeek/dayOfYear: {}/{}
\\ - daysInWeek/daysInMonth/daysInYear: {}/{}/{}
\\ - monthCode/monthsInYear: {s}/{}
\\ - inLeapYear: {}
\\ - era/eraYear: {any}/{?}
\\ - weekOfYear/yearOfWeek: {?}/{?}
\\ - toPlainMonthDay: {s}
\\ - toPlainYearMonth: {s}
\\ - toZonedDateTime: {s}
\\ - toJSON(): {s}
\\ - toLocaleString supported: {}
\\ - valueOf supported: {}
\\ - with year/month/day: {s}
\\
\\
, .{
try date_cal.toString(allocator, .{}),
try date_from.toString(allocator, .{}),
Temporal.PlainDate.compare(date, date_from),
try date.calendarId(allocator),
date.dayOfWeek(),
date.dayOfYear(),
date.daysInWeek(),
date.daysInMonth(),
date.daysInYear(),
try date.monthCode(allocator),
date.monthsInYear(),
date.inLeapYear(),
try date.era(allocator),
date.eraYear(),
date.weekOfYear(),
date.yearOfWeek(),
try date_md.toString(allocator),
try date_ym.toString(allocator),
try date_zdt.toString(allocator, .{}),
try date.toJSON(allocator),
date_locale_supported,
date_valueof_supported,
try date_with_coverage.toString(allocator, .{}),
});
const dt_cal = try Temporal.PlainDateTime.calInit(2024, 2, 2, 13, 45, 30, 123, 456, 789, "iso8601");
const dt_from = try Temporal.PlainDateTime.from("2024-02-02T13:45:30.123456789", .{});
const dt_plain_time = try dt.toPlainTime();
const dt_zdt = try dt.toZonedDateTime(.{ .timeZone = "UTC" });
const dt_valueof_supported = dt.valueOf() != error.ComparisonNotSupported;
std.log.info(
\\PlainDateTime Coverage
\\ - calInit: {s}
\\ - from string: {s}
\\ - compare(dt, from): {}
\\ - calendarId: {s}
\\ - dayOfWeek/dayOfYear: {}/{}
\\ - daysInWeek/daysInMonth/daysInYear: {}/{}/{}
\\ - monthCode/monthsInYear: {s}/{}
\\ - inLeapYear: {}
\\ - era/eraYear: {any}/{?}
\\ - weekOfYear/yearOfWeek: {?}/{?}
\\ - millisecond/microsecond/nanosecond: {}/{}/{}
\\ - toPlainTime: {s}
\\ - toZonedDateTime: {s}
\\ - toJSON(): {s}
\\ - toLocaleString(): {s}
\\ - valueOf supported: {}
\\
\\
, .{
try dt_cal.toString(allocator, .{}),
try dt_from.toString(allocator, .{}),
Temporal.PlainDateTime.compare(dt, dt_from),
try dt.calendarId(allocator),
dt.dayOfWeek(),
dt.dayOfYear(),
dt.daysInWeek(),
dt.daysInMonth(),
dt.daysInYear(),
try dt.monthCode(allocator),
dt.monthsInYear(),
dt.inLeapYear(),
try dt.era(allocator),
try dt.eraYear(),
try dt.weekOfYear(),
try dt.yearOfWeek(),
dt.millisecond(),
dt.microsecond(),
dt.nanosecond(),
try dt_plain_time.toString(allocator),
try dt_zdt.toString(allocator, .{}),
try dt.toJSON(allocator),
dt.toLocaleString(allocator),
dt_valueof_supported,
});
const md_from = try Temporal.PlainMonthDay.from("02-02");
const md_with = try md.with(.{ .day = 3 });
const md_date = try md.toPlainDate(2024);
const md_valueof_supported = md.valueOf() != error.ValueError;
std.log.info(
\\PlainMonthDay Coverage
\\ - from string: {s}
\\ - equals(from): {}
\\ - calendarId: {s}
\\ - with day=3: {s}
\\ - toPlainDate(2024): {s}
\\ - toJSON(): {s}
\\ - toLocaleString(): {s}
\\ - valueOf supported: {}
\\
\\
, .{
try md_from.toString(allocator),
md.equals(md_from),
try md.calendarId(allocator),
try md_with.toString(allocator),
try md_date.toString(allocator, .{}),
try md.toJSON(allocator),
try md.toLocaleString(allocator),
md_valueof_supported,
});
const tm_from = try Temporal.PlainTime.from("13:45:30.123456789");
const tm_valueof_supported = tm.valueOf() != error.ValueError;
std.log.info(
\\PlainTime Coverage
\\ - from string: {s}
\\ - compare(tm, from): {}
\\ - millisecond/microsecond/nanosecond: {}/{}/{}
\\ - toJSON(): {s}
\\ - toLocaleString(): {s}
\\ - valueOf supported: {}
\\
\\
, .{
try tm_from.toString(allocator),
Temporal.PlainTime.compare(tm, tm_from),
tm.millisecond(),
tm.microsecond(),
tm.nanosecond(),
try tm.toJSON(allocator),
try tm.toLocaleString(allocator),
tm_valueof_supported,
});
const ym_from = try Temporal.PlainYearMonth.from("2024-02");
const ym_date = try ym.toPlainDate(2);
const ym_valueof_supported = ym.valueOf() != error.ValueError;
std.log.info(
\\PlainYearMonth Coverage
\\ - from string: {s}
\\ - compare(ym, from): {}
\\ - calendarId: {s}
\\ - monthCode: {s}
\\ - daysInMonth/daysInYear/monthsInYear: {}/{}/{}
\\ - inLeapYear: {}
\\ - era/eraYear: {any}/{?}
\\ - toPlainDate(2): {s}
\\ - toJSON(): {s}
\\ - toLocaleString(): {s}
\\ - valueOf supported: {}
\\
\\
, .{
try ym_from.toString(allocator),
Temporal.PlainYearMonth.compare(ym, ym_from),
try ym.calendarId(allocator),
try ym.monthCode(allocator),
ym.daysInMonth(),
ym.daysInYear(),
ym.monthsInYear(),
ym.inLeapYear(),
try ym.era(allocator),
ym.eraYear(),
try ym_date.toString(allocator, .{}),
try ym.toJSON(allocator),
try ym.toLocaleString(allocator),
ym_valueof_supported,
});
const zdt_init = try Temporal.ZonedDateTime.init(zdt_epoch_ns, tz);
const zdt_from_ms = try Temporal.ZonedDateTime.fromEpochMilliseconds(1_706_881_530_123, tz);
const zdt_from = try Temporal.ZonedDateTime.from("2024-02-02T13:45:30.123456789+00:00[UTC]", null, .compatible, .reject);
const zdt_transition_next = try zdt.getTimeZoneTransition(.next);
const zdt_transition_previous = try zdt.getTimeZoneTransition(.previous);
const zdt_day_start = try zdt.startOfDay();
const zdt_plain_date = try zdt.toPlainDate();
const zdt_plain_datetime = try zdt.toPlainDateTime();
const zdt_plain_time = try zdt.toPlainTime();
const zdt_valueof_supported = zdt.valueOf() != error.ValueOfNotSupported;
const zdt_with_coverage = try zdt.with(allocator, .{ .year = 2025 });
defer zdt_with_coverage.deinit();
std.log.info(
\\ZonedDateTime Coverage
\\ - init: {s}
\\ - fromEpochMilliseconds: {s}
\\ - from string: {s}
\\ - compare(zdt, from): {}
\\ - next/previous transition exists: {}/{}
\\ - startOfDay: {s}
\\ - toJSON(): {s}
\\ - toLocaleString(): {s}
\\ - toPlainDate: {s}
\\ - toPlainDateTime: {s}
\\ - toPlainTime: {s}
\\ - calendarId: {s}
\\ - dayOfWeek/dayOfYear: {}/{}
\\ - daysInWeek/daysInMonth/daysInYear: {}/{}/{}
\\ - epochMilliseconds/epochNanoseconds: {}/{}
\\
, .{
try zdt_init.toString(allocator, .{}),
try zdt_from_ms.toString(allocator, .{}),
try zdt_from.toString(allocator, .{}),
Temporal.ZonedDateTime.compare(zdt, zdt_from),
zdt_transition_next != null,
zdt_transition_previous != null,
try zdt_day_start.toString(allocator, .{}),
try zdt.toJSON(allocator),
try zdt.toLocaleString(allocator),
try zdt_plain_date.toString(allocator, .{}),
try zdt_plain_datetime.toString(allocator, .{}),
try zdt_plain_time.toString(allocator),
try zdt.calendarId(allocator),
zdt.dayOfWeek(),
zdt.dayOfYear(),
zdt.daysInWeek(),
zdt.daysInMonth(),
zdt.daysInYear(),
zdt.epochMilliseconds(),
zdt.epochNanoseconds(),
});
std.log.info(
\\ZonedDateTime Coverage Continued
\\ - era/eraYear: {any}/{?}
\\ - hoursInDay/inLeapYear: {d}/{}
\\ - millisecond/microsecond/nanosecond: {}/{}/{}
\\ - monthCode/monthsInYear: {s}/{}
\\ - offset/offsetNanoseconds: {s}/{}
\\ - weekOfYear/yearOfWeek: {?}/{?}
\\ - valueOf supported: {}
\\ - with year=2025: {s}
\\
\\
, .{
try zdt.era(allocator),
zdt.eraYear(),
try zdt.hoursInDay(),
zdt.inLeapYear(),
zdt.millisecond(),
zdt.microsecond(),
zdt.nanosecond(),
try zdt.monthCode(allocator),
zdt.monthsInYear(),
try zdt.offset(allocator),
zdt.offsetNanoseconds(),
zdt.weekOfYear(),
zdt.yearOfWeek(),
zdt_valueof_supported,
try zdt_with_coverage.toString(allocator, .{}),
});
}
pub fn runTimeZoneExamples(
allocator: std.mem.Allocator,
io_optional: ?std.Io,
now_epoch_ms: ?i64,
) !void {
const epoch_ns: i128 = if (now_epoch_ms) |ms| @as(i128, ms) * 1_000_000 else 1_706_881_530_123_456_789;
const utc_tz = try Temporal.ZonedDateTime.TimeZone.init("UTC");
const ny_tz = try Temporal.ZonedDateTime.TimeZone.init("America/New_York");
const dhaka_tz = try Temporal.ZonedDateTime.TimeZone.init("Asia/Dhaka");
const zdt_utc = try Temporal.ZonedDateTime.fromEpochNanoseconds(epoch_ns, utc_tz);
defer zdt_utc.deinit();
const zdt_ny = try zdt_utc.withTimeZone(ny_tz);
defer zdt_ny.deinit();
const zdt_dhaka = try zdt_utc.withTimeZone(dhaka_tz);
defer zdt_dhaka.deinit();
const utc_id = try zdt_utc.timeZoneId(allocator);
defer allocator.free(utc_id);
const ny_id = try zdt_ny.timeZoneId(allocator);
defer allocator.free(ny_id);
const dhaka_id = try zdt_dhaka.timeZoneId(allocator);
defer allocator.free(dhaka_id);
std.log.info(
\\TimeZone
\\ - same instant in UTC ({s}): {s}
\\ - same instant in New York ({s}): {s}
\\ - same instant in Dhaka ({s}): {s}
\\ - UTC offset: {s}
\\ - New York offset: {s}
\\ - Dhaka offset: {s}
\\
\\
, .{
utc_id,
try zdt_utc.toString(allocator, .{}),
ny_id,
try zdt_ny.toString(allocator, .{}),
dhaka_id,
try zdt_dhaka.toString(allocator, .{}),
try zdt_utc.offset(allocator),
try zdt_ny.offset(allocator),
try zdt_dhaka.offset(allocator),
});
if (io_optional) |io| {
const system_tz_id = try Temporal.Now.timeZoneId(allocator, io);
defer allocator.free(system_tz_id);
const now_zdt = try Temporal.Now.zonedDateTimeISO(allocator, io, null);
defer now_zdt.deinit();
const now_zdt_utc = try Temporal.Now.zonedDateTimeISO(allocator, io, "UTC");
defer now_zdt_utc.deinit();
const now_date = try Temporal.Now.plainDateISO(allocator, io, null);
defer now_date.deinit();
std.log.info(
\\TimeZone (system)
\\ - system timeZoneId(): {s}
\\ - Now.zonedDateTimeISO(): {s}
\\ - Now.zonedDateTimeISO("UTC"): {s}
\\ - Now.plainDateISO(): {s}
\\
\\
, .{
system_tz_id,
try now_zdt.toString(allocator, .{}),
try now_zdt_utc.toString(allocator, .{}),
try now_date.toString(allocator, .{}),
});
} else if (now_epoch_ms) |ms| {
const inst = try Temporal.Instant.fromEpochMilliseconds(ms);
defer inst.deinit();
const inst_dhaka_tz = try Temporal.Instant.TimeZone.init("Asia/Dhaka");
const inst_utc_tz = try Temporal.Instant.TimeZone.init("UTC");
const host_zdt = try inst.toZonedDateTimeISO(inst_dhaka_tz);
defer host_zdt.deinit();
const host_zdt_utc = try inst.toZonedDateTimeISO(inst_utc_tz);
defer host_zdt_utc.deinit();
std.log.info(
\\TimeZone (host epoch)
\\ - Instant.toZonedDateTimeISO("Asia/Dhaka"): {s}
\\ - Instant.toZonedDateTimeISO("UTC"): {s}
\\
\\
, .{
try host_zdt.toString(allocator, .{}),
try host_zdt_utc.toString(allocator, .{}),
});
}
}

@ -0,0 +1 @@
Subproject commit 80286aa081b04bb9c9881615af62ae0d47912791

683
test/test262/polyfill.js Normal file
View file

@ -0,0 +1,683 @@
// This polyfill is executed in a vm.Script context by test262-runner,
// so it must be synchronous and self-contained.
// The wasm bytes are injected as global.__TEMPORALZ_WASM_BYTES__ by the runner.
(function () {
if (!globalThis.__TEMPORALZ_WASM_BYTES__) {
throw new Error("WASM bytes not injected into test context");
}
const wasmBinary = globalThis.__TEMPORALZ_WASM_BYTES__;
const wasmModule = new WebAssembly.Module(wasmBinary);
const wasmInstance = new WebAssembly.Instance(wasmModule, {
env: {
console(ptr, len) {
const bytes = new Uint8Array(memory.buffer, ptr, len);
globalThis.console.log(decoder.decode(bytes));
},
},
});
const exports = wasmInstance.exports;
const memory = exports.memory;
const encoder = {
encode(str) {
const buf = [];
for (let i = 0; i < str.length; i++) {
const code = str.charCodeAt(i);
if (code < 0x80) {
buf.push(code);
} else if (code < 0x800) {
buf.push(0xc0 | (code >> 6), 0x80 | (code & 0x3f));
} else if (code < 0xd800 || code >= 0xe000) {
buf.push(0xe0 | (code >> 12), 0x80 | ((code >> 6) & 0x3f), 0x80 | (code & 0x3f));
} else {
const code2 = str.charCodeAt(++i);
const codePoint = 0x10000 + (((code & 0x3ff) << 10) | (code2 & 0x3ff));
buf.push(
0xf0 | (codePoint >> 18),
0x80 | ((codePoint >> 12) & 0x3f),
0x80 | ((codePoint >> 6) & 0x3f),
0x80 | (codePoint & 0x3f)
);
}
}
return new Uint8Array(buf);
},
};
const decoder = {
decode(bytes) {
let str = "";
for (let i = 0; i < bytes.length; i++) {
const byte = bytes[i];
if (byte < 0x80) {
str += String.fromCharCode(byte);
} else if ((byte & 0xe0) === 0xc0) {
str += String.fromCharCode(((byte & 0x1f) << 6) | (bytes[++i] & 0x3f));
} else if ((byte & 0xf0) === 0xe0) {
str += String.fromCharCode(
((byte & 0x0f) << 12) | ((bytes[++i] & 0x3f) << 6) | (bytes[++i] & 0x3f)
);
} else if ((byte & 0xf8) === 0xf0) {
const codePoint =
((byte & 0x07) << 18) |
((bytes[++i] & 0x3f) << 12) |
((bytes[++i] & 0x3f) << 6) |
(bytes[++i] & 0x3f);
const high = ((codePoint - 0x10000) >> 10) + 0xd800;
const low = ((codePoint - 0x10000) & 0x3ff) + 0xdc00;
str += String.fromCharCode(high, low);
}
}
return str;
},
};
function readString(ptr, len) {
return decoder.decode(new Uint8Array(memory.buffer, ptr, len));
}
function lastError() {
const ptr = exports.temporalz_last_error_ptr();
const len = exports.temporalz_last_error_len();
if (!ptr || !len) return new Error("temporalz error");
const msg = readString(ptr, len);
exports.temporalz_last_error_clear();
if (msg.includes("Range")) return new RangeError(msg);
if (msg.includes("Type")) return new TypeError(msg);
return new Error(msg);
}
function requireHandle(handle) {
if (!handle) throw lastError();
return handle;
}
function allocString(text) {
const bytes = encoder.encode(text);
const ptr = exports.temporalz_alloc(bytes.length);
if (!ptr) throw lastError();
new Uint8Array(memory.buffer, ptr, bytes.length).set(bytes);
return { ptr, len: bytes.length };
}
function takeString(packed) {
if (!packed) throw lastError();
const value = BigInt(packed);
const ptr = Number(value >> 32n);
const len = Number(value & 0xffffffffn);
const text = readString(ptr, len);
exports.temporalz_string_free(ptr, len);
return text;
}
function splitI128(value) {
const v = typeof value === "bigint" ? value : BigInt(value);
const mask = (1n << 64n) - 1n;
return { hi: v >> 64n, lo: v & mask };
}
function joinI128(hi, lo) {
const mask = (1n << 64n) - 1n;
return (BigInt(hi) << 64n) | (BigInt(lo) & mask);
}
const unitCodes = {
nanosecond: 1,
microsecond: 2,
millisecond: 3,
second: 4,
minute: 5,
hour: 6,
day: 7,
week: 8,
month: 9,
year: 10,
auto: 11,
};
const roundingModeCodes = {
ceil: 1,
floor: 2,
expand: 3,
trunc: 4,
halfCeil: 5,
halfFloor: 6,
halfExpand: 7,
halfTrunc: 8,
halfEven: 9,
};
function toUnitCode(value, name) {
if (value === undefined || value === null) return 255;
const code = unitCodes[value];
if (!code) throw new RangeError(`Invalid ${name}`);
return code;
}
function toRoundingModeCode(value) {
if (value === undefined || value === null) return 255;
const code = roundingModeCodes[value];
if (!code) throw new RangeError("Invalid roundingMode");
return code;
}
function toIntegerBigInt(value, name) {
if (typeof value === "bigint") return value;
const number = Number(value);
if (!isFiniteNumber(number)) throw new RangeError(`${name} must be finite`);
if (!Number.isInteger(number)) throw new RangeError(`${name} must be an integer`);
return BigInt(number);
}
function toNumber(value, name) {
const number = Number(value);
if (!isFiniteNumber(number)) throw new RangeError(`${name} must be finite`);
return number;
}
function toInteger(value, name) {
const number = Number(value);
if (!isFiniteNumber(number)) throw new RangeError(`${name} must be finite`);
if (!Number.isInteger(number)) throw new RangeError(`${name} must be an integer`);
return number;
}
function isFiniteNumber(value) {
return value === value && value !== Infinity && value !== -Infinity;
}
function unimplemented(name) {
return function () {
throw new Error(`${name} is not implemented yet`);
};
}
class Instant {
constructor(handle) {
this._handle = handle;
}
static _fromHandle(handle) {
return new Instant(handle);
}
static fromEpochMilliseconds(epochMs) {
const number = Number(epochMs);
if (!isFiniteNumber(number)) throw new RangeError("epochMilliseconds must be finite");
const handle = exports.temporalz_instant_from_epoch_milliseconds(number);
return Instant._fromHandle(requireHandle(handle));
}
static fromEpochNanoseconds(epochNs) {
const parts = splitI128(epochNs);
const handle = exports.temporalz_instant_from_epoch_nanoseconds_parts(
parts.hi,
parts.lo
);
return Instant._fromHandle(requireHandle(handle));
}
static from(value) {
if (value instanceof Instant) return value;
if (typeof value === "string") {
const text = allocString(value);
const handle = exports.temporalz_instant_from_utf8(text.ptr, text.len);
exports.temporalz_free(text.ptr, text.len);
return Instant._fromHandle(requireHandle(handle));
}
if (value && typeof value === "object") {
if (value.epochNanoseconds !== undefined) {
return Instant.fromEpochNanoseconds(value.epochNanoseconds);
}
if (value.epochMilliseconds !== undefined) {
return Instant.fromEpochMilliseconds(value.epochMilliseconds);
}
}
throw new TypeError("Instant.from expects a string or object");
}
get epochMilliseconds() {
return exports.temporalz_instant_epoch_milliseconds(this._handle);
}
get epochNanoseconds() {
const hi = exports.temporalz_instant_epoch_nanoseconds_hi(this._handle);
const lo = exports.temporalz_instant_epoch_nanoseconds_lo(this._handle);
return joinI128(hi, lo);
}
toString() {
return takeString(exports.temporalz_instant_to_string(this._handle));
}
toJSON() {
return this.toString();
}
add(durationLike) {
const dur = Duration.from(durationLike);
const handle = exports.temporalz_instant_add(this._handle, dur._handle);
return Instant._fromHandle(requireHandle(handle));
}
subtract(durationLike) {
const dur = Duration.from(durationLike);
const handle = exports.temporalz_instant_subtract(this._handle, dur._handle);
return Instant._fromHandle(requireHandle(handle));
}
round(options) {
if (!options || typeof options !== "object") {
throw new TypeError("round options must be an object");
}
const smallestUnit = toUnitCode(options.smallestUnit, "smallestUnit");
if (smallestUnit === 255) throw new RangeError("smallestUnit is required");
const roundingMode = toRoundingModeCode(options.roundingMode);
let roundingIncrement = 0;
if (options.roundingIncrement !== undefined) {
const inc = Number(options.roundingIncrement);
if (!isFiniteNumber(inc) || !Number.isInteger(inc) || inc <= 0) {
throw new RangeError("Invalid roundingIncrement");
}
roundingIncrement = inc;
}
const handle = exports.temporalz_instant_round(
this._handle,
smallestUnit,
roundingMode,
roundingIncrement
);
return Instant._fromHandle(requireHandle(handle));
}
equals(other) {
const rhs = Instant.from(other);
return exports.temporalz_instant_equals(this._handle, rhs._handle) === 1;
}
toLocaleString() {
return this.toString();
}
valueOf() {
throw new TypeError("Cannot convert Temporal.Instant to a number");
}
static compare(a, b) {
const left = Instant.from(a);
const right = Instant.from(b);
return Number(exports.temporalz_instant_compare(left._handle, right._handle));
}
}
const plainDateHandleToken = Symbol("PlainDateHandle");
class PlainDate {
constructor(year, month, day) {
if (year === plainDateHandleToken) {
this._handle = month;
return;
}
const yearValue = toInteger(year ?? 0, "year");
const monthValue = toInteger(month ?? 0, "month");
const dayValue = toInteger(day ?? 0, "day");
const handle = exports.temporalz_plain_date_init(yearValue, monthValue, dayValue);
this._handle = requireHandle(handle);
}
static _fromHandle(handle) {
return new PlainDate(plainDateHandleToken, handle);
}
static from(value) {
if (value instanceof PlainDate) return value;
if (typeof value === "string") {
const text = allocString(value);
const handle = exports.temporalz_plain_date_from_utf8(text.ptr, text.len);
exports.temporalz_free(text.ptr, text.len);
return PlainDate._fromHandle(requireHandle(handle));
}
if (value === null || typeof value !== "object") {
throw new TypeError("PlainDate.from expects a string or object");
}
const year = toInteger(value.year, "year");
const month = toInteger(value.month, "month");
const day = toInteger(value.day, "day");
const handle = exports.temporalz_plain_date_init(year, month, day);
return PlainDate._fromHandle(requireHandle(handle));
}
toString() {
return takeString(exports.temporalz_plain_date_to_string(this._handle));
}
}
const durationHandleToken = Symbol("DurationHandle");
class Duration {
constructor(
years,
months,
weeks,
days,
hours,
minutes,
seconds,
milliseconds,
microseconds,
nanoseconds
) {
if (years === durationHandleToken) {
this._handle = months;
return;
}
const yearsValue = toIntegerBigInt(years ?? 0, "years");
const monthsValue = toIntegerBigInt(months ?? 0, "months");
const weeksValue = toIntegerBigInt(weeks ?? 0, "weeks");
const daysValue = toIntegerBigInt(days ?? 0, "days");
const hoursValue = toIntegerBigInt(hours ?? 0, "hours");
const minutesValue = toIntegerBigInt(minutes ?? 0, "minutes");
const secondsValue = toIntegerBigInt(seconds ?? 0, "seconds");
const millisecondsValue = toIntegerBigInt(milliseconds ?? 0, "milliseconds");
const microsecondsValue = toNumber(microseconds ?? 0, "microseconds");
const nanosecondsValue = toNumber(nanoseconds ?? 0, "nanoseconds");
const created = exports.temporalz_duration_init(
yearsValue,
monthsValue,
weeksValue,
daysValue,
hoursValue,
minutesValue,
secondsValue,
millisecondsValue,
microsecondsValue,
nanosecondsValue
);
this._handle = requireHandle(created);
}
static _fromHandle(handle) {
return new Duration(durationHandleToken, handle);
}
static from(value) {
if (value instanceof Duration) return value;
if (typeof value === "string") {
const text = allocString(value);
const handle = exports.temporalz_duration_from_utf8(text.ptr, text.len);
exports.temporalz_free(text.ptr, text.len);
return Duration._fromHandle(requireHandle(handle));
}
if (value === null || typeof value !== "object") {
throw new TypeError("Duration.from expects a string or object");
}
const fields = [
"years",
"months",
"weeks",
"days",
"hours",
"minutes",
"seconds",
"milliseconds",
"microseconds",
"nanoseconds",
];
let mask = 0;
const values = [0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0, 0];
fields.forEach((field, index) => {
if (value[field] !== undefined) {
mask |= 1 << index;
if (field === "microseconds" || field === "nanoseconds") {
values[index] = toNumber(value[field], field);
} else {
values[index] = toIntegerBigInt(value[field], field);
}
}
});
const handle = exports.temporalz_duration_from_parts(
mask,
values[0],
values[1],
values[2],
values[3],
values[4],
values[5],
values[6],
values[7],
values[8],
values[9]
);
return Duration._fromHandle(requireHandle(handle));
}
static compare(a, b, options) {
const left = Duration.from(a);
const right = Duration.from(b);
return Duration.compareWithOptions(left, right, options);
}
static compareWithOptions(left, right, options) {
if (options !== undefined && (options === null || typeof options !== "object")) {
throw new TypeError("options must be an object");
}
const relativeTo = toRelativeTo(options);
if (!relativeTo && (hasYearMonthWeek(left) || hasYearMonthWeek(right))) {
throw new RangeError("relativeTo is required for calendar units");
}
if (relativeTo) {
return Number(
exports.temporalz_duration_compare_plain_date(
left._handle,
right._handle,
relativeTo._handle
)
);
}
return Number(exports.temporalz_duration_compare(left._handle, right._handle));
}
add(other) {
const rhs = Duration.from(other);
const handle = exports.temporalz_duration_add(this._handle, rhs._handle);
return Duration._fromHandle(requireHandle(handle));
}
subtract(other) {
const rhs = Duration.from(other);
const handle = exports.temporalz_duration_subtract(this._handle, rhs._handle);
return Duration._fromHandle(requireHandle(handle));
}
abs() {
const handle = exports.temporalz_duration_abs(this._handle);
return Duration._fromHandle(requireHandle(handle));
}
negated() {
const handle = exports.temporalz_duration_negated(this._handle);
return Duration._fromHandle(requireHandle(handle));
}
round(options = {}) {
if (options === undefined) options = {};
if (options === null || typeof options !== "object") {
throw new TypeError("round options must be an object");
}
const relativeTo = toRelativeTo(options);
if (!relativeTo && hasCalendarUnits(this)) {
throw new RangeError("relativeTo is required for calendar units");
}
const smallestUnit = toUnitCode(options.smallestUnit, "smallestUnit");
const largestUnit = toUnitCode(options.largestUnit, "largestUnit");
const roundingMode = toRoundingModeCode(options.roundingMode);
let roundingIncrement = 0;
if (options.roundingIncrement !== undefined) {
const inc = Number(options.roundingIncrement);
if (!Number.isFinite(inc) || !Number.isInteger(inc) || inc <= 0) {
throw new RangeError("Invalid roundingIncrement");
}
roundingIncrement = inc;
}
const handle = relativeTo
? exports.temporalz_duration_round_plain_date(
this._handle,
smallestUnit,
largestUnit,
roundingMode,
roundingIncrement,
relativeTo._handle
)
: exports.temporalz_duration_round(
this._handle,
smallestUnit,
largestUnit,
roundingMode,
roundingIncrement
);
return Duration._fromHandle(requireHandle(handle));
}
total(options) {
if (!options || typeof options !== "object") {
throw new TypeError("total options must be an object");
}
const relativeTo = toRelativeTo(options);
if (!relativeTo && hasCalendarUnits(this)) {
throw new RangeError("relativeTo is required for calendar units");
}
const unit = toUnitCode(options.unit, "unit");
if (unit === 255) throw new RangeError("Invalid unit");
const result = relativeTo
? exports.temporalz_duration_total_plain_date(
this._handle,
unit,
relativeTo._handle
)
: exports.temporalz_duration_total(this._handle, unit);
if (!Number.isFinite(result)) throw lastError();
return result;
}
get sign() {
return Number(exports.temporalz_duration_sign(this._handle));
}
get blank() {
return exports.temporalz_duration_blank(this._handle) === 1;
}
toString() {
return takeString(exports.temporalz_duration_to_string(this._handle));
}
toJSON() {
return this.toString();
}
toLocaleString() {
return this.toString();
}
valueOf() {
throw new TypeError("Cannot convert Temporal.Duration to a number");
}
get years() {
return Number(exports.temporalz_duration_years(this._handle));
}
get months() {
return Number(exports.temporalz_duration_months(this._handle));
}
get weeks() {
return Number(exports.temporalz_duration_weeks(this._handle));
}
get days() {
return Number(exports.temporalz_duration_days(this._handle));
}
get hours() {
return Number(exports.temporalz_duration_hours(this._handle));
}
get minutes() {
return Number(exports.temporalz_duration_minutes(this._handle));
}
get seconds() {
return Number(exports.temporalz_duration_seconds(this._handle));
}
get milliseconds() {
return Number(exports.temporalz_duration_milliseconds(this._handle));
}
get microseconds() {
return Number(exports.temporalz_duration_microseconds(this._handle));
}
get nanoseconds() {
return Number(exports.temporalz_duration_nanoseconds(this._handle));
}
}
function hasCalendarUnits(duration) {
return (
duration.years !== 0 ||
duration.months !== 0 ||
duration.weeks !== 0 ||
duration.days !== 0
);
}
function hasYearMonthWeek(duration) {
return duration.years !== 0 || duration.months !== 0 || duration.weeks !== 0;
}
function toRelativeTo(options) {
if (!options || options.relativeTo === undefined) return null;
const rel = options.relativeTo;
if (rel instanceof PlainDate) return rel;
if (typeof rel === "string") return PlainDate.from(rel);
if (rel && typeof rel === "object") return PlainDate.from(rel);
throw new TypeError("Invalid relativeTo");
}
const Temporal = {
Instant,
Duration,
Now: {
instant: unimplemented("Temporal.Now.instant"),
plainDateISO: unimplemented("Temporal.Now.plainDateISO"),
plainDateTimeISO: unimplemented("Temporal.Now.plainDateTimeISO"),
plainTimeISO: unimplemented("Temporal.Now.plainTimeISO"),
timeZoneId: unimplemented("Temporal.Now.timeZoneId"),
zonedDateTimeISO: unimplemented("Temporal.Now.zonedDateTimeISO"),
},
PlainDate,
PlainTime: unimplemented("Temporal.PlainTime"),
PlainDateTime: unimplemented("Temporal.PlainDateTime"),
PlainYearMonth: unimplemented("Temporal.PlainYearMonth"),
PlainMonthDay: unimplemented("Temporal.PlainMonthDay"),
ZonedDateTime: unimplemented("Temporal.ZonedDateTime"),
};
globalThis.Temporal = Temporal;
})();

35
test/test262/runner.mjs Normal file
View file

@ -0,0 +1,35 @@
import runTest262 from "../temporal-test262-runner/index.mjs";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const wasmPath =
process.env.TEMPORALZ_WASM ||
path.resolve(__dirname, "../../zig-out/bin/temporalz.wasm");
const wasmBytes = fs.readFileSync(wasmPath);
const polyfillPath = path.resolve(__dirname, "../test262/polyfill.js");
let polyfillCode = fs.readFileSync(polyfillPath, "utf-8");
const bytesArray = JSON.stringify(Array.from(wasmBytes));
// TextEncoder/TextDecoder need to be manually constructed and passed via context
// Since we can't serialize them, we inject polyfill-compatible shim versions
const injection = `globalThis.__TEMPORALZ_WASM_BYTES__ = new Uint8Array(${bytesArray});
`;
polyfillCode = injection + polyfillCode;
const tempPolyfillPath = path.resolve(__dirname, "../test262/polyfill-injected.js");
fs.writeFileSync(tempPolyfillPath, polyfillCode);
const result = runTest262({
test262Dir: "test/temporal-test262-runner/test262",
polyfillCodeFile: tempPolyfillPath,
testGlobs: process.argv.slice(2),
});
fs.unlinkSync(tempPolyfillPath);
process.exit(result ? 0 : 1);