Compare commits

..

35 commits
v0.2.3 ... main

Author SHA1 Message Date
Nurul Huda (Apon)
06ce040347
refactor: cleanup to have single entrypoints 2026-07-16 15:01:12 +06:00
Nurul Huda (Apon)
126777caea
chore: remove test262 link from readme 2026-07-16 12:51:57 +06:00
Nurul Huda (Apon)
b4b0aac7da
fix: missed linking libc 2026-07-16 07:07:12 +06:00
Nurul Huda (Apon)
5b3cacdb3b
fix: link libc in test 2026-07-16 07:01:19 +06:00
Nurul Huda (Apon)
e63cc5ba5a
ci: add more deps paths 2026-07-16 06:55:24 +06:00
Nurul Huda (Apon)
599dd9e224
fix: make build-rust false by default 2026-07-16 06:54:24 +06:00
Nurul Huda (Apon)
133b2be3fc
refactor: mv example to test 2026-07-16 06:46:07 +06:00
Nurul Huda (Apon)
37c8ac5b2e
chore: sync version 2026-07-16 06:18:36 +06:00
Nurul Huda (Apon)
25282ad6af
ci: run example from example dir 2026-07-16 04:55:59 +06:00
Nurul Huda (Apon)
40b6332499
ci: rm exe verification 2026-07-16 04:52:01 +06:00
Nurul Huda (Apon)
aab32053ae
ci: update paths 2026-07-16 04:49:13 +06:00
Nurul Huda (Apon)
f58d2efda7
ci: rm upload and download of artifacts 2026-07-16 04:47:52 +06:00
Nurul Huda (Apon)
19525f12a1
ci: rm build requirment for running test 2026-07-16 04:42:34 +06:00
Nurul Huda (Apon)
65cfa18d63
refactor: use isolated package per targets 2026-07-16 04:33:16 +06:00
Nurul Huda (Apon)
cfb111fb74
ci: rm failing target 2026-07-16 03:44:18 +06:00
Nurul Huda (Apon)
0775cd6b2f
ci: proper target mapping 2026-07-16 03:37:02 +06:00
Nurul Huda (Apon)
04c46bf624
ci: add more release targets 2026-07-16 03:24:17 +06:00
Nurul Huda (Apon)
7273dda302
ci: do not pass target to build.crab to crosscompile 2026-07-16 03:15:41 +06:00
Nurul Huda (Apon)
377f0afb2a
chore: add splitted targets 2026-07-16 02:49:20 +06:00
Nurul Huda (Apon)
d844d2a5fc
refactor: rename lib and restructure pkg/ 2026-07-16 02:27:13 +06:00
Nurul Huda (Apon)
b0064649dc
test: rm test262 test setup 2026-07-16 02:09:44 +06:00
Nurul Huda (Apon)
de05d1303d
fix: plain-time and now fix on linux 2026-07-16 01:36:14 +06:00
Nurul Huda (Apon)
6d5dca2ffd
feat: add local timezone 2026-07-16 00:26:17 +06:00
Nurul Huda (Apon)
ac36792fdc
chore: gitignore tool-versions file 2026-07-15 17:27:26 +06:00
Nurul Huda (Apon)
b45e6adddd
chore: update zig version and doccomments 2026-07-15 17:23:58 +06:00
Nurul Huda (Apon)
076e030bca
chore: modify test262 submod 2026-06-18 17:57:39 +06:00
Nurul Huda (Apon)
66a9527c38
ci(docs): update zig version 2026-06-12 15:40:38 +06:00
Nurul Huda (Apon)
6b27752cfe
ci: add docs deploy to gh pages 2026-06-12 15:37:07 +06:00
Nurul Huda (Apon)
b03d42e72d
chore: add todo for timezone() 2026-06-08 13:31:57 +06:00
Nurul Huda (Apon)
a4c2e4cd7a
chore: update zig version 2026-06-04 16:34:09 +06:00
Nurul Huda (Apon)
eeac7a08b6
chore: changes for lang.Type 2026-06-04 16:31:44 +06:00
Nurul Huda (Apon)
2cb7b2709d
fix: wasi run step 2026-06-02 17:15:07 +06:00
Nurul Huda (Apon)
df3b636f35
fix: issue with using prebuilt libs 2026-06-01 15:14:00 +06:00
Nurul Huda (Apon)
e12c5ac8f3
refactor: zig 0.17.0 update and test coverage 2026-06-01 14:49:14 +06:00
Nurul Huda (Apon)
ae1fb8a2fb
fix: rm std.os usage 2026-05-27 16:38:39 +06:00
52 changed files with 1281 additions and 2544 deletions

View file

@ -3,7 +3,7 @@ name: Release
on:
push:
tags:
- 'v*'
- "v*"
workflow_dispatch:
permissions:
@ -17,78 +17,180 @@ 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.387+31f157d80
version: 0.17.0-dev.1398+cb5635714
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.rust-target }}
- name: Install cross-compilers (Linux-aarch64)
if: contains(matrix.target, 'aarch64-linux')
- name: Install cross-compilers
if: matrix.cross-packages != ''
run: |
sudo apt-get update
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
sudo apt-get install -y ${{ matrix.cross-packages }}
- name: Build Package
run: |
cd pkg/temporal
if [ -n "${{ matrix.cargo-linker-env }}" ]; then
export "${{ matrix.cargo-linker-env }}=${{ matrix.cargo-linker }}"
fi
cd lib
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: lib-${{ matrix.target }}
path: pkg/temporal/zig-out/lib/
name: ${{ matrix.target }}
path: lib/dist/${{ matrix.target }}.tar.gz
retention-days: 1
release:
@ -97,30 +199,18 @@ jobs:
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Checkout code
uses: actions/checkout@v4
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: all-libs
pattern: lib-*
path: dist
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: |
libtemporal.tar.gz
libtemporal.zip
files: dist/*.tar.gz
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -2,9 +2,17 @@ name: CI
on:
push:
branches: [ main ]
branches: [main]
paths:
- 'src/**'
- 'lib/**'
- 'test/**'
- 'build.zig'
- 'build.zig.zon'
- '.github/workflows/ci.yml'
pull_request:
branches: [ main ]
branches: [main]
jobs:
build:
@ -13,7 +21,6 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
# os: [ubuntu-latest, macos-latest]
steps:
- name: Checkout code
@ -22,31 +29,17 @@ jobs:
- name: Setup Zig
uses: mlugg/setup-zig@v2
with:
version: 0.17.0-dev.387+31f157d80
version: 0.17.0-dev.1398+cb5635714
- 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
- name: Build and run project
run: cd test && zig build run
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
@ -55,17 +48,7 @@ jobs:
- name: Setup Zig
uses: mlugg/setup-zig@v2
with:
version: 0.17.0-dev.387+31f157d80
- 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
version: 0.17.0-dev.1398+cb5635714
- name: Run tests
run: zig build test

55
.github/workflows/docs.yml vendored Normal file
View file

@ -0,0 +1,55 @@
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

6
.gitignore vendored
View file

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

3
.gitmodules vendored
View file

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

View file

@ -1 +0,0 @@
zig master

View file

@ -6,12 +6,11 @@ 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.387+31f157d80
- Zig 0.17.0-dev.1398+cb5635714
- Rust toolchain (only required if [prebuilt staticlibs](#prebuilt) are not available for your platform)
#### Add as a Dependency
@ -35,36 +34,31 @@ const exe = b.addExecutable(.{...});
exe.root_module.addImport("temporalz", temporalz.module("temporalz"));
```
## Checklist
## 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 |
| Namespace | Status |
| -------------- | ------ |
| Instant | ✅ |
| Duration | ✅ |
| PlainDate | ✅ |
| PlainTime | ✅ |
| PlainDateTime | ✅ |
| PlainYearMonth | ✅ |
| PlainMonthDay | ✅ |
| ZonedDateTime | ✅ |
## Prebuilt
Prebuilt libraries are included for the following platforms:
- `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`
- `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`
For other platforms, the library will build from source; you need the Rust toolchain installed.
@ -81,6 +75,12 @@ cd temporalz
```bash
zig build run
# Node.js
zig build run -Dtarget=wasm32-freestanding
# wasmtime
zig build run -Dtarget=wasm32-wasi
```
#### Run Tests
@ -88,8 +88,3 @@ zig build run
```bash
zig build test
```
## License
MIT

298
SPEC.md
View file

@ -1,298 +0,0 @@
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,58 +3,38 @@ 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 force_build_rust = b.option(bool, "build-rust", "Always build Rust library from source") orelse false;
// --- Rust C ABI & Pre-built via temporal-rs subpackage --- //
const temporal = b.dependency("temporal", .{
const build_rust = b.option(bool, "build-rust", "Build Rust library from source") orelse false;
const libtemporal = b.dependency("libtemporal", .{
.target = target,
.optimize = optimize,
.@"build-rust" = force_build_rust,
.@"build-rust" = build_rust,
});
// --- Zig Module: temporalz --- //
// --- Module: temporalz --- //
const mod = b.addModule("temporalz", .{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
mod.addImport("temporal_rs", temporal.module("temporal_rs"));
mod.addImport("libtemporal", libtemporal.module("libtemporal"));
// --- Zig Executable: temporalz --- //
const exe = b.addExecutable(.{
.name = "temporalz",
.root_module = b.createModule(.{
.root_source_file = if (is_freestanding)
b.path("example/src/wasm.zig")
else
b.path("example/src/main.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "temporalz", .module = mod },
},
}),
});
exe.root_module.link_libc = !is_freestanding;
exe.rdynamic = is_freestanding;
b.installArtifact(exe);
// --- Steps: Run --- //
// --- Step: run --- //
{
const run_step = b.step("run", "Run the example project");
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)}),
});
run_cmd.setCwd(b.path("example"));
if (b.args) |args| run_cmd.addArgs(args);
run_cmd.setCwd(b.path("test"));
run_cmd.addPassthruArgs();
run_step.dependOn(&run_cmd.step);
}
// --- Steps: Docs --- //
// --- Step: docs --- //
{
const docs_step = b.step("docs", "Build the temporalz docs");
const docs_obj = b.addObject(.{ .name = "temporalz", .root_module = mod });
@ -67,7 +47,7 @@ pub fn build(b: *std.Build) !void {
}).step);
}
// --- Steps: Test --- //
// --- Step: test --- //
{
const test_step = b.step("test", "Run tests");
const mod_tests = b.addTest(.{
@ -77,20 +57,7 @@ pub fn build(b: *std.Build) !void {
.mode = .simple,
},
});
mod_tests.root_module.link_libc = !is_freestanding;
mod_tests.root_module.link_libc = target.result.os.tag != .freestanding;
test_step.dependOn(&b.addRunArtifact(mod_tests).step);
if (!is_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.0",
.version = "0.2.4",
.fingerprint = 0xd8d79d59acc4faae,
.minimum_zig_version = "0.17.0-dev.387+31f157d80",
.minimum_zig_version = "0.17.0-dev.1398+cb5635714",
.dependencies = .{
.temporal = .{
.path = "pkg/temporal",
.libtemporal = .{
.path = "lib",
},
},
.paths = .{
@ -14,6 +14,6 @@
"README.md",
"LICENCE",
"src",
"pkg",
"lib",
},
}

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,9 +0,0 @@
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);
}

View file

@ -1,842 +0,0 @@
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 };

144
lib/build.zig Normal file
View file

@ -0,0 +1,144 @@
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;
}
}

127
lib/build.zig.zon Normal file
View file

@ -0,0 +1,127 @@
.{
.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",
},
}

57
lib/targets.zig Normal file
View file

@ -0,0 +1,57 @@
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) });
}

26
lib/targets.zon Normal file
View file

@ -0,0 +1,26 @@
.{
.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

@ -1,94 +0,0 @@
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,
});
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());
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

@ -1,26 +0,0 @@
.{
.name = .temporal,
.version = "0.2.0",
.fingerprint = 0xd5dcf3f41df6b117,
.minimum_zig_version = "0.17.0-dev.387+31f157d80",
.dependencies = .{
.temporal_rs = .{
.url = "git+https://github.com/boa-dev/temporal?ref=v0.2.3#c003cc92325e19b26f8ee2f85e4a47d98cbcc781",
.hash = "N-V-__8AAPLKOQDfJ5TYhiiy_6a_dZqUmo9K4e8Xhjfup3fd",
},
.libtemporal = .{
.url = "https://github.com/nurulhudaapon/temporalz/releases/download/v0.2.3/libtemporal.tar.gz",
.hash = "N-V-__8AAIwh2AUYrkLbf6RU87sNN1tKAQ4qt1kqOwZXNld8",
.lazy = true,
},
.build_crab = .{
.url = "git+https://github.com/nurulhudaapon/build.crab?ref=zig-dev#48706bf535be39c87df6aeafcc14b946d174bb50",
.hash = "build_crab-0.2.1-U0id_ybJAABQczZZ4_zdQnkJuZF9WLQoHkkrY5TTq4bR",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

View file

@ -8,7 +8,8 @@ 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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration
///
/// See: [Temporal.Duration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration)
const Duration = @This();
_inner: *abi.c.Duration,
@ -40,7 +41,8 @@ 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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/from
///
/// See: [Temporal.Duration.from](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,
@ -55,7 +57,8 @@ pub const PartialDuration = struct {
};
/// Relative-to context for duration operations, used for balancing and calendar-aware math.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration#calendar_durations
///
/// See: [Temporal.Duration#calendar_durations](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,
@ -78,7 +81,8 @@ 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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/Duration
///
/// See: [Temporal.Duration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/Duration)
pub fn init(
years_val: i64,
months_val: i64,
@ -164,105 +168,122 @@ fn isTimeWithinRange(self: Duration) bool {
}
/// Returns the number of years in the duration.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/years
///
/// See: [Temporal.Duration.years](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/months
///
/// See: [Temporal.Duration.months](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/weeks
///
/// See: [Temporal.Duration.weeks](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/days
///
/// See: [Temporal.Duration.days](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/hours
///
/// See: [Temporal.Duration.hours](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/minutes
///
/// See: [Temporal.Duration.minutes](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/seconds
///
/// See: [Temporal.Duration.seconds](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/milliseconds
///
/// See: [Temporal.Duration.milliseconds](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/microseconds
///
/// See: [Temporal.Duration.microseconds](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/nanoseconds
///
/// See: [Temporal.Duration.nanoseconds](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/sign
///
/// See: [Temporal.Duration.sign](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/blank
///
/// See: [Temporal.Duration.blank](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/abs
///
/// See: [Temporal.Duration.abs](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/negated
///
/// See: [Temporal.Duration.negated](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/add
///
/// See: [Temporal.Duration.add](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/subtract
///
/// See: [Temporal.Duration.subtract](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/round
///
/// See: [Temporal.Duration.round](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));
@ -274,7 +295,8 @@ 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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/compare
///
/// See: [Temporal.Duration.compare](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);
@ -288,7 +310,8 @@ fn compareWithProvider(self: Duration, other: Duration, relative_to: RelativeTo,
}
/// Returns the total value of the duration in the specified unit.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/total
///
/// See: [Temporal.Duration.total](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);
@ -303,7 +326,8 @@ fn totalWithProvider(self: Duration, options: TotalOptions, provider: *const abi
}
/// Returns a string representing this duration in the ISO 8601 format.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toString
///
/// See: [Temporal.Duration.toString](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();
@ -315,14 +339,16 @@ 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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toJSON
///
/// See: [Temporal.Duration.toJSON](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration/toLocaleString
///
/// See: [Temporal.Duration.toLocaleString](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;
@ -340,8 +366,6 @@ 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);
}
@ -352,8 +376,6 @@ 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;
@ -362,8 +384,6 @@ 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);
@ -667,7 +687,6 @@ 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

@ -7,7 +7,8 @@ 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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant
///
/// See: [Temporal.Instant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant)
const Instant = @This();
_inner: *abi.c.Instant,
@ -26,7 +27,8 @@ pub const DifferenceSettings = t.DifferenceSettings;
pub const TimeZone = t.TimeZone;
/// Options for Instant.toString().
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toString
///
/// See: [Temporal.Instant.toString](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.
@ -47,26 +49,31 @@ pub const ToStringOptions = struct {
};
/// Construct an Instant from epoch nanoseconds (Temporal.Instant.fromEpochNanoseconds).
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/fromEpochNanoseconds
///
/// See: [Temporal.Instant.fromEpochNanoseconds](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/fromEpochMilliseconds
///
/// See: [Temporal.Instant.fromEpochMilliseconds](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/fromEpochNanoseconds
///
/// See: [Temporal.Instant.fromEpochNanoseconds](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/from
///
/// See: [Temporal.Instant.from](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);
@ -102,51 +109,59 @@ inline fn fromUtf8(text: []const u8) !Instant {
}
/// Returns a new Instant representing this instant moved forward by a given Duration.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/add
///
/// See: [Temporal.Instant.add](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/subtract
///
/// See: [Temporal.Instant.subtract](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/until
///
/// See: [Temporal.Instant.until](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/since
///
/// See: [Temporal.Instant.since](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/round
///
/// See: [Temporal.Instant.round](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/compare
///
/// See: [Temporal.Instant.compare](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/equals
///
/// See: [Temporal.Instant.equals](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toString
///
/// See: [Temporal.Instant.toString](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);
@ -175,19 +190,22 @@ 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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toJSON
///
/// See: [Temporal.Instant.toJSON](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toLocaleString
///
/// See: [Temporal.Instant.toLocaleString](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/toZonedDateTimeISO
///
/// See: [Temporal.Instant.toZonedDateTimeISO](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 };
@ -206,13 +224,15 @@ fn clone(self: Instant) Instant {
}
/// Returns the number of milliseconds since the Unix epoch for this instant.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/epochMilliseconds
///
/// See: [Temporal.Instant.epochMilliseconds](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: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant/epochNanoseconds
///
/// See: [Temporal.Instant.epochNanoseconds](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));
}
@ -222,8 +242,6 @@ 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 .{
@ -261,8 +279,6 @@ fn optsToRounding(opts: ToStringOptions) abi.c.ToStringRoundingOptions {
};
}
// --- 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);

View file

@ -1,16 +1,17 @@
const builtin = @import("builtin");
const std = @import("std");
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.
///
/// - [MDN Temporal.Now](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now)
/// See: [Temporal.Now](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now)
///
/// ## Description
///
@ -30,7 +31,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: [MDN Temporal.Now.instant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/instant)
/// See: [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);
@ -38,123 +39,80 @@ 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.
///
/// 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);
/// 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 };
}
/// 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.
///
/// 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,
);
/// 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 };
}
/// 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.
///
/// 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,
);
/// 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();
}
/// Returns a time zone identifier representing the system's current time zone.
///
/// 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";
/// 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();
}
/// 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.
///
/// See: [MDN Temporal.Now.zonedDateTimeISO](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now/zonedDateTimeISO)
pub fn zonedDateTimeISO() !ZonedDateTime {
const time_zone = try ZonedDateTime.TimeZone.init(timeZoneId());
return ZonedDateTime.fromEpochNanoseconds(currentEpochNanoseconds(), 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);
}
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,
};
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);
}
fn currentEpochNanoseconds() i128 {
return switch (builtin.os.tag) {
.windows => blk: {
const epoch_ns = std.time.epoch.windows * std.time.ns_per_s;
break :blk @as(i128, @intCast(std.os.windows.ntdll.RtlGetSystemTimePrecise())) * 100 + epoch_ns;
},
else => blk: {
var timespec: std.posix.timespec = undefined;
switch (std.posix.errno(std.posix.system.clock_gettime(.REALTIME, &timespec))) {
.SUCCESS => {},
else => return 0,
}
const seconds: i128 = @intCast(timespec.sec);
const nanos: i128 = @intCast(timespec.nsec);
break :blk seconds * std.time.ns_per_s + nanos;
},
};
}
// ---------- Tests ---------------------
test instant {
const io = std.testing.io;
const inst = try instant(io);
@ -164,37 +122,62 @@ test instant {
test plainDateISO {
const io = std.testing.io;
const date = try plainDateISO(io);
const date = try plainDateISO(std.testing.allocator, io, null);
defer date.deinit();
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;
const dt = try plainDateTimeISO(io);
var dt = try plainDateTimeISO(std.testing.allocator, io, null);
defer dt.deinit();
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(io);
const t = try plainTimeISO(std.testing.allocator, io, null);
try std.testing.expect(t.hour() < 24);
try std.testing.expect(t.minute() < 60);
try std.testing.expect(t.second() < 60);
}
test timeZoneId {
const tz = timeZoneId();
try std.testing.expectEqualStrings("UTC", tz);
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);
}
test zonedDateTimeISO {
const zdt = try 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);
try std.testing.expectEqualStrings("UTC", 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));
}

View file

@ -13,8 +13,7 @@ const Duration = @import("Duration.zig");
///
/// The `Temporal.PlainDate` object represents a calendar date (year, month, day) with no time or time zone.
///
/// 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
/// See: [Temporal.PlainDate](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.

View file

@ -11,9 +11,7 @@ const Duration = @import("Duration.zig");
///
/// The `Temporal.PlainDateTime` object represents a calendar date and wall-clock time, but no time zone or offset.
///
/// - [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
/// See: [Temporal.PlainDateTime](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.
@ -547,7 +545,6 @@ 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.
///
/// - [MDN Temporal.PlainMonthDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay)
/// See: [Temporal.PlainMonthDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay)
const PlainMonthDay = @This();
_inner: *abi.c.PlainMonthDay,
@ -39,7 +39,8 @@ fn wrapPlainMonthDay(result: anytype) !PlainMonthDay {
/// Creates a new PlainMonthDay from the given month, day, and optional calendar.
/// Equivalent to the Temporal.PlainMonthDay constructor.
/// See [MDN Temporal.PlainMonthDay() constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/PlainMonthDay)
///
/// See: [Temporal.PlainMonthDay](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);
@ -60,7 +61,8 @@ pub fn init(month_val: u8, day_val: u8, calendar: ?[]const u8) !PlainMonthDay {
}
/// Parses a PlainMonthDay from a string.
/// See [MDN Temporal.PlainMonthDay.from()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/from)
///
/// See: [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);
}
@ -77,14 +79,16 @@ fn fromUtf16(utf16: []const u16) !PlainMonthDay {
// Comparison
/// Returns true if this PlainMonthDay is equal to another (same date and calendar).
/// See [MDN Temporal.PlainMonthDay.prototype.equals()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/equals)
///
/// See: [Temporal.PlainMonthDay.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 [MDN Temporal.PlainMonthDay.prototype.calendarId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/calendarId)
///
/// See: [Temporal.PlainMonthDay.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);
@ -92,13 +96,15 @@ pub fn calendarId(self: PlainMonthDay, allocator: std.mem.Allocator) ![]u8 {
}
/// Returns the 1-based day index in the month of this date.
/// See [MDN Temporal.PlainMonthDay.prototype.day](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/day)
///
/// See: [Temporal.PlainMonthDay.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 [MDN Temporal.PlainMonthDay.prototype.monthCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/monthCode)
///
/// See: [Temporal.PlainMonthDay.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();
@ -109,7 +115,8 @@ pub fn monthCode(self: PlainMonthDay, allocator: std.mem.Allocator) ![]const u8
// Modification
/// Returns a new PlainMonthDay with some fields replaced by new values.
/// See [MDN Temporal.PlainMonthDay.prototype.with()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/with)
///
/// See: [Temporal.PlainMonthDay.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|
@ -142,7 +149,8 @@ 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 [MDN Temporal.PlainMonthDay.prototype.toPlainDate()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toPlainDate)
///
/// See: [Temporal.PlainMonthDay.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,
@ -167,7 +175,8 @@ pub fn toPlainDate(self: PlainMonthDay, year: i32) !PlainDate {
// String conversions
/// Returns a string representing this month-day in RFC 9557 format.
/// See [MDN Temporal.PlainMonthDay.prototype.toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toString)
///
/// See: [Temporal.PlainMonthDay.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, .{});
}
@ -184,26 +193,27 @@ fn toStringWithOptions(self: PlainMonthDay, allocator: std.mem.Allocator, option
}
/// Returns a string representing this month-day in RFC 9557 format (ISO 8601).
/// See [MDN Temporal.PlainMonthDay.prototype.toJSON()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toJSON)
///
/// See: [Temporal.PlainMonthDay.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 [MDN Temporal.PlainMonthDay.prototype.toLocaleString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/toLocaleString)
///
/// See: [Temporal.PlainMonthDay.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 [MDN Temporal.PlainMonthDay.prototype.valueOf()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay/valueOf)
///
/// See: [Temporal.PlainMonthDay.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.
///
/// - [MDN Temporal.PlainTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime)
/// See: [Temporal.PlainTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime)
const PlainTime = @This();
_inner: *abi.c.PlainTime,
@ -45,18 +45,26 @@ pub fn init(
microsecond_val: u16,
nanosecond_val: u16,
) !PlainTime {
return wrapPlainTime(abi.c.temporal_rs_PlainTime_try_new(
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}", .{
hour_val,
minute_val,
second_val,
millisecond_val,
microsecond_val,
nanosecond_val,
));
}) catch unreachable;
return from(s);
}
/// Parses a PlainTime from a string.
/// See [MDN Temporal.PlainTime.from()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/from)
///
/// See: [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);
}
@ -73,31 +81,36 @@ 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 [MDN Temporal.PlainTime.compare()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/compare)
///
/// See: [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 [MDN Temporal.PlainTime.prototype.equals()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/equals)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.add()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/add)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.subtract()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/subtract)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.until()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/until)
///
/// See: [Temporal.PlainTime.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);
@ -106,7 +119,8 @@ pub fn until(self: PlainTime, other: PlainTime, options: DifferenceSettings) !Du
}
/// Returns the duration from another PlainTime to this one.
/// See [MDN Temporal.PlainTime.prototype.since()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/since)
///
/// See: [Temporal.PlainTime.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);
@ -116,51 +130,59 @@ pub fn since(self: PlainTime, other: PlainTime, options: DifferenceSettings) !Du
// Rounding
/// Returns a new PlainTime rounded to the given unit and options.
/// See [MDN Temporal.PlainTime.prototype.round()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/round)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.hour](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/hour)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.minute](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/minute)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.second](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/second)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.millisecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/millisecond)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.microsecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/microsecond)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.nanosecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/nanosecond)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.with()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/with)
///
/// See: [Temporal.PlainTime.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),
@ -179,7 +201,8 @@ pub fn with(self: PlainTime, options: WithOptions) !PlainTime {
// String conversions
/// Returns a string representing this PlainTime in RFC 9557 format.
/// See [MDN Temporal.PlainTime.prototype.toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/toString)
///
/// See: [Temporal.PlainTime.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, .{});
}
@ -201,28 +224,29 @@ fn toStringWithOptions(self: PlainTime, allocator: std.mem.Allocator, options: t
}
/// Returns a string representing this PlainTime in RFC 9557 format (ISO 8601).
/// See [MDN Temporal.PlainTime.prototype.toJSON()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/toJSON)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.toLocaleString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/toLocaleString)
///
/// See: [Temporal.PlainTime.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 [MDN Temporal.PlainTime.prototype.valueOf()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime/valueOf)
///
/// See: [Temporal.PlainTime.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.
///
/// - [MDN Temporal.PlainYearMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth)
/// See: [Temporal.PlainYearMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth)
const PlainYearMonth = @This();
_inner: *abi.c.PlainYearMonth,
@ -47,7 +47,8 @@ fn wrapPlainYearMonth(result: anytype) !PlainYearMonth {
/// Creates a new PlainYearMonth from the given year, month, and optional calendar.
/// Equivalent to the Temporal.PlainYearMonth constructor.
/// See [MDN Temporal.PlainYearMonth() constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/PlainYearMonth)
///
/// See: [Temporal.PlainYearMonth](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);
@ -68,7 +69,8 @@ pub fn init(year_val: i32, month_val: u8, calendar: ?[]const u8) !PlainYearMonth
}
/// Parses a PlainYearMonth from a string.
/// See [MDN Temporal.PlainYearMonth.from()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/from)
///
/// See: [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);
}
@ -86,34 +88,39 @@ 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 [MDN Temporal.PlainYearMonth.compare()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/compare)
///
/// See: [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 [MDN Temporal.PlainYearMonth.prototype.equals()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/equals)
///
/// See: [Temporal.PlainYearMonth.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 [MDN Temporal.PlainYearMonth.prototype.add()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/add)
///
/// See: [Temporal.PlainYearMonth.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 [MDN Temporal.PlainYearMonth.prototype.subtract()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/subtract)
///
/// See: [Temporal.PlainYearMonth.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 [MDN Temporal.PlainYearMonth.prototype.until()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/until)
///
/// See: [Temporal.PlainYearMonth.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);
@ -122,7 +129,8 @@ pub fn until(self: PlainYearMonth, other: PlainYearMonth, options: DifferenceSet
}
/// Returns the duration from another PlainYearMonth to this one.
/// See [MDN Temporal.PlainYearMonth.prototype.since()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/since)
///
/// See: [Temporal.PlainYearMonth.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);
@ -132,7 +140,8 @@ pub fn since(self: PlainYearMonth, other: PlainYearMonth, options: DifferenceSet
// Property accessors
/// Returns the calendar identifier used to interpret the internal ISO 8601 date.
/// See [MDN Temporal.PlainYearMonth.prototype.calendarId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/calendarId)
///
/// See: [Temporal.PlainYearMonth.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);
@ -140,19 +149,22 @@ pub fn calendarId(self: PlainYearMonth, allocator: std.mem.Allocator) ![]u8 {
}
/// Returns the year of this year-month relative to the calendar's epoch.
/// See [MDN Temporal.PlainYearMonth.prototype.year](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/year)
///
/// See: [Temporal.PlainYearMonth.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 [MDN Temporal.PlainYearMonth.prototype.month](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/month)
///
/// See: [Temporal.PlainYearMonth.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 [MDN Temporal.PlainYearMonth.prototype.monthCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/monthCode)
///
/// See: [Temporal.PlainYearMonth.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();
@ -162,31 +174,36 @@ pub fn monthCode(self: PlainYearMonth, allocator: std.mem.Allocator) ![]const u8
}
/// Returns the number of days in the month of this year-month.
/// See [MDN Temporal.PlainYearMonth.prototype.daysInMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/daysInMonth)
///
/// See: [Temporal.PlainYearMonth.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 [MDN Temporal.PlainYearMonth.prototype.daysInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/daysInYear)
///
/// See: [Temporal.PlainYearMonth.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 [MDN Temporal.PlainYearMonth.prototype.monthsInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/monthsInYear)
///
/// See: [Temporal.PlainYearMonth.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 [MDN Temporal.PlainYearMonth.prototype.inLeapYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/inLeapYear)
///
/// See: [Temporal.PlainYearMonth.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 [MDN Temporal.PlainYearMonth.prototype.era](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/era)
///
/// See: [Temporal.PlainYearMonth.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();
@ -198,7 +215,8 @@ 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 [MDN Temporal.PlainYearMonth.prototype.eraYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/eraYear)
///
/// See: [Temporal.PlainYearMonth.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;
@ -207,7 +225,8 @@ pub fn eraYear(self: PlainYearMonth) ?i32 {
// Modification
/// Returns a new PlainYearMonth with some fields replaced by new values.
/// See [MDN Temporal.PlainYearMonth.prototype.with()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/with)
///
/// See: [Temporal.PlainYearMonth.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|
@ -240,7 +259,8 @@ 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 [MDN Temporal.PlainYearMonth.prototype.toPlainDate()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toPlainDate)
///
/// See: [Temporal.PlainYearMonth.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,
@ -265,7 +285,8 @@ pub fn toPlainDate(self: PlainYearMonth, day: u8) !PlainDate {
// String conversions
/// Returns a string representing this year-month in RFC 9557 format.
/// See [MDN Temporal.PlainYearMonth.prototype.toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toString)
///
/// See: [Temporal.PlainYearMonth.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, .{});
}
@ -282,26 +303,27 @@ fn toStringWithOptions(self: PlainYearMonth, allocator: std.mem.Allocator, optio
}
/// Returns a JSON string representing this year-month.
/// See [MDN Temporal.PlainYearMonth.prototype.toJSON()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toJSON)
///
/// See: [Temporal.PlainYearMonth.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 [MDN Temporal.PlainYearMonth.prototype.toLocaleString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/toLocaleString)
///
/// See: [Temporal.PlainYearMonth.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 [MDN Temporal.PlainYearMonth.prototype.valueOf()](https://developer.mozilla
///
/// See: [Temporal.PlainYearMonth.valueOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth/valueOf)
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());

68
src/SystemTimeZone.zig Normal file
View file

@ -0,0 +1,68 @@
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,27 +13,21 @@ 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,
@ -47,7 +41,6 @@ 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,
@ -56,7 +49,6 @@ 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,
@ -65,7 +57,6 @@ 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,
@ -74,14 +65,12 @@ 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,
@ -89,7 +78,8 @@ pub const DisplayTimeZone = enum {
};
/// Options for formatting ZonedDateTime as a string.
/// See [MDN Temporal.ZonedDateTime#rfc-9557-format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime#rfc-9557-format).
///
/// See: [Temporal.ZonedDateTime.toString](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toString#parameters)
pub const ToStringOptions = struct {
fractional_second_digits: ?u8 = null,
smallest_unit: ?Unit = null,
@ -100,6 +90,8 @@ pub const ToStringOptions = struct {
};
/// 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,
@ -117,35 +109,29 @@ pub const WithOptions = struct {
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 [MDN Temporal.ZonedDateTime() constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/ZonedDateTime)
///
/// See: [Temporal.ZonedDateTime](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 [MDN Temporal.ZonedDateTime.from()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/from)
///
/// See: [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);
@ -154,26 +140,30 @@ 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 [MDN Temporal.ZonedDateTime.compare()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/compare)
///
/// See: [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 [MDN Temporal.ZonedDateTime.prototype.add()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/add)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.equals()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/equals)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.getTimeZoneTransition()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/getTimeZoneTransition)
///
/// See: [Temporal.ZonedDateTime.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,
@ -188,13 +178,15 @@ pub fn getTimeZoneTransition(self: ZonedDateTime, direction: enum { next, previo
}
/// Returns a new ZonedDateTime rounded to the given unit and options.
/// See [MDN Temporal.ZonedDateTime.prototype.round()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/round)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.since()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/since)
///
/// See: [Temporal.ZonedDateTime.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;
@ -202,60 +194,69 @@ pub fn since(self: ZonedDateTime, other: ZonedDateTime, settings: DifferenceSett
}
/// Returns a ZonedDateTime representing the start of the day in the time zone.
/// See [MDN Temporal.ZonedDateTime.prototype.startOfDay()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/startOfDay)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.subtract()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/subtract)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.toInstant()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toInstant)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.toJSON()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toJSON)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.toLocaleString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toLocaleString)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.toPlainDate()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainDate)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.toPlainDateTime()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainDateTime)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.toPlainTime()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toPlainTime)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.toString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/toString)
///
/// See: [Temporal.ZonedDateTime.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();
@ -274,7 +275,8 @@ pub fn toString(self: ZonedDateTime, allocator: std.mem.Allocator, opts: ToStrin
}
/// Returns the duration from this ZonedDateTime to another.
/// See [MDN Temporal.ZonedDateTime.prototype.until()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/until)
///
/// See: [Temporal.ZonedDateTime.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;
@ -282,7 +284,8 @@ pub fn until(self: ZonedDateTime, other: ZonedDateTime, settings: DifferenceSett
}
/// Throws an error; valueOf() is not supported for ZonedDateTime.
/// See [MDN Temporal.ZonedDateTime.prototype.valueOf()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/valueOf)
///
/// See: [Temporal.ZonedDateTime.valueOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/valueOf)
pub fn valueOf(_: ZonedDateTime) !void {
return error.ValueOfNotSupported;
}
@ -309,7 +312,8 @@ pub fn with(self: ZonedDateTime, allocator: std.mem.Allocator, fields: anytype)
}
/// Returns a new ZonedDateTime interpreted in the new calendar system.
/// See [MDN Temporal.ZonedDateTime.prototype.withCalendar()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withCalendar)
///
/// See: [Temporal.ZonedDateTime.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);
@ -320,21 +324,24 @@ pub fn withCalendar(self: ZonedDateTime, calendar: []const u8) !ZonedDateTime {
}
/// Returns a new ZonedDateTime with the time part replaced by the new time.
/// See [MDN Temporal.ZonedDateTime.prototype.withPlainTime()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withPlainTime)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.withTimeZone()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/withTimeZone)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.calendarId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/calendarId)
///
/// See: [Temporal.ZonedDateTime.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);
@ -342,56 +349,65 @@ pub fn calendarId(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
}
/// Returns the 1-based day index in the month of this date.
/// See [MDN Temporal.ZonedDateTime.prototype.day](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/day)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.dayOfWeek](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/dayOfWeek)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.dayOfYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/dayOfYear)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.daysInMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInMonth)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.daysInWeek](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInWeek)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.daysInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/daysInYear)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.epochMilliseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/epochMilliseconds)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.epochNanoseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/epochNanoseconds)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.era](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/era)
///
/// See: [Temporal.ZonedDateTime.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();
@ -405,57 +421,66 @@ 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 [MDN Temporal.ZonedDateTime.prototype.eraYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/eraYear)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.hour](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/hour)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.hoursInDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/hoursInDay)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.inLeapYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/inLeapYear)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.microsecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/microsecond)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.millisecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/millisecond)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.minute](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/minute)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.month](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/month)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.monthCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/monthCode)
///
/// See: [Temporal.ZonedDateTime.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();
@ -464,19 +489,22 @@ pub fn monthCode(self: ZonedDateTime, allocator: std.mem.Allocator) ![]u8 {
}
/// Returns the number of months in the year of this date.
/// See [MDN Temporal.ZonedDateTime.prototype.monthsInYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/monthsInYear)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.nanosecond](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/nanosecond)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.offset](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/offset)
///
/// See: [Temporal.ZonedDateTime.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();
@ -486,19 +514,22 @@ 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 [MDN Temporal.ZonedDateTime.prototype.offsetNanoseconds](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/offsetNanoseconds)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.second](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/second)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.timeZoneId](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/timeZoneId)
///
/// See: [Temporal.ZonedDateTime.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);
@ -510,20 +541,23 @@ 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 [MDN Temporal.ZonedDateTime.prototype.weekOfYear](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/weekOfYear)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.year](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/year)
///
/// See: [Temporal.ZonedDateTime.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 [MDN Temporal.ZonedDateTime.prototype.yearOfWeek](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime/yearOfWeek)
///
/// See: [Temporal.ZonedDateTime.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);
@ -540,7 +574,12 @@ pub fn deinit(self: ZonedDateTime) void {
abi.c.temporal_rs_ZonedDateTime_destroy(self._inner);
}
// ---------- Tests ---------------------
/// 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 };
}
test init {
const tz = try TimeZone.init("America/New_York");
const zdt = try init(0, tz);

View file

@ -1,6 +1,6 @@
const std = @import("std");
pub const c = @import("temporal_rs").c;
pub const c = @import("libtemporal").c;
pub const to_string_rounding_options_auto: c.ToStringRoundingOptions = .{
.precision = .{ .is_minute = false, .precision = toOption(c.OptionU8, null) },

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.
///
/// - [MDN Temporal.Duration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Duration)
/// See: [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.
///
/// - [MDN Temporal.Instant](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Instant)
/// See: [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.
///
/// - [MDN Temporal.Now](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/Now)
/// See: [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.
///
/// - [MDN Temporal.PlainDate](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDate)
/// See: [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.
///
/// - [MDN Temporal.PlainDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDateTime)
/// See: [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.
///
/// - [MDN Temporal.PlainMonthDay](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainMonthDay)
/// See: [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.
///
/// - [MDN Temporal.PlainTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainTime)
/// See: [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.
///
/// - [MDN Temporal.PlainYearMonth](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainYearMonth)
/// See: [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.
///
/// - [MDN Temporal.ZonedDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime)
/// See: [Temporal.ZonedDateTime](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/ZonedDateTime)
pub const ZonedDateTime = @import("ZonedDateTime.zig");
test Temporal {
@ -526,10 +526,10 @@ fn assertDecls(comptime T: type, checks: anytype) !void {
var hasField = false;
if (typeInfo == .@"struct") {
const struct_info = typeInfo.@"struct";
inline for (struct_info.fields) |field| {
inline for (struct_info.field_names) |field_name| {
// 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 +548,39 @@ fn assertDecls(comptime T: type, checks: anytype) !void {
const struct_info = typeInfo.@"struct";
// Check declarations
inline for (struct_info.decls) |decl| {
inline for (struct_info.decl_names) |decl_name| {
// 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.fields) |field| {
inline for (struct_info.field_names) |field_name| {
// 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,11 +1,4 @@
/// # 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,

View file

@ -12,15 +12,18 @@ pub fn build(b: *std.Build) void {
const exe = b.addExecutable(.{
.name = "temporalz",
.root_module = b.createModule(.{
.root_source_file = b.path(if (is_freestanding) "src/wasm.zig" else "src/main.zig"),
.root_source_file = b.path("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;
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) {
@ -29,10 +32,16 @@ pub fn build(b: *std.Build) void {
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_cmd.addPassthruArgs();
run_step.dependOn(&run_cmd.step);
},
}

View file

@ -1,8 +1,7 @@
.{
.name = .temporalz_example,
.version = "0.1.2",
.version = "0.0.0",
.fingerprint = 0x686c9dfc777f9593,
.minimum_zig_version = "0.17.0-dev.387+31f157d80",
.dependencies = .{
.temporalz = .{
.path = "../",

View file

@ -100,13 +100,13 @@ pub fn main(init: std.process.Init) !void {
while (attempt < max_attempts) : (attempt += 1) {
current_test = friendly_name;
std.testing.allocator_instance = .{};
std.testing.allocator_instance = .init(std.heap.page_allocator, .{});
final_result = t.func();
current_test = null;
final_ns_taken = slowest.endTiming(allocator, scope_name, friendly_name);
if (std.testing.allocator_instance.deinit() == .leak) {
if (std.testing.allocator_instance.deinit() > 0) {
leak += 1;
Printer.status(.fail, "\n{s}\n\"{s}\" - Memory Leak\n{s}\n", .{ BORDER, friendly_name, BORDER });
}

17
test/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();

24
test/src/main.zig Normal file
View file

@ -0,0 +1,24 @@
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

@ -53,10 +53,10 @@ pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
if (io_optional) |io| {
const now_instant = try Temporal.Now.instant(io);
defer now_instant.deinit();
const now_date = try Temporal.Now.plainDateISO(io);
const now_date = try Temporal.Now.plainDateISO(allocator, io, null);
defer now_date.deinit();
const now_datetime = try Temporal.Now.plainDateTimeISO(io);
const now_time = try Temporal.Now.plainTimeISO(io);
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}
@ -186,6 +186,8 @@ pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
try zdt.toString(allocator, .{}),
});
try runTimeZoneExamples(allocator, io_optional, null);
// ----
// More complex Temporal API examples
// ----
@ -522,8 +524,11 @@ pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
try instant_zdt.toString(allocator, .{}),
});
const now_zdt = try Temporal.Now.zonedDateTimeISO();
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}
@ -531,9 +536,10 @@ pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
\\
\\
, .{
Temporal.Now.timeZoneId(),
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");
@ -810,17 +816,98 @@ pub fn run(allocator: std.mem.Allocator, io_optional: ?std.Io) !void {
});
}
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);
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, .{}),
});
}
std.log.defaultLog(message_level, scope, format, args);
}
pub const std_options: std.Options = .{
.logFn = logFn,
};

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

View file

@ -1,683 +0,0 @@
// 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;
})();

View file

@ -1,35 +0,0 @@
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);