{"id":28175452,"url":"https://github.com/davoodeh/jelal","last_synced_at":"2026-06-30T05:31:54.809Z","repository":{"id":293288549,"uuid":"983554192","full_name":"Davoodeh/jelal","owner":"Davoodeh","description":"A minimal, no-std modern Jalali (Persian/Iranian/Shamsi) calendar for developers with diverse language support (Rust, JS/TS/WASM, C/C++, Python, and more)","archived":false,"fork":false,"pushed_at":"2025-10-22T03:33:30.000Z","size":256,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-05-17T21:35:09.601Z","etag":null,"topics":["calendar","ffi","jalali","jelal","no-alloc","no-std","persian","rust","shamsi"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/jelal","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Davoodeh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-14T14:53:59.000Z","updated_at":"2025-10-22T03:30:53.000Z","dependencies_parsed_at":"2025-05-14T16:35:46.030Z","dependency_job_id":null,"html_url":"https://github.com/Davoodeh/jelal","commit_stats":null,"previous_names":["davoodeh/jelal"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/Davoodeh/jelal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Davoodeh%2Fjelal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Davoodeh%2Fjelal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Davoodeh%2Fjelal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Davoodeh%2Fjelal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Davoodeh","download_url":"https://codeload.github.com/Davoodeh/jelal/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Davoodeh%2Fjelal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34954283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-30T02:00:05.919Z","response_time":92,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["calendar","ffi","jalali","jelal","no-alloc","no-std","persian","rust","shamsi"],"created_at":"2025-05-15T23:14:13.246Z","updated_at":"2026-06-30T05:31:54.796Z","avatar_url":"https://github.com/Davoodeh.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Crates.io Version](https://img.shields.io/crates/v/jelal)](https://crates.io/crates/jelal)\n[![docs.rs](https://img.shields.io/docsrs/jelal)](https://docs.rs/jelal/latest/jelal/)\n\n---\n\n\u003e \"_ASAD_!\"  -[Captian Jelal](https://soundcloud.com/alisorena/nakhodajelal)\n\n---\n\nJelal is a modern and lean Jalali (Persian/Iranian) calendar for developers.\n\nSupported in:\n- Rust\n- JavaScript/TypeScript (using `wasm-pack`)\n- Python (using `maturin`)\n- C (using `cbindgen` or built-in `codegen`)\n\nJump to [Building and Usage](#building-and-usage) for installation.\n\n## Introduction\n\nThis library does not reinvent the wheel nor aims to be the fastest or the most\ncorrect for all the ages (-99999 to year 99999). The goal of this project is to\nbe light and fairly correct by doing the absolute minimum and working mostly\naround the contemporary centuries at best. Just to remind myself that doing less\nis sometimes doing more. This approach makes for verbose configurations since\nthe exported functionalities use established tools like `cbindgen` and\n`wasm-pack` which do not support macro expansion even though this is not an\nissue since the size and scope of the library is really slim.\n\nMost attempts at implementing of Jalali underestimate how much work it takes to\nimplement a calendar from scratch with libc level of features including\ntimezones, localization and else. Knowing that a calendar only actually concerns\n\"days,\" especially a calendar like Jalali which is a mirror of Gregorian (both\nsolar calendars). With that in mind, this crate tries to simply sync Jalali to\nGregorian by days which effectively dodges all of the complexity, issues and\nfeatures. Simply use your default Gregorian time libraries including libc's and\nupon needing a date conversion do that by calling this to get the right idea\nabout what month and day is it in Jalali and format accordingly. The rest (day\nof week, time of day, timezone and etc.) is exactly as your Gregorian library\nsuggests.\n\nAs such conversions are rarely actually needed, there is no point in being fast\neither. The base of all the calculations will be the mature Gregorian\nimplementations and this little structs can be used just for the IO and other\ninteractions. Hence, this crate simply works and aims to be a single reference\nfor how exactly calculations about this calendar must be since there is nothing\nbut hard to read papers from 2000's on this issue, all text and not a single\nformula.\n\nRegardless, this crate is `no_std` for the ease of use cross boundaries.\nEverything is in `const` so usage in compile-time is a viable option. Beyond\nthat, no dependencies is required! Once `no_core` is stable, core will be\nstripped away too.\n\n### Example and Design Motivation\n\nThis library does not calculate the date directly and works with a \"Day Delta\"\napproach. Since both the Gregorian and Persian calendars are solar and almost\nidentical in most aspects, the aim for this library is to just do the least\npossible logical process to convert the two different days (even if it results\nin a somewhat primitive algorithm). Below an example of this approach is\nprovided.\n\nConsider a fixed point in both calendars with verified equals (i.e Saturday 3rd\nof May (5) 2025 is 13th of Ordibehesht (2) 1404, the date of the start of the\nproject).  To convert any other date based on that time, a \"Day Delta\" or day\ndifference with that day in Gregorian is needed. This is a trivial problem which\nis done in almost every date and time library for most languages. In this\nexample, we try to convert Wednesday May 14 2025 to Jalali. Since this is\ntrivial, no other library is used to calculate the 11 day difference. Granted,\nwe run that in this library to add eleven days to the initial fixed-point like\nbelow, which yields the correct results.\n\n\u003c!-- edit test_readme --\u003e\n```rust\nuse jelal::Date;\n\nlet fixed_point = Date::from((1404, 2, 13)); // 2025, 5 (May), 3\nassert_eq!(fixed_point.add_days(11), Date::from((1404, 2, 24)));\n```\n\nAs explained above, this has the benefit of being simple and removes all the\nresponsiblity of calculating and matching the dates without engaging\nlocalization, second counting or any other complication. The API is not the most\neasy to use but the goal is not its user-friendliness and rather the ease of its\nuse in FFIs, in cross-boundaries and in environments with limited features with\none single code base.\n\n#### Regarding `codegen` and Alternatives\n\nThis crate uses `codegen` local binary to generate the FFI files. The output is\nalready included in the sources with each commit so there is no need to run it\nbut to know the reason this square wheel exists while the general \"calendar\nparts\" avoid re-inventing the wheel (as mentioned before) is important.\nThe output of the crate is some simple Rust code that is easy to work with for\ntools like `cbindgen` and provides some occasional solutions for their\nlimitations (like \"conditional attribute not found when using `pymethods`\" in\n`pyo3`).\n\nMajor crates like `icu4x` use `uniffi` or `diplomat` to create binds. `codegen`\nis a hack compared to the aforementioned tools. However, after experiments,\nthese sophisticated tools proved to be excess in binding generation and\ninconvenient in packaging department as their goals is to provide \"good enough\nbindings for many languages\" rather than a \"one click magic everything for one\nlanguage\".\n\nSo in short, `codegen` was written to automatically create FFI compatible Rust\ncode from the main Rust modules without the clusters of `cfg` attributes and\nburden of keeping everything in sync. All the while keeping the convenience of\ntools like `maturin` and `wasm-pack`.\n\nFor more information, see the crate. This crate was not intended for publication\n(at least for now) since it is yet to prove useful for any purpose and style of\ncoding beyond this project's.\n\n#### Regarding `codegen`'s `cffi` and `cbindgen`\n\nAlthough this crate originally supported `cbindgen`, that was put aside\n(partially) and a custom solution is being iterated on which you can use right\nnow using `make` commands.\n\n`codegen` internal crate heavily relies on re-exports under different names\nwhich confuses `cbindgen` (i.e `Date` is the Rust struct that operates\neverything and also `ffi::Date` is a \"mirror\" of it created by `codegen` to work\nmore gracefully in FFI boundaries). This confusion causes incosistent behavior\nfor attribute and values (especially if a value should differ in FFI in compare\nto its Rust-only counterpart). As of now, such incosistencies do not effect the\ncrate and make `cbindgen` a viable option; Only if the user accepts that\neverything is working \"unintentionally.\"\n\nAnother interesting conflict between the capabilities of `cbindgen` and the\nmethods that `codegen` uses to facilities FFI interactions is regarding\nconstants. As of now constants use transmutes to convert between FFI counterpart\nand Rust-only counterparts (yes, `transmute` is frowned upon and this approach\nmay change for that reason). Yet again, `cbindgen` cannot handle the transmute\nexpression and opts for the original value instead (which is mostly fine but\naccidentally) and dumps a lot of false warnings. A bold distinction of\n`cbindgen` and `codegen`'s `cffi` binary is that the latter prefers\n`extern const` for constants rather than (\"evil\") `define` macros.\n\n## Building and Usage\n\nIf you are in a hurry, run the following command with either of the `verb`s\nbelow:\n\n```sh\ncargo make $VERB\n```\n\nImportant final verbs for the rushed:\n- `build`: Rust build\n- `headers` (C): Creates the C compatible library and C headers for the C\n  language (the default using nightly for the `cbindgen` part, or use `cffi`)\n- `wasm-pack` (JS/TS): Creates the library and its package with `wasm-pack`\n- `maturin` (Python): Creates the library and its package with `maturin`\n\n### Longer explanation\n\nTo build the library one could use a simple `cargo build` and generate the\nheaders using tools like `cbindgen` or `cffi` and else, which are not explained\nin this README. If the user is not acquainted with the correct tools, the\ndefaults are prepared in `Makefile.toml` which can be used with `cargo build`\n(`makers`) to build and install the project.\n\nFirst, if `cargo-make` is not installed, install it.\n\n```sh\ncargo install cargo-make\n```\n\nAfter ensuring `cargo-make`, to build the project call:\n\n\n```sh\n# This is the same as calling `cargo build`.\ncargo make build\n```\n\nTo see the possible build tasks (\"targets\" in `make` jargon), run the following:\n\n```sh\ncargo make --list-category-steps Jelal\n```\n\n### Building for Release\n\nTo build for release in `cargo make`, simply pass `--profile release` right\nafter `make`:\n\n```sh\ncargo make --profile release $REST_OF_ARGUMENTS\n```\n\nAs in `cargo`, the default is set to `debug` or `development` but `release` is\nsupported. Any invalid profile will behave as `debug`.\n\nNote that flags in this mode are set to treat any warning as hard error.\n\n### Build Requirements\n\nBesides Rust utilities like `cargo` and `rustup`, the following are optionally\nrequired. The dependencies will be automatically installed if using\n`cargo-make`:\n- `build`: no further dependencies\n- `cbindgen`: requires `cbindgen 0.29.0` and a `nightly` since attributes for\n  this tool are behind `cfg_attr` (`cargo install cbindgen`)\n- `build-wasm`: `wasm32-unknown-unknown` tuple (`rustup target add\n  wasm32-unknown-unknown`)\n- `wasm-pack`: `build-wasm` requirements and also `wasm-pack` (`cargo install\n  wasm-pack`)\n- `maturin`: requires `maturin` (`cargo install maturin`)\n\nThe requirements for the tools mentioned above can be found on their resources.\n\nThe `makers` scripts are heavily dependent on the environment variables defined\nin the `Makefile.toml`. Read the sources for their requirements.\n\n### Installation\n\nAs of now, only C/Rust, C headers and Python package (via `pip`) can be\ninstalled automatically.\n\n#### C or Dynamic Library Installation\n\nAfter building the library for C or Rust, run the following (with correct\npriviledges) to install the library and optionally the headers (if generated).\n\n```sh\ncargo make install-lib\n\n# or with `sudo`\nsudo -E cargo make install-lib\n```\n\nNote that a common pitfall on dynamically linking is forgetting to set\n`LD_LIBRARY_PATH` (more on that online, a good default is\n`LD_LIBRARY_PATH=\"/usr/local/lib\"`) which may make you think that the install\ncommand had silently failed!\n\nAlso, the `rustup` command is usually installed by the user and in the `$HOME`\ndirectory hence the `-E` after `sudo`.\n\n#### Python Wheel Package\n\nLike before, after building the `whl` for Python, run the following command to\ninstall it (make sure your environment is configured):\n\n```sh\ncargo make install-wheel\n```\n\nThis will install the most recently built `whl` file in your target directory.\nIf another behavior is needed, you should manually run the installation\ncommands.\n\n## Contribute\n\nThe feature set seems to be enough for the goal of the project and the most\nwelcome contributions as for now are tests! The first and foremost important\ngoal of this project is to be \"correct\" rather than anything else. The languages\ncan be expanded further as well. For more TODO see the sources and the section\nbelow. Please keep the simple conventions in the section ahead in mind while\ndeveloping.\n\n### Style and Notes\n\n- Whenever possible, order values, codes and all else in year, month, day order.\n- Avoid abbrevations.\n- Since `Makefile.toml` searches `Cargo.toml` `features` section, keep that\n  simple, formatted and keep each key-value pair on one line with no `.`\n  notation.\n- Do not use any proc-macro if not necessary (`jelal_proc` is discontinued and\n  if necessary, will host them)\n- Keep changes in as small as possible commits with imperative short\n  descriptions.\n- Mention the changes in the changelog in the order of \"Add\", \"Change\" and\n  \"Remove\" and \"Fix\".\n- Run `cargo make pre-commit` before committing which does a lot of unnessary\n  checks and takes a really long time to finish but still, better safe.\n- In pervious versions, some features could not work together. This is not\n  desirable so keep in mind how features interact if all or some are enabled\n  together.\n\n### Versioning\n\nBefore `1.0.0`, every minor version (`0.THIS.0`) bump *may* be a breaking change\nfor the dependent code using this library.\n\nSee the `CHANGELOG` file in the source for the news about each release.\n\n### TODOs\n\nSee the code or `CHANGELOG` file for TODOs.\n\n## License\n\nThe license of this crate and its components is exactly as described in the\n`Cargo.toml`, [`MIT`] OR [`Apache-2.0`]. Some functions are copied (with minor\nchanges) from\n[`unicode-org/icu4x/utils/calendrical_calculations/src/persian.rs`] which\nprobably lies under the \"Software\" clause of the free [`Unicode-3.0`] license\n(see the exact file here: [`unicode-org/icu4x/LICENSE`]).\n\nFor the dependencies, consult their licenses but this crate aims to keep it at\n[`MIT`] OR [`Apache-2.0`] dual license for the sake of simplicity, as for the\nrest of the ecosystem with the exception of the [`Unicode-3.0`] mentioned above.\n\n[`MIT`]: https://opensource.org/license/MIT\n[`Apache-2.0`]: https://opensource.org/license/apache-2-0\n[`Unicode-3.0`]: https://opensource.org/license/unicode-license-v3\n[`unicode-org/icu4x/LICENSE`]: https://github.com/unicode-org/icu4x/blob/main/LICENSE\n[`unicode-org/icu4x/utils/calendrical_calculations/src/persian.rs`]: https://github.com/unicode-org/icu4x/blob/main/utils/calendrical_calculations/src/persian.rs\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavoodeh%2Fjelal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavoodeh%2Fjelal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavoodeh%2Fjelal/lists"}