siderust-js 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +166 -0
- package/.gitmodules +9 -0
- package/CHANGELOG.md +26 -0
- package/LICENSE +661 -0
- package/README.md +138 -0
- package/package.json +12 -0
- package/qtty-js/.github/workflows/ci.yml +151 -0
- package/qtty-js/.gitmodules +3 -0
- package/qtty-js/CHANGELOG.md +31 -0
- package/qtty-js/LICENSE +661 -0
- package/qtty-js/README.md +132 -0
- package/qtty-js/package.json +20 -0
- package/qtty-js/qtty/.github/workflows/ci.yml +155 -0
- package/qtty-js/qtty/CHANGELOG.md +120 -0
- package/qtty-js/qtty/Cargo.lock +1462 -0
- package/qtty-js/qtty/Cargo.toml +12 -0
- package/qtty-js/qtty/LICENSE +661 -0
- package/qtty-js/qtty/README.md +9 -0
- package/qtty-js/qtty/qtty/Cargo.toml +41 -0
- package/qtty-js/qtty/qtty/README.md +8 -0
- package/qtty-js/qtty/qtty/examples/angles.rs +14 -0
- package/qtty-js/qtty/qtty/examples/astronomy.rs +17 -0
- package/qtty-js/qtty/qtty/examples/dimensional_arithmetic.rs +83 -0
- package/qtty-js/qtty/qtty/examples/python_integration.rs +61 -0
- package/qtty-js/qtty/qtty/examples/quickstart.rs +15 -0
- package/qtty-js/qtty/qtty/examples/ratios.rs +12 -0
- package/qtty-js/qtty/qtty/examples/serde_with_unit.rs +234 -0
- package/qtty-js/qtty/qtty/examples/serialization.rs +141 -0
- package/qtty-js/qtty/qtty/examples/serialization_advanced.rs +155 -0
- package/qtty-js/qtty/qtty/src/f32.rs +108 -0
- package/qtty-js/qtty/qtty/src/f64.rs +30 -0
- package/qtty-js/qtty/qtty/src/i128.rs +111 -0
- package/qtty-js/qtty/qtty/src/i16.rs +111 -0
- package/qtty-js/qtty/qtty/src/i32.rs +111 -0
- package/qtty-js/qtty/qtty/src/i64.rs +111 -0
- package/qtty-js/qtty/qtty/src/i8.rs +111 -0
- package/qtty-js/qtty/qtty/src/lib.rs +238 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/src/lib.rs +7 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/src/lib.rs +7 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/src/lib.rs +5 -0
- package/qtty-js/qtty/qtty/tests/integration_tests.rs +529 -0
- package/qtty-js/qtty/qtty/tests/qtty_vec_feature_matrix.rs +58 -0
- package/qtty-js/qtty/qtty-core/Cargo.toml +41 -0
- package/qtty-js/qtty/qtty-core/README.md +8 -0
- package/qtty-js/qtty/qtty-core/examples/diesel_integration.rs +145 -0
- package/qtty-js/qtty/qtty-core/examples/quantity_db_serde.rs +215 -0
- package/qtty-js/qtty/qtty-core/src/dimension.rs +249 -0
- package/qtty-js/qtty/qtty-core/src/feature_diesel.rs +318 -0
- package/qtty-js/qtty/qtty-core/src/feature_pyo3.rs +27 -0
- package/qtty-js/qtty/qtty-core/src/feature_serde.rs +203 -0
- package/qtty-js/qtty/qtty-core/src/feature_tiberius.rs +28 -0
- package/qtty-js/qtty/qtty-core/src/lib.rs +744 -0
- package/qtty-js/qtty/qtty-core/src/macros.rs +93 -0
- package/qtty-js/qtty/qtty-core/src/quantity.rs +810 -0
- package/qtty-js/qtty/qtty-core/src/scalar.rs +1742 -0
- package/qtty-js/qtty/qtty-core/src/unit.rs +332 -0
- package/qtty-js/qtty/qtty-core/src/units/angular.rs +1228 -0
- package/qtty-js/qtty/qtty-core/src/units/area.rs +243 -0
- package/qtty-js/qtty/qtty-core/src/units/frequency.rs +179 -0
- package/qtty-js/qtty/qtty-core/src/units/length.rs +1270 -0
- package/qtty-js/qtty/qtty-core/src/units/mass.rs +488 -0
- package/qtty-js/qtty/qtty-core/src/units/mod.rs +26 -0
- package/qtty-js/qtty/qtty-core/src/units/power.rs +324 -0
- package/qtty-js/qtty/qtty-core/src/units/time.rs +667 -0
- package/qtty-js/qtty/qtty-core/src/units/unitless.rs +212 -0
- package/qtty-js/qtty/qtty-core/src/units/velocity.rs +210 -0
- package/qtty-js/qtty/qtty-core/src/units/volume.rs +269 -0
- package/qtty-js/qtty/qtty-core/tests/core.rs +628 -0
- package/qtty-js/qtty/qtty-core/tests/diesel.rs +461 -0
- package/qtty-js/qtty/qtty-core/tests/integers.rs +632 -0
- package/qtty-js/qtty/qtty-core/tests/no_cross_unit_ops.rs +35 -0
- package/qtty-js/qtty/qtty-core/tests/pyo3.rs +334 -0
- package/qtty-js/qtty/qtty-core/tests/quantity_f32.rs +276 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_decimal.rs +258 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_f32.rs +286 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_f64_real.rs +287 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_rational.rs +260 -0
- package/qtty-js/qtty/qtty-core/tests/serde.rs +256 -0
- package/qtty-js/qtty/qtty-core/tests/tiberius.rs +208 -0
- package/qtty-js/qtty/qtty-derive/Cargo.toml +23 -0
- package/qtty-js/qtty/qtty-derive/README.md +8 -0
- package/qtty-js/qtty/qtty-derive/src/lib.rs +340 -0
- package/qtty-js/qtty/qtty-ffi/ARCHITECTURE.md +3 -0
- package/qtty-js/qtty/qtty-ffi/Cargo.toml +31 -0
- package/qtty-js/qtty/qtty-ffi/README.md +9 -0
- package/qtty-js/qtty/qtty-ffi/build.rs +326 -0
- package/qtty-js/qtty/qtty-ffi/cbindgen.toml +105 -0
- package/qtty-js/qtty/qtty-ffi/include/qtty_ffi.h +1126 -0
- package/qtty-js/qtty/qtty-ffi/src/ffi.rs +1251 -0
- package/qtty-js/qtty/qtty-ffi/src/ffi_serde.rs +294 -0
- package/qtty-js/qtty/qtty-ffi/src/helpers.rs +310 -0
- package/qtty-js/qtty/qtty-ffi/src/lib.rs +229 -0
- package/qtty-js/qtty/qtty-ffi/src/macros.rs +121 -0
- package/qtty-js/qtty/qtty-ffi/src/registry.rs +274 -0
- package/qtty-js/qtty/qtty-ffi/src/types.rs +620 -0
- package/qtty-js/qtty/qtty-ffi/tests/integration_tests.rs +842 -0
- package/qtty-js/qtty/qtty-ffi/units.csv +156 -0
- package/qtty-js/qtty/qtty-ffi/units.csv.md +3 -0
- package/qtty-js/qtty-node/.prettierignore +6 -0
- package/qtty-js/qtty-node/.prettierrc.json +6 -0
- package/qtty-js/qtty-node/README.md +250 -0
- package/qtty-js/qtty-node/c8.config.json +11 -0
- package/qtty-js/qtty-node/eslint.config.js +31 -0
- package/qtty-js/qtty-node/examples/arithmetic.mjs +64 -0
- package/qtty-js/qtty-node/examples/astronomy.mjs +90 -0
- package/qtty-js/qtty-node/examples/quickstart.mjs +36 -0
- package/qtty-js/qtty-node/examples/serialization.mjs +125 -0
- package/qtty-js/qtty-node/examples/unit_factories.mjs +74 -0
- package/qtty-js/qtty-node/index.d.ts +219 -0
- package/qtty-js/qtty-node/index.js +323 -0
- package/qtty-js/qtty-node/lib/DerivedQuantity.js +122 -0
- package/qtty-js/qtty-node/lib/Quantity.js +151 -0
- package/qtty-js/qtty-node/lib/backend.js +25 -0
- package/qtty-js/qtty-node/native.cjs +306 -0
- package/qtty-js/qtty-node/package-lock.json +3223 -0
- package/qtty-js/qtty-node/package.json +70 -0
- package/qtty-js/qtty-node/units.d.ts +299 -0
- package/qtty-js/qtty-node/units.js +210 -0
- package/qtty-js/qtty-web/Cargo.lock +767 -0
- package/qtty-js/qtty-web/Cargo.toml +21 -0
- package/qtty-js/qtty-web/index.d.ts +140 -0
- package/qtty-js/qtty-web/index.js +20 -0
- package/qtty-js/qtty-web/lib/DerivedQuantity.js +58 -0
- package/qtty-js/qtty-web/lib/Quantity.js +75 -0
- package/qtty-js/qtty-web/lib/backend.js +80 -0
- package/qtty-js/qtty-web/package.json +45 -0
- package/qtty-js/qtty-web/src/lib.rs +111 -0
- package/qtty-js/scripts/ci.sh +73 -0
- package/scripts/ci.sh +123 -0
- package/siderust-core/Cargo.lock +787 -0
- package/siderust-core/Cargo.toml +18 -0
- package/siderust-core/DEDUPLICATION.md +124 -0
- package/siderust-core/src/body.rs +120 -0
- package/siderust-core/src/events.rs +184 -0
- package/siderust-core/src/lib.rs +20 -0
- package/siderust-core/src/observer.rs +55 -0
- package/siderust-core/src/position.rs +213 -0
- package/siderust-node/.prettierignore +7 -0
- package/siderust-node/.prettierrc.json +6 -0
- package/siderust-node/Cargo.lock +906 -0
- package/siderust-node/Cargo.toml +29 -0
- package/siderust-node/README.md +109 -0
- package/siderust-node/__test__/index.test.mjs +248 -0
- package/siderust-node/build.rs +5 -0
- package/siderust-node/c8.config.json +3 -0
- package/siderust-node/eslint.config.js +31 -0
- package/siderust-node/examples/01_basic_coordinates.mjs +24 -0
- package/siderust-node/examples/02_coordinate_transformations.mjs +25 -0
- package/siderust-node/examples/03_all_frames_conversions.mjs +26 -0
- package/siderust-node/examples/04_all_center_conversions.mjs +24 -0
- package/siderust-node/examples/05_target_tracking.mjs +22 -0
- package/siderust-node/examples/06_night_events.mjs +18 -0
- package/siderust-node/examples/07_moon_properties.mjs +21 -0
- package/siderust-node/examples/08_solar_system.mjs +19 -0
- package/siderust-node/examples/09_star_observability.mjs +22 -0
- package/siderust-node/examples/10_time_periods.mjs +9 -0
- package/siderust-node/examples/11_serialization.mjs +31 -0
- package/siderust-node/examples/12_runtime_ephemeris.mjs +27 -0
- package/siderust-node/examples/13_coordinate_operations.mjs +20 -0
- package/siderust-node/index.d.ts +623 -0
- package/siderust-node/index.js +79 -0
- package/siderust-node/lib/Observer.js +112 -0
- package/siderust-node/lib/Star.js +118 -0
- package/siderust-node/lib/backend.js +63 -0
- package/siderust-node/lib/wrappers.js +566 -0
- package/siderust-node/main.js +20 -0
- package/siderust-node/native.cjs +360 -0
- package/siderust-node/package-lock.json +3261 -0
- package/siderust-node/package.json +71 -0
- package/siderust-node/src/body.rs +74 -0
- package/siderust-node/src/coordinates.rs +372 -0
- package/siderust-node/src/ephemeris.rs +462 -0
- package/siderust-node/src/events.rs +577 -0
- package/siderust-node/src/lib.rs +43 -0
- package/siderust-node/src/observer.rs +132 -0
- package/siderust-node/src/phase.rs +218 -0
- package/siderust-node/src/position.rs +292 -0
- package/siderust-node/src/star.rs +200 -0
- package/siderust-web/Cargo.lock +855 -0
- package/siderust-web/Cargo.toml +34 -0
- package/siderust-web/README.md +100 -0
- package/siderust-web/__test__/index.test.mjs +118 -0
- package/siderust-web/examples/github-pages/README.md +31 -0
- package/siderust-web/examples/github-pages/index.html +135 -0
- package/siderust-web/index.d.ts +311 -0
- package/siderust-web/index.js +66 -0
- package/siderust-web/lib/Observer.js +103 -0
- package/siderust-web/lib/Star.js +116 -0
- package/siderust-web/lib/backend.js +400 -0
- package/siderust-web/lib/wrappers.js +512 -0
- package/siderust-web/package.json +55 -0
- package/siderust-web/src/body.rs +69 -0
- package/siderust-web/src/coordinates.rs +302 -0
- package/siderust-web/src/ephemeris.rs +456 -0
- package/siderust-web/src/events.rs +520 -0
- package/siderust-web/src/lib.rs +51 -0
- package/siderust-web/src/observer.rs +117 -0
- package/siderust-web/src/phase.rs +190 -0
- package/siderust-web/src/position.rs +291 -0
- package/siderust-web/src/star.rs +178 -0
- package/tempoch-js/.github/workflows/ci.yml +142 -0
- package/tempoch-js/.gitmodules +3 -0
- package/tempoch-js/CHANGELOG.md +25 -0
- package/tempoch-js/LICENSE +661 -0
- package/tempoch-js/README.md +126 -0
- package/tempoch-js/package.json +20 -0
- package/tempoch-js/scripts/ci.sh +73 -0
- package/tempoch-js/tempoch/.github/workflows/ci.yml +113 -0
- package/tempoch-js/tempoch/CHANGELOG.md +82 -0
- package/tempoch-js/tempoch/Cargo.lock +947 -0
- package/tempoch-js/tempoch/Cargo.toml +3 -0
- package/tempoch-js/tempoch/LICENSE +661 -0
- package/tempoch-js/tempoch/README.md +76 -0
- package/tempoch-js/tempoch/tempoch/Cargo.toml +27 -0
- package/tempoch-js/tempoch/tempoch/examples/periods.rs +45 -0
- package/tempoch-js/tempoch/tempoch/examples/quickstart.rs +13 -0
- package/tempoch-js/tempoch/tempoch/src/lib.rs +49 -0
- package/tempoch-js/tempoch/tempoch/tests/integration.rs +57 -0
- package/tempoch-js/tempoch/tempoch-core/Cargo.toml +24 -0
- package/tempoch-js/tempoch/tempoch-core/src/delta_t.rs +345 -0
- package/tempoch-js/tempoch/tempoch-core/src/instant.rs +811 -0
- package/tempoch-js/tempoch/tempoch-core/src/julian_date_ext.rs +142 -0
- package/tempoch-js/tempoch/tempoch-core/src/lib.rs +81 -0
- package/tempoch-js/tempoch/tempoch-core/src/period.rs +1168 -0
- package/tempoch-js/tempoch/tempoch-core/src/scales.rs +779 -0
- package/tempoch-js/tempoch/tempoch-ffi/Cargo.lock +889 -0
- package/tempoch-js/tempoch/tempoch-ffi/Cargo.toml +26 -0
- package/tempoch-js/tempoch/tempoch-ffi/build.rs +24 -0
- package/tempoch-js/tempoch/tempoch-ffi/cbindgen.toml +30 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/error.rs +19 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/lib.rs +82 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/period.rs +101 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/time.rs +711 -0
- package/tempoch-js/tempoch/tempoch-ffi/tests/ffi.rs +265 -0
- package/tempoch-js/tempoch-node/.prettierignore +6 -0
- package/tempoch-js/tempoch-node/.prettierrc.json +6 -0
- package/tempoch-js/tempoch-node/Cargo.lock +496 -0
- package/tempoch-js/tempoch-node/Cargo.toml +29 -0
- package/tempoch-js/tempoch-node/README.md +265 -0
- package/tempoch-js/tempoch-node/__test__/index.test.mjs +598 -0
- package/tempoch-js/tempoch-node/build.rs +5 -0
- package/tempoch-js/tempoch-node/c8.config.json +3 -0
- package/tempoch-js/tempoch-node/eslint.config.js +31 -0
- package/tempoch-js/tempoch-node/examples/periods.mjs +79 -0
- package/tempoch-js/tempoch-node/examples/quickstart.mjs +71 -0
- package/tempoch-js/tempoch-node/examples/timescales.mjs +92 -0
- package/tempoch-js/tempoch-node/index.d.ts +280 -0
- package/tempoch-js/tempoch-node/index.js +32 -0
- package/tempoch-js/tempoch-node/lib/JulianDate.js +176 -0
- package/tempoch-js/tempoch-node/lib/ModifiedJulianDate.js +156 -0
- package/tempoch-js/tempoch-node/lib/Period.js +133 -0
- package/tempoch-js/tempoch-node/lib/backend.js +38 -0
- package/tempoch-js/tempoch-node/lib/qttyCompat.js +92 -0
- package/tempoch-js/tempoch-node/native.cjs +317 -0
- package/tempoch-js/tempoch-node/package-lock.json +3223 -0
- package/tempoch-js/tempoch-node/package.json +56 -0
- package/tempoch-js/tempoch-node/src/lib.rs +573 -0
- package/tempoch-js/tempoch-web/Cargo.toml +23 -0
- package/tempoch-js/tempoch-web/index.d.ts +95 -0
- package/tempoch-js/tempoch-web/index.js +27 -0
- package/tempoch-js/tempoch-web/lib/JulianDate.js +170 -0
- package/tempoch-js/tempoch-web/lib/ModifiedJulianDate.js +145 -0
- package/tempoch-js/tempoch-web/lib/Period.js +121 -0
- package/tempoch-js/tempoch-web/lib/backend.js +118 -0
- package/tempoch-js/tempoch-web/package.json +46 -0
- package/tempoch-js/tempoch-web/src/lib.rs +184 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@siderust/tempoch",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Astronomical time primitives for Node.js — Julian Dates, Modified Julian Dates, UTC conversions, and period operations. Powered by Rust.",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "napi build --release --platform",
|
|
9
|
+
"build:debug": "napi build --platform",
|
|
10
|
+
"format": "prettier --write .",
|
|
11
|
+
"format:check": "prettier --check .",
|
|
12
|
+
"lint": "eslint .",
|
|
13
|
+
"test": "node --test __test__/*.test.mjs",
|
|
14
|
+
"test:coverage": "c8 --config c8.config.json node --test __test__/*.test.mjs",
|
|
15
|
+
"ci": "npm run format:check && npm run lint && npm run build:debug && npm test && npm run test:coverage",
|
|
16
|
+
"prepublishOnly": "napi build --release --platform"
|
|
17
|
+
},
|
|
18
|
+
"napi": {
|
|
19
|
+
"name": "tempoch",
|
|
20
|
+
"triples": {
|
|
21
|
+
"defaults": true
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"index.js",
|
|
26
|
+
"index.d.ts",
|
|
27
|
+
"native.cjs",
|
|
28
|
+
"lib/",
|
|
29
|
+
"examples/",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"keywords": [
|
|
33
|
+
"astronomy",
|
|
34
|
+
"time",
|
|
35
|
+
"julian-date",
|
|
36
|
+
"mjd",
|
|
37
|
+
"ephemeris",
|
|
38
|
+
"science",
|
|
39
|
+
"napi",
|
|
40
|
+
"rust",
|
|
41
|
+
"native"
|
|
42
|
+
],
|
|
43
|
+
"license": "AGPL-3.0",
|
|
44
|
+
"repository": {
|
|
45
|
+
"type": "git",
|
|
46
|
+
"url": "https://github.com/Siderust/tempoch"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@eslint/js": "^10.0.1",
|
|
50
|
+
"@napi-rs/cli": "^3.5.1",
|
|
51
|
+
"c8": "^11.0.0",
|
|
52
|
+
"eslint": "^10.0.3",
|
|
53
|
+
"globals": "^17.4.0",
|
|
54
|
+
"prettier": "^3.6.2"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Vallés Puig, Ramon
|
|
3
|
+
|
|
4
|
+
#![deny(clippy::all)]
|
|
5
|
+
|
|
6
|
+
use chrono::{DateTime, NaiveDate, Utc};
|
|
7
|
+
use napi::bindgen_prelude::*;
|
|
8
|
+
use napi_derive::napi;
|
|
9
|
+
use qtty::Days;
|
|
10
|
+
use tempoch::{
|
|
11
|
+
Interval, JulianDate as RustJD, ModifiedJulianDate as RustMJD, TimeInstant, JD, MJD,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
15
|
+
// Conversion helpers
|
|
16
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
17
|
+
|
|
18
|
+
/// Convert a JavaScript Date (f64 milliseconds since Unix epoch) to
|
|
19
|
+
/// `chrono::DateTime<Utc>`.
|
|
20
|
+
fn date_to_chrono(date: Date) -> napi::Result<DateTime<Utc>> {
|
|
21
|
+
let ms = date.value_of()? as i64;
|
|
22
|
+
DateTime::from_timestamp_millis(ms)
|
|
23
|
+
.ok_or_else(|| napi::Error::from_reason("Date value is outside representable UTC range"))
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/// Convert a `chrono::DateTime<Utc>` to a JavaScript Date.
|
|
27
|
+
fn chrono_to_date(env: &Env, dt: DateTime<Utc>) -> napi::Result<Date> {
|
|
28
|
+
env.create_date(dt.timestamp_millis() as f64)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
32
|
+
// UtcBounds — plain object returned by Period.toUtc()
|
|
33
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
34
|
+
|
|
35
|
+
/// UTC bounds of a [`Period`] expressed as millisecond timestamps.
|
|
36
|
+
///
|
|
37
|
+
/// Construct JS `Date` objects with `new Date(bounds.startMs)`.
|
|
38
|
+
#[napi(object)]
|
|
39
|
+
pub struct UtcBounds {
|
|
40
|
+
/// Start instant in milliseconds since Unix epoch.
|
|
41
|
+
pub start_ms: f64,
|
|
42
|
+
/// End instant in milliseconds since Unix epoch.
|
|
43
|
+
pub end_ms: f64,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
47
|
+
// JulianDate
|
|
48
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
49
|
+
|
|
50
|
+
/// A Julian Date — continuous count of days from the Julian Period origin.
|
|
51
|
+
///
|
|
52
|
+
/// The Julian Date for J2000.0 is **2 451 545.0** (2000-01-01 12:00:00 TT).
|
|
53
|
+
///
|
|
54
|
+
/// ```js
|
|
55
|
+
/// const { JulianDate } = require('@siderust/tempoch');
|
|
56
|
+
///
|
|
57
|
+
/// // Construct from raw value
|
|
58
|
+
/// const jd = new JulianDate(2_451_545.0);
|
|
59
|
+
///
|
|
60
|
+
/// // Construct from a JavaScript Date
|
|
61
|
+
/// const jd2 = JulianDate.fromDate(new Date('2000-01-01T12:00:00Z'));
|
|
62
|
+
/// ```
|
|
63
|
+
#[napi(js_name = "JulianDate")]
|
|
64
|
+
pub struct JsJulianDate {
|
|
65
|
+
pub(crate) inner: RustJD,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
#[napi]
|
|
69
|
+
impl JsJulianDate {
|
|
70
|
+
// ── constructors ─────────────────────────────────────────────────
|
|
71
|
+
|
|
72
|
+
/// Create a Julian Date from a raw scalar (days since the Julian Period).
|
|
73
|
+
///
|
|
74
|
+
/// Throws if `value` is `NaN` or `±Infinity`.
|
|
75
|
+
#[napi(constructor)]
|
|
76
|
+
pub fn new(value: f64) -> napi::Result<Self> {
|
|
77
|
+
if !value.is_finite() {
|
|
78
|
+
return Err(napi::Error::from_reason(
|
|
79
|
+
"Julian date value must be finite (not NaN or ±infinity)",
|
|
80
|
+
));
|
|
81
|
+
}
|
|
82
|
+
Ok(Self {
|
|
83
|
+
inner: RustJD::new(value),
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Create a Julian Date from a JavaScript `Date` object.
|
|
88
|
+
///
|
|
89
|
+
/// The UTC timestamp is interpreted as Universal Time and the ΔT
|
|
90
|
+
/// correction is applied automatically.
|
|
91
|
+
#[napi(factory)]
|
|
92
|
+
pub fn from_date(date: Date) -> napi::Result<Self> {
|
|
93
|
+
let dt = date_to_chrono(date)?;
|
|
94
|
+
Ok(Self {
|
|
95
|
+
inner: RustJD::from_utc(dt),
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// Create a Julian Date from explicit UTC components.
|
|
100
|
+
///
|
|
101
|
+
/// `second` may include a fractional part for sub-second precision.
|
|
102
|
+
/// All values are in the proleptic Gregorian calendar (UTC).
|
|
103
|
+
#[napi(factory)]
|
|
104
|
+
pub fn from_utc(
|
|
105
|
+
year: i32,
|
|
106
|
+
month: u8,
|
|
107
|
+
day: u8,
|
|
108
|
+
hour: u8,
|
|
109
|
+
minute: u8,
|
|
110
|
+
second: f64,
|
|
111
|
+
) -> napi::Result<Self> {
|
|
112
|
+
let whole_sec = second.floor() as u32;
|
|
113
|
+
let nanos = (second.fract() * 1_000_000_000.0) as u32;
|
|
114
|
+
let naive = NaiveDate::from_ymd_opt(year, month as u32, day as u32)
|
|
115
|
+
.and_then(|d| d.and_hms_nano_opt(hour as u32, minute as u32, whole_sec, nanos))
|
|
116
|
+
.ok_or_else(|| napi::Error::from_reason("Invalid UTC date/time components"))?;
|
|
117
|
+
let dt = DateTime::<Utc>::from_naive_utc_and_offset(naive, Utc);
|
|
118
|
+
Ok(Self {
|
|
119
|
+
inner: RustJD::from_utc(dt),
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// The J2000.0 epoch — JD 2 451 545.0 (2000-01-01T12:00:00 TT).
|
|
124
|
+
#[napi(factory)]
|
|
125
|
+
pub fn j2000() -> Self {
|
|
126
|
+
Self {
|
|
127
|
+
inner: RustJD::J2000,
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ── accessors ────────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
/// Raw Julian Date value (days since the Julian Period origin).
|
|
134
|
+
#[napi(getter)]
|
|
135
|
+
pub fn value(&self) -> f64 {
|
|
136
|
+
self.inner.value()
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ── conversions ──────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
/// Convert to a [`ModifiedJulianDate`] (`JD − 2 400 000.5`).
|
|
142
|
+
#[napi(js_name = "toMjd")]
|
|
143
|
+
pub fn to_mjd(&self) -> JsModifiedJulianDate {
|
|
144
|
+
JsModifiedJulianDate {
|
|
145
|
+
inner: self.inner.to::<MJD>(),
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/// Convert to a JavaScript `Date` (UTC).
|
|
150
|
+
///
|
|
151
|
+
/// Throws if the Julian Date falls outside the range representable by
|
|
152
|
+
/// `chrono` (roughly −262 143 to +262 143 CE).
|
|
153
|
+
#[napi(js_name = "toDate")]
|
|
154
|
+
pub fn to_date(&self, env: Env) -> napi::Result<Date> {
|
|
155
|
+
let dt = self.inner.to_utc().ok_or_else(|| {
|
|
156
|
+
napi::Error::from_reason("Julian date is outside the representable UTC range")
|
|
157
|
+
})?;
|
|
158
|
+
chrono_to_date(&env, dt)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ── epoch-based quantities ────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
/// Julian centuries since J2000.0 (T).
|
|
164
|
+
///
|
|
165
|
+
/// Used extensively by precession, nutation, and sidereal-time formulae.
|
|
166
|
+
#[napi(js_name = "julianCenturies")]
|
|
167
|
+
pub fn julian_centuries(&self) -> f64 {
|
|
168
|
+
self.inner.julian_centuries().value()
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/// Julian years since J2000.0.
|
|
172
|
+
#[napi(js_name = "julianYears")]
|
|
173
|
+
pub fn julian_years(&self) -> f64 {
|
|
174
|
+
self.inner.julian_years().value()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ── arithmetic ───────────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
/// Add a duration in days, returning a new `JulianDate`.
|
|
180
|
+
#[napi(js_name = "addDays")]
|
|
181
|
+
pub fn add_days(&self, days: f64) -> napi::Result<JsJulianDate> {
|
|
182
|
+
if !days.is_finite() {
|
|
183
|
+
return Err(napi::Error::from_reason("days must be finite"));
|
|
184
|
+
}
|
|
185
|
+
Ok(Self {
|
|
186
|
+
inner: self.inner.add_duration(Days::new(days)),
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/// Signed difference `self − other` in days.
|
|
191
|
+
#[napi]
|
|
192
|
+
pub fn difference(&self, other: &JsJulianDate) -> f64 {
|
|
193
|
+
self.inner.difference(&other.inner).value()
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ── formatting ───────────────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
/// Human-readable representation (e.g. `"Julian Day: 2451545 d"`).
|
|
199
|
+
#[napi]
|
|
200
|
+
pub fn format(&self) -> String {
|
|
201
|
+
format!("{}", self.inner)
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
206
|
+
// ModifiedJulianDate
|
|
207
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
208
|
+
|
|
209
|
+
/// A Modified Julian Date — `JD − 2 400 000.5`.
|
|
210
|
+
///
|
|
211
|
+
/// MJD starts at 1858-11-17T00:00:00 UTC (= JD 2 400 000.5).
|
|
212
|
+
/// J2000.0 is MJD **51 544.5**.
|
|
213
|
+
///
|
|
214
|
+
/// ```js
|
|
215
|
+
/// const { ModifiedJulianDate } = require('@siderust/tempoch');
|
|
216
|
+
///
|
|
217
|
+
/// const mjd = new ModifiedJulianDate(51_544.5);
|
|
218
|
+
/// const mjd2 = ModifiedJulianDate.fromDate(new Date('2000-01-01T12:00:00Z'));
|
|
219
|
+
/// ```
|
|
220
|
+
#[napi(js_name = "ModifiedJulianDate")]
|
|
221
|
+
pub struct JsModifiedJulianDate {
|
|
222
|
+
pub(crate) inner: RustMJD,
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
#[napi]
|
|
226
|
+
impl JsModifiedJulianDate {
|
|
227
|
+
// ── constructors ─────────────────────────────────────────────────
|
|
228
|
+
|
|
229
|
+
/// Create a Modified Julian Date from a raw scalar.
|
|
230
|
+
///
|
|
231
|
+
/// Throws if `value` is `NaN` or `±Infinity`.
|
|
232
|
+
#[napi(constructor)]
|
|
233
|
+
pub fn new(value: f64) -> napi::Result<Self> {
|
|
234
|
+
if !value.is_finite() {
|
|
235
|
+
return Err(napi::Error::from_reason(
|
|
236
|
+
"MJD value must be finite (not NaN or ±infinity)",
|
|
237
|
+
));
|
|
238
|
+
}
|
|
239
|
+
Ok(Self {
|
|
240
|
+
inner: RustMJD::new(value),
|
|
241
|
+
})
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/// Create a Modified Julian Date from a JavaScript `Date` object.
|
|
245
|
+
#[napi(factory)]
|
|
246
|
+
pub fn from_date(date: Date) -> napi::Result<Self> {
|
|
247
|
+
let dt = date_to_chrono(date)?;
|
|
248
|
+
Ok(Self {
|
|
249
|
+
inner: RustMJD::from_utc(dt),
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/// Create a Modified Julian Date from explicit UTC components.
|
|
254
|
+
#[napi(factory)]
|
|
255
|
+
pub fn from_utc(
|
|
256
|
+
year: i32,
|
|
257
|
+
month: u8,
|
|
258
|
+
day: u8,
|
|
259
|
+
hour: u8,
|
|
260
|
+
minute: u8,
|
|
261
|
+
second: f64,
|
|
262
|
+
) -> napi::Result<Self> {
|
|
263
|
+
let whole_sec = second.floor() as u32;
|
|
264
|
+
let nanos = (second.fract() * 1_000_000_000.0) as u32;
|
|
265
|
+
let naive = NaiveDate::from_ymd_opt(year, month as u32, day as u32)
|
|
266
|
+
.and_then(|d| d.and_hms_nano_opt(hour as u32, minute as u32, whole_sec, nanos))
|
|
267
|
+
.ok_or_else(|| napi::Error::from_reason("Invalid UTC date/time components"))?;
|
|
268
|
+
let dt = DateTime::<Utc>::from_naive_utc_and_offset(naive, Utc);
|
|
269
|
+
Ok(Self {
|
|
270
|
+
inner: RustMJD::from_utc(dt),
|
|
271
|
+
})
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// ── accessors ────────────────────────────────────────────────────
|
|
275
|
+
|
|
276
|
+
/// Raw MJD value.
|
|
277
|
+
#[napi(getter)]
|
|
278
|
+
pub fn value(&self) -> f64 {
|
|
279
|
+
self.inner.value()
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// ── conversions ──────────────────────────────────────────────────
|
|
283
|
+
|
|
284
|
+
/// Convert to a [`JulianDate`].
|
|
285
|
+
#[napi(js_name = "toJd")]
|
|
286
|
+
pub fn to_jd(&self) -> JsJulianDate {
|
|
287
|
+
JsJulianDate {
|
|
288
|
+
inner: self.inner.to::<JD>(),
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/// Convert to a JavaScript `Date` (UTC).
|
|
293
|
+
///
|
|
294
|
+
/// Throws if the MJD falls outside the representable UTC range.
|
|
295
|
+
#[napi(js_name = "toDate")]
|
|
296
|
+
pub fn to_date(&self, env: Env) -> napi::Result<Date> {
|
|
297
|
+
let dt = self.inner.to_utc().ok_or_else(|| {
|
|
298
|
+
napi::Error::from_reason("MJD is outside the representable UTC range")
|
|
299
|
+
})?;
|
|
300
|
+
chrono_to_date(&env, dt)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ── arithmetic ───────────────────────────────────────────────────
|
|
304
|
+
|
|
305
|
+
/// Add a duration in days, returning a new `ModifiedJulianDate`.
|
|
306
|
+
#[napi(js_name = "addDays")]
|
|
307
|
+
pub fn add_days(&self, days: f64) -> napi::Result<JsModifiedJulianDate> {
|
|
308
|
+
if !days.is_finite() {
|
|
309
|
+
return Err(napi::Error::from_reason("days must be finite"));
|
|
310
|
+
}
|
|
311
|
+
Ok(Self {
|
|
312
|
+
inner: self.inner.add_duration(Days::new(days)),
|
|
313
|
+
})
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/// Signed difference `self − other` in days.
|
|
317
|
+
#[napi]
|
|
318
|
+
pub fn difference(&self, other: &JsModifiedJulianDate) -> f64 {
|
|
319
|
+
self.inner.difference(&other.inner).value()
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// ── formatting ───────────────────────────────────────────────────
|
|
323
|
+
|
|
324
|
+
/// Human-readable representation (e.g. `"MJD 51544.5 d"`).
|
|
325
|
+
#[napi]
|
|
326
|
+
pub fn format(&self) -> String {
|
|
327
|
+
format!("{}", self.inner)
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
332
|
+
// Period
|
|
333
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
334
|
+
|
|
335
|
+
/// A time period (interval) defined by two MJD endpoints.
|
|
336
|
+
///
|
|
337
|
+
/// Intervals are half-open `[start, end)`: `start` is included, `end` is
|
|
338
|
+
/// excluded from containment tests.
|
|
339
|
+
///
|
|
340
|
+
/// ```js
|
|
341
|
+
/// const { Period } = require('@siderust/tempoch');
|
|
342
|
+
///
|
|
343
|
+
/// const p = new Period(51_544.5, 51_545.5); // one-day period at J2000
|
|
344
|
+
/// console.log(p.durationDays()); // 1
|
|
345
|
+
/// console.log(p.contains(51_545.0)); // true
|
|
346
|
+
/// ```
|
|
347
|
+
#[napi(js_name = "Period")]
|
|
348
|
+
pub struct JsPeriod {
|
|
349
|
+
pub(crate) inner: Interval<RustMJD>,
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
#[napi]
|
|
353
|
+
impl JsPeriod {
|
|
354
|
+
// ── constructors ─────────────────────────────────────────────────
|
|
355
|
+
|
|
356
|
+
/// Create a period from two MJD values.
|
|
357
|
+
///
|
|
358
|
+
/// Throws if `startMjd > endMjd`.
|
|
359
|
+
#[napi(constructor)]
|
|
360
|
+
pub fn new(start_mjd: f64, end_mjd: f64) -> napi::Result<Self> {
|
|
361
|
+
if !start_mjd.is_finite() || !end_mjd.is_finite() {
|
|
362
|
+
return Err(napi::Error::from_reason("Period endpoints must be finite"));
|
|
363
|
+
}
|
|
364
|
+
if start_mjd > end_mjd {
|
|
365
|
+
return Err(napi::Error::from_reason(
|
|
366
|
+
"Period start must not be after end",
|
|
367
|
+
));
|
|
368
|
+
}
|
|
369
|
+
Ok(Self {
|
|
370
|
+
inner: Interval::new(RustMJD::new(start_mjd), RustMJD::new(end_mjd)),
|
|
371
|
+
})
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/// Create a period from two JavaScript `Date` objects.
|
|
375
|
+
///
|
|
376
|
+
/// Throws if `start > end`.
|
|
377
|
+
#[napi(factory)]
|
|
378
|
+
pub fn from_dates(start: Date, end: Date) -> napi::Result<Self> {
|
|
379
|
+
let start_dt = date_to_chrono(start)?;
|
|
380
|
+
let end_dt = date_to_chrono(end)?;
|
|
381
|
+
let start_mjd = RustMJD::from_utc(start_dt);
|
|
382
|
+
let end_mjd = RustMJD::from_utc(end_dt);
|
|
383
|
+
if start_mjd > end_mjd {
|
|
384
|
+
return Err(napi::Error::from_reason(
|
|
385
|
+
"Period start must not be after end",
|
|
386
|
+
));
|
|
387
|
+
}
|
|
388
|
+
Ok(Self {
|
|
389
|
+
inner: Interval::new(start_mjd, end_mjd),
|
|
390
|
+
})
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// ── accessors ────────────────────────────────────────────────────
|
|
394
|
+
|
|
395
|
+
/// Start of the period as a raw MJD value.
|
|
396
|
+
#[napi(getter, js_name = "startMjd")]
|
|
397
|
+
pub fn start_mjd(&self) -> f64 {
|
|
398
|
+
self.inner.start.value()
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/// End of the period as a raw MJD value.
|
|
402
|
+
#[napi(getter, js_name = "endMjd")]
|
|
403
|
+
pub fn end_mjd(&self) -> f64 {
|
|
404
|
+
self.inner.end.value()
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/// Start as a [`ModifiedJulianDate`] object.
|
|
408
|
+
#[napi(getter)]
|
|
409
|
+
pub fn start(&self) -> JsModifiedJulianDate {
|
|
410
|
+
JsModifiedJulianDate {
|
|
411
|
+
inner: self.inner.start,
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/// End as a [`ModifiedJulianDate`] object.
|
|
416
|
+
#[napi(getter)]
|
|
417
|
+
pub fn end(&self) -> JsModifiedJulianDate {
|
|
418
|
+
JsModifiedJulianDate {
|
|
419
|
+
inner: self.inner.end,
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// ── duration ─────────────────────────────────────────────────────
|
|
424
|
+
|
|
425
|
+
/// Duration of the period in days.
|
|
426
|
+
#[napi(js_name = "durationDays")]
|
|
427
|
+
pub fn duration_days(&self) -> f64 {
|
|
428
|
+
self.inner.duration_days().value()
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ── set operations ───────────────────────────────────────────────
|
|
432
|
+
|
|
433
|
+
/// Return the overlapping sub-period, or `null` if they do not overlap.
|
|
434
|
+
///
|
|
435
|
+
/// Periods are half-open `[start, end)`: two periods that share only an
|
|
436
|
+
/// endpoint are considered non-overlapping.
|
|
437
|
+
#[napi]
|
|
438
|
+
pub fn intersection(&self, other: &JsPeriod) -> Option<JsPeriod> {
|
|
439
|
+
self.inner
|
|
440
|
+
.intersection(&other.inner)
|
|
441
|
+
.map(|p| JsPeriod { inner: p })
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/// Return `true` if the MJD value falls inside `[start, end)`.
|
|
445
|
+
#[napi]
|
|
446
|
+
pub fn contains(&self, mjd: f64) -> bool {
|
|
447
|
+
let t = RustMJD::new(mjd);
|
|
448
|
+
t >= self.inner.start && t < self.inner.end
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// ── conversions ──────────────────────────────────────────────────
|
|
452
|
+
|
|
453
|
+
/// Return start and end as millisecond timestamps (ms since Unix epoch).
|
|
454
|
+
///
|
|
455
|
+
/// Construct JS `Date` objects with:
|
|
456
|
+
/// ```js
|
|
457
|
+
/// const { startMs, endMs } = period.toUtc();
|
|
458
|
+
/// const startDate = new Date(startMs);
|
|
459
|
+
/// ```
|
|
460
|
+
///
|
|
461
|
+
/// Throws if either endpoint is outside the representable UTC range.
|
|
462
|
+
#[napi(js_name = "toUtc")]
|
|
463
|
+
pub fn to_utc(&self) -> napi::Result<UtcBounds> {
|
|
464
|
+
let start_dt = self.inner.start.to_utc().ok_or_else(|| {
|
|
465
|
+
napi::Error::from_reason("Period start is outside the representable UTC range")
|
|
466
|
+
})?;
|
|
467
|
+
let end_dt = self.inner.end.to_utc().ok_or_else(|| {
|
|
468
|
+
napi::Error::from_reason("Period end is outside the representable UTC range")
|
|
469
|
+
})?;
|
|
470
|
+
Ok(UtcBounds {
|
|
471
|
+
start_ms: start_dt.timestamp_millis() as f64,
|
|
472
|
+
end_ms: end_dt.timestamp_millis() as f64,
|
|
473
|
+
})
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// ── formatting ───────────────────────────────────────────────────
|
|
477
|
+
|
|
478
|
+
/// Human-readable representation.
|
|
479
|
+
#[napi]
|
|
480
|
+
pub fn format(&self) -> String {
|
|
481
|
+
format!(
|
|
482
|
+
"Period(MJD {:.6} to MJD {:.6})",
|
|
483
|
+
self.inner.start.value(),
|
|
484
|
+
self.inner.end.value()
|
|
485
|
+
)
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
490
|
+
// Free conversion functions
|
|
491
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
492
|
+
|
|
493
|
+
/// Convert a Julian Date to a Modified Julian Date value.
|
|
494
|
+
///
|
|
495
|
+
/// `mjd = jd − 2 400 000.5`
|
|
496
|
+
#[napi(js_name = "jdToMjd")]
|
|
497
|
+
pub fn jd_to_mjd(jd: f64) -> f64 {
|
|
498
|
+
RustJD::new(jd).to::<MJD>().value()
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/// Convert a Modified Julian Date to a Julian Date value.
|
|
502
|
+
///
|
|
503
|
+
/// `jd = mjd + 2 400 000.5`
|
|
504
|
+
#[napi(js_name = "mjdToJd")]
|
|
505
|
+
pub fn mjd_to_jd(mjd: f64) -> f64 {
|
|
506
|
+
RustMJD::new(mjd).to::<JD>().value()
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/// Compute Julian centuries since J2000.0 for a Julian Date.
|
|
510
|
+
#[napi(js_name = "julianCenturies")]
|
|
511
|
+
pub fn julian_centuries(jd: f64) -> f64 {
|
|
512
|
+
RustJD::new(jd).julian_centuries().value()
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/// Compute Julian years since J2000.0 for a Julian Date.
|
|
516
|
+
#[napi(js_name = "julianYears")]
|
|
517
|
+
pub fn julian_years(jd: f64) -> f64 {
|
|
518
|
+
RustJD::new(jd).julian_years().value()
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/// Convert a JavaScript `Date` to a Julian Date value.
|
|
522
|
+
#[napi(js_name = "jdFromDate")]
|
|
523
|
+
pub fn jd_from_date(date: Date) -> napi::Result<f64> {
|
|
524
|
+
let dt = date_to_chrono(date)?;
|
|
525
|
+
Ok(RustJD::from_utc(dt).value())
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/// Convert a JavaScript `Date` to a Modified Julian Date value.
|
|
529
|
+
#[napi(js_name = "mjdFromDate")]
|
|
530
|
+
pub fn mjd_from_date(date: Date) -> napi::Result<f64> {
|
|
531
|
+
let dt = date_to_chrono(date)?;
|
|
532
|
+
Ok(RustMJD::from_utc(dt).value())
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/// Convert a Julian Date value to a JavaScript `Date`.
|
|
536
|
+
///
|
|
537
|
+
/// Throws if the Julian Date is outside the representable UTC range.
|
|
538
|
+
#[napi(js_name = "jdToDate")]
|
|
539
|
+
pub fn jd_to_date(env: Env, jd: f64) -> napi::Result<Date> {
|
|
540
|
+
let dt = RustJD::new(jd).to_utc().ok_or_else(|| {
|
|
541
|
+
napi::Error::from_reason("Julian date is outside the representable UTC range")
|
|
542
|
+
})?;
|
|
543
|
+
chrono_to_date(&env, dt)
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/// Convert a Modified Julian Date value to a JavaScript `Date`.
|
|
547
|
+
///
|
|
548
|
+
/// Throws if the MJD is outside the representable UTC range.
|
|
549
|
+
#[napi(js_name = "mjdToDate")]
|
|
550
|
+
pub fn mjd_to_date(env: Env, mjd: f64) -> napi::Result<Date> {
|
|
551
|
+
let dt = RustMJD::new(mjd).to_utc().ok_or_else(|| {
|
|
552
|
+
napi::Error::from_reason("MJD is outside the representable UTC range")
|
|
553
|
+
})?;
|
|
554
|
+
chrono_to_date(&env, dt)
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/// Signed difference `jd1 − jd2` in days.
|
|
558
|
+
#[napi(js_name = "jdDifference")]
|
|
559
|
+
pub fn jd_difference(jd1: f64, jd2: f64) -> f64 {
|
|
560
|
+
RustJD::new(jd1).difference(&RustJD::new(jd2)).value()
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/// Signed difference `mjd1 − mjd2` in days.
|
|
564
|
+
#[napi(js_name = "mjdDifference")]
|
|
565
|
+
pub fn mjd_difference(mjd1: f64, mjd2: f64) -> f64 {
|
|
566
|
+
RustMJD::new(mjd1).difference(&RustMJD::new(mjd2)).value()
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/// Return the tempoch-node version string.
|
|
570
|
+
#[napi(js_name = "version")]
|
|
571
|
+
pub fn version() -> String {
|
|
572
|
+
env!("CARGO_PKG_VERSION").to_string()
|
|
573
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[package]
|
|
2
|
+
name = "tempoch-web"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
edition = "2021"
|
|
5
|
+
authors = ["VPRamon <vallespuigramon@gmail.com>"]
|
|
6
|
+
license = "AGPL-3.0"
|
|
7
|
+
repository = "https://github.com/Siderust/tempoch"
|
|
8
|
+
description = "Browser/WASM bindings for tempoch — astronomical time primitives in the browser"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
|
|
11
|
+
[lib]
|
|
12
|
+
crate-type = ["cdylib", "rlib"]
|
|
13
|
+
|
|
14
|
+
[dependencies]
|
|
15
|
+
tempoch = "0.3.0"
|
|
16
|
+
qtty = "0.4.0"
|
|
17
|
+
chrono = "0.4"
|
|
18
|
+
wasm-bindgen = "0.2"
|
|
19
|
+
js-sys = "0.3"
|
|
20
|
+
console_error_panic_hook = "0.1"
|
|
21
|
+
|
|
22
|
+
[patch.crates-io]
|
|
23
|
+
tempoch = { path = "../tempoch/tempoch" }
|