├── .commitlintrc.json ├── .editorconfig ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── SECURITY.md └── workflows │ ├── ci.yml │ └── release-please.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .prettierignore ├── .prettierrc ├── .release-please-manifest.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build.config.ts ├── codecov.yml ├── example.ts ├── jest.config.js ├── package-lock.json ├── package.json ├── release-please-config.json ├── src ├── NepaliDate.ts ├── constants.ts ├── dateConverter │ ├── constants.ts │ ├── dateConverter.ts │ └── index.ts ├── format │ ├── format.ts │ ├── formatEnglishDate.ts │ ├── index.ts │ └── tokenFormatters.ts ├── index.ts ├── parse │ ├── index.ts │ ├── parse.ts │ └── parseEnglishDate.ts ├── utils.ts └── validators.ts ├── tests ├── NepaliDate.test.ts ├── dateConverter │ └── dateConverter.test.ts ├── format │ ├── format.test.ts │ └── formatEnglishDate.test.ts ├── parse │ ├── parse.test.ts │ └── parseEnglishDate.test.ts └── utils.test.ts └── tsconfig.json /.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["@commitlint/config-conventional"] 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Use 4 spaces for indentation 12 | [*.{ts,js,json}] 13 | indent_style = space 14 | indent_size = 4 15 | 16 | # Do trim trailing whitespaces and remove UTF-8 byte order mark 17 | [*.{ts,js,json}] 18 | trim_trailing_whitespace = true 19 | charset = utf-8 20 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Introduction 4 | 5 | This document outlines the code of conduct for contributors, maintainers, and users of the "node-nepali-datetime" project. It aims to foster an inclusive and respectful community, promoting collaboration and positive interactions. By participating in this project, you are expected to adhere to this code of conduct. This code of conduct applies to all project-related spaces, including GitHub repositories, issue trackers, mailing lists, and social media platforms associated with the project. 6 | 7 | ## Our Pledge 8 | 9 | In the interest of fostering an open and welcoming environment, we, as contributors, maintainers, and users of the node-nepali-datetime project, pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual orientation. 10 | 11 | ## Expected Behavior 12 | 13 | To create a positive and inclusive environment, we expect all participants to: 14 | 15 | 1. Be respectful and considerate: Treat others with kindness, respect, and empathy, fostering a welcoming and collaborative atmosphere. 16 | 2. Be inclusive and supportive: Welcome individuals from all backgrounds, experiences, and perspectives, ensuring everyone feels valued and heard. 17 | 3. Be mindful of language and tone: Use inclusive language and avoid offensive or derogatory comments or personal attacks. 18 | 4. Be constructive: Provide constructive feedback, suggestions, and criticism in a respectful manner, with the aim of improving the project and fostering growth. 19 | 5. Be open-minded: Embrace diverse ideas, viewpoints, and approaches, encouraging healthy discussions and debates. 20 | 6. Be accountable: Take responsibility for your actions, acknowledge and learn from mistakes, and avoid repeating harmful behavior. 21 | 7. Respect project guidelines: Adhere to the project's technical guidelines, contribution guidelines, and licensing requirements. 22 | 23 | ## Unacceptable Behavior 24 | 25 | The following behaviors are considered unacceptable and will not be tolerated within the community: 26 | 27 | 1. Harassment and discrimination: Engaging in any form of harassment, discrimination, or exclusionary behavior, including but not limited to offensive comments, slurs, insults, derogatory remarks, or personal attacks. 28 | 2. Intimidation and threats: Intimidating or threatening behavior, both online and offline, towards any participant in the community. 29 | 3. Unwelcome advances: Making unwelcome sexual advances, inappropriate comments, or any other behavior of a sexual nature. 30 | 4. Spam and trolling: Posting irrelevant, repetitive, or disruptive content with the intention of annoying or provoking others. 31 | 5. Violation of privacy: Sharing personal or confidential information of others without their explicit consent. 32 | 6. Plagiarism and intellectual property infringement: Claiming the work of others as your own, including copying code or content without proper attribution or permission. 33 | 7. Violation of project guidelines: Repeatedly disregarding the project's technical guidelines, contribution guidelines, or licensing requirements. 34 | 35 | ## Reporting and Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainers at aj3sshh@gmail.com or sugatbajracharya49@gmail.com. All complaints will be reviewed and investigated promptly and fairly. The project maintainers are responsible for maintaining the confidentiality of the reporting individual(s). 38 | 39 | In the case of a verified violation of this code of conduct, appropriate actions will be taken, which may include: 40 | 41 | 1. Educating the individual(s) involved about the code of conduct and providing guidance on acceptable behavior. 42 | 2. Issuing warnings or temporary bans from project-related spaces. 43 | 3. Implementing permanent bans from project-related spaces for repeated or severe violations. 44 | 4. Reporting illegal behavior to relevant authorities if necessary. 45 | 46 | ## Attribution 47 | 48 | This code of conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html) and [Mozilla Community Participation Guidelines](https://www.mozilla.org/en-US/about/governance/policies/participation/). It is licensed under the Creative Commons Attribution 4.0 International License 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug, help wanted 6 | assignees: aj3sh, sugat009 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Please provide the steps to reproduce the issue. Include code snippets or specific examples if applicable. 14 | 15 | **Expected behavior** 16 | Please provide a clear and concise description of your expected outcome. 17 | 18 | **Environment** 19 | 20 | - npm/node version: 21 | - Package version: 22 | - Operating system: 23 | - Any other relevant information about your environment. 24 | 25 | **Additional context** 26 | Please provide any additional context or information that may be helpful in understanding and resolving the issue. This can include: 27 | 28 | - Error stack trace 29 | - Error messages 30 | - Log files 31 | - Screenshots 32 | - Any other relevant details related to the issue. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | **Use Case** 10 | Please describe the specific use case or scenario where this feature would be beneficial. 11 | 12 | **Proposed Solution** 13 | Please outline your proposed solution or approach for implementing this feature. Include any relevant details, such as code snippets or examples, if applicable. 14 | 15 | **Alternative Considered** 16 | Have you considered any alternative solutions or approaches? If so, please describe them and explain why you believe the proposed solution is the best option. 17 | 18 | **Dependencies** 19 | If this feature has any dependencies or requirements, please list them here. 20 | 21 | **Additional context** 22 | Add any other context or screenshots about the feature request here. 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | [Provide a brief description of the changes introduced by the pull request.] 4 | 5 | ## Related Issue 6 | 7 | [If your pull request is related to an existing issue, reference it here using the format "Fixes #issue_number".] 8 | 9 | ## Type of Change 10 | 11 | Please mark the appropriate option below to describe the type of change your pull request introduces: 12 | 13 | - [ ] Bug fix 14 | - [ ] New feature 15 | - [ ] Enhancement 16 | - [ ] Documentation update 17 | - [ ] Refactor 18 | - [ ] Other (please specify) 19 | 20 | ## Checklist 21 | 22 | - [ ] I have added/updated the necessary documentation on `README.md`. 23 | - [ ] I have added appropriate test cases (if applicable) to ensure the changes are functioning correctly. 24 | - [ ] My pull request has a clear title and description. 25 | 26 | ## Additional Notes 27 | 28 | [Add any additional notes or context that you think the reviewers should know about.] 29 | 30 | By submitting this pull request, I confirm that I have read and complied with the contribution guidelines of this project. 31 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | The 'node-nepali-datetime' project is committed to maintaining the security and integrity of our software. This Security Policy outlines the steps we take to address security vulnerabilities, as well as the responsibilities of our contributors and users in reporting and resolving security-related issues. 4 | 5 | ## Supported Versions 6 | 7 | We provide security updates and support for the latest stable release of the 'node-nepali-datetime' package. It is important to keep your software up to date to ensure you have the latest security patches. 8 | 9 | | Version | Supported | 10 | | --------------- | ------------------ | 11 | | 1.0.0 and above | :white_check_mark: | 12 | | 0.1.0 | :x: | 13 | 14 | ## Reporting a Vulnerability 15 | 16 | If you discover a security vulnerability within the project, we encourage you to report it the maintainers immediately. Promptly reporting security issues helps us protect our users and take appropriate actions to address the vulnerability. To report a security vulnerability, please follow these steps: 17 | 18 | 1. Email at aj3sshh@gmail.com or sugatbajracharya49@gmail.com with a detailed description of the vulnerability. Please include the following information: 19 | 20 | - Description of the vulnerability, including steps to reproduce if applicable 21 | - Version of the node-nepali-datetime package affected 22 | - Any potential mitigations or workarounds 23 | 24 | 2. Our security team will acknowledge your report within 3 to 7 days and provide further instructions and communication regarding the vulnerability. 25 | 26 | 3. We kindly request that you do not publicly disclose the vulnerability until we have had sufficient time to address it and provide a fix. We strive to resolve security vulnerabilities promptly and will work with you to coordinate disclosure if necessary. 27 | 28 | 4. Once the vulnerability is confirmed and addressed, we will release a security update in the form of a new package version. We will credit the reporter if desired. 29 | 30 | ## Security Updates and Mitigations 31 | 32 | Upon receiving a security vulnerability report, our team will evaluate the issue and take appropriate actions to address it. This may include: 33 | 34 | - Developing and testing a patch or fix for the vulnerability 35 | - Coordinating with the reporter or other relevant parties to verify the vulnerability and its impact 36 | - Releasing a new version that includes the necessary security fixes 37 | 38 | We strive to provide security updates in a timely manner and communicate any necessary steps for users to upgrade to the latest secure version. 39 | 40 | ## Responsible Disclosure 41 | 42 | We are committed to responsible disclosure of security vulnerabilities. Once a vulnerability has been addressed and a new package version is released, we encourage users and contributors to upgrade to the latest version to ensure they are protected. 43 | 44 | While we appreciate the efforts of security researchers and users who report vulnerabilities, we kindly request that you follow responsible disclosure practices by allowing us sufficient time to address the issue and release a fix before disclosing the vulnerability publicly. 45 | 46 | ## Disclaimer 47 | 48 | The node-nepali-datetime project is provided "as is," without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. In no event shall the package maintainers or contributors be liable for any claim, damages, or other liability arising from the use of the this node-nepali-datetime project or any security-related incidents. 49 | 50 | ## Contact 51 | 52 | For any questions, concerns, or additional information regarding the node-nepali-datetime project's security policy, please contact us at aj3sshh@gmail.com or sugatbajracharya49@gmail.com. 53 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs 3 | 4 | name: Github CI 5 | 6 | on: 7 | push: 8 | branches: ['main'] 9 | pull_request: 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | strategy: 16 | matrix: 17 | node-version: [18, 20, 22] 18 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - name: Conventional Commitlint 24 | uses: opensource-nepal/commitlint@v1 25 | with: 26 | verbose: true 27 | 28 | - name: Use Node.js ${{ matrix.node-version }} 29 | uses: actions/setup-node@v4 30 | with: 31 | node-version: ${{ matrix.node-version }} 32 | cache: 'npm' 33 | 34 | - name: Install dependencies 35 | run: npm ci 36 | 37 | - name: Build 38 | run: npm run build 39 | 40 | - name: Prettier check files 41 | run: npm run lint 42 | 43 | - name: Run tests and generate coverage 44 | run: npm run coverage 45 | 46 | - name: Send coverage reports to CodeCov 47 | uses: codecov/codecov-action@v4 48 | with: 49 | token: ${{ secrets.CODECOV_TOKEN }} 50 | fail_ci_if_error: false 51 | verbose: true 52 | -------------------------------------------------------------------------------- /.github/workflows/release-please.yml: -------------------------------------------------------------------------------- 1 | name: 'Release Please' 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | permissions: 9 | contents: write 10 | pull-requests: write 11 | 12 | jobs: 13 | release-please: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: googleapis/release-please-action@v4 17 | id: release 18 | with: 19 | # NOTE: GITHUB_TOKEN doesn't run checks on Release PR 20 | token: ${{ secrets.GITHUB_TOKEN }} 21 | 22 | # The logic below handles the npm publication: 23 | - uses: actions/checkout@v4 24 | # these if statements ensure that a publication only occurs when 25 | # a new release is created: 26 | if: ${{ steps.release.outputs.release_created }} 27 | 28 | - name: Setup node 29 | uses: actions/setup-node@v4 30 | with: 31 | node-version: 22 32 | registry-url: 'https://registry.npmjs.org' 33 | if: ${{ steps.release.outputs.release_created }} 34 | 35 | - name: Install Dependencies 36 | run: npm ci 37 | if: ${{ steps.release.outputs.release_created }} 38 | 39 | - name: Build 40 | run: npm run build 41 | if: ${{ steps.release.outputs.release_created }} 42 | 43 | - name: Publish to NPM 44 | run: npm publish --access public 45 | env: 46 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 47 | if: ${{ steps.release.outputs.release_created }} 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (https://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules/ 31 | jspm_packages/ 32 | 33 | # TypeScript v1 declaration files 34 | typings/ 35 | 36 | # Optional npm cache directory 37 | .npm 38 | 39 | # Optional eslint cache 40 | .eslintcache 41 | 42 | # Optional REPL history 43 | .node_repl_history 44 | 45 | # Output of 'npm pack' 46 | *.tgz 47 | 48 | # Yarn Integrity file 49 | .yarn-integrity 50 | 51 | # dotenv environment variables file 52 | .env 53 | 54 | 55 | #Build files and Others 56 | /lib 57 | /coverage 58 | dist/ 59 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | npx --no-install commitlint --edit $1 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | npm run test 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | CHANGELOG.md 3 | .release-please-manifest.json 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "bracketSpacing": true, 4 | "endOfLine": "auto", 5 | "printWidth": 88, 6 | "semi": false, 7 | "singleQuote": true, 8 | "trailingComma": "es5", 9 | "tabWidth": 4, 10 | "useTabs": false 11 | } 12 | -------------------------------------------------------------------------------- /.release-please-manifest.json: -------------------------------------------------------------------------------- 1 | {".":"1.4.1"} 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## [1.4.1](https://github.com/opensource-nepal/node-nepali-datetime/compare/v1.4.0...v1.4.1) (2025-04-08) 4 | 5 | 6 | ### Bug Fixes 7 | 8 | * update months data for year 2082 ([4dfd5d1](https://github.com/opensource-nepal/node-nepali-datetime/commit/4dfd5d12931e54e1cd60aaa21f236caa32f67c9d)) 9 | * update months data for year 2082 ([c927ade](https://github.com/opensource-nepal/node-nepali-datetime/commit/c927ade22dbadc1a4ec638863ce8893db2c8cb2b)) 10 | 11 | ## [1.4.0](https://github.com/opensource-nepal/node-nepali-datetime/compare/v1.3.0...v1.4.0) (2024-12-25) 12 | 13 | 14 | ### Features 15 | 16 | * add static method `getDaysOfMonth` on NepaliDate ([#96](https://github.com/opensource-nepal/node-nepali-datetime/issues/96)) ([c85edfa](https://github.com/opensource-nepal/node-nepali-datetime/commit/c85edfa4d40f93061674f6143f6343b23a653bc0)) 17 | * add static methods for min and max supported dates ([#102](https://github.com/opensource-nepal/node-nepali-datetime/issues/102)) ([6b13079](https://github.com/opensource-nepal/node-nepali-datetime/commit/6b130794cbaad396e7e4a648163a346de0f6cdbb)) 18 | * add support for node 22 and remove 16 ([#101](https://github.com/opensource-nepal/node-nepali-datetime/issues/101)) ([3254f8d](https://github.com/opensource-nepal/node-nepali-datetime/commit/3254f8de6b384c4078117949feb51b3c2a93900d)) 19 | 20 | 21 | ### Bug Fixes 22 | 23 | * update nepali months data ([#103](https://github.com/opensource-nepal/node-nepali-datetime/issues/103)) ([b19d135](https://github.com/opensource-nepal/node-nepali-datetime/commit/b19d135f0a7a610a2858e230924b4420cc70f1f9)) 24 | 25 | ## [1.3.0](https://github.com/opensource-nepal/node-nepali-datetime/compare/v1.2.1...v1.3.0) (2024-11-30) 26 | 27 | 28 | ### Features 29 | 30 | * add method `formatEnglishDate` and `formatEnglishDateInNepali` ([#94](https://github.com/opensource-nepal/node-nepali-datetime/issues/94)) ([6cf9d14](https://github.com/opensource-nepal/node-nepali-datetime/commit/6cf9d142e5193e246b546f8599411efbf4e2a014)) 31 | * add method `parseEnglishDate` for English date parsing ([#95](https://github.com/opensource-nepal/node-nepali-datetime/issues/95)) ([aeabb8d](https://github.com/opensource-nepal/node-nepali-datetime/commit/aeabb8dde4903114b19010cfee25b0a61a4fc227)) 32 | * **ci:** add prettier check on ci ([a728ed4](https://github.com/opensource-nepal/node-nepali-datetime/commit/a728ed48477139eb3417e0e52ead16c23be8e9ff)) 33 | 34 | ## [1.2.1](https://github.com/opensource-nepal/node-nepali-datetime/compare/v1.2.0...v1.2.1) (2024-03-06) 35 | 36 | 37 | ### Bug Fixes 38 | 39 | * updated months data for 2081 ([a49b3d6](https://github.com/opensource-nepal/node-nepali-datetime/commit/a49b3d679bcddfdbfc9c5bcf28826ccfedc3a7b9)) 40 | 41 | ## [1.2.0](https://github.com/opensource-nepal/node-nepali-datetime/compare/v1.1.2...v1.2.0) (2023-11-16) 42 | 43 | 44 | ### Features 45 | 46 | * reduced package bundle size ([d15e575](https://github.com/opensource-nepal/node-nepali-datetime/commit/d15e5750ffdebce5233b0476e95c3db1cc7311e6)) 47 | 48 | ## [1.1.2](https://github.com/opensource-nepal/node-nepali-datetime/compare/v1.1.1...v1.1.2) (2023-10-03) 49 | 50 | 51 | ### Bug Fixes 52 | 53 | * fixed AM/PM formatting issue of noon ([57091bc](https://github.com/opensource-nepal/node-nepali-datetime/commit/57091bc817f275e07627a0388382f7402f44baff)) 54 | 55 | ## 1.1.1 56 | 57 | - Updated NepaliDate members to private. 58 | - Fixed type resolve issue. (#59, #60) 59 | 60 | ## 1.1.0 - (August 17, 2023) 61 | 62 | - Added husky for running pre-commit hook. 63 | - Run npm test on pre-commit hook. 64 | - Added formatting on pre-commit hook. 65 | - Refactored formatting. 66 | - Added parse feature in a given format. 67 | 68 | ## v1.0.1 - (July 14, 2023) 69 | 70 | - Added dateConverter module. 71 | - Added time/timezone support in NepaliDate. 72 | - Updated new formatting methods and added time formatting (with moment.js format reference). Added `formatNepali` method. 73 | - Supported parse for date and time string on `NepaliDate` constructor. 74 | - Renamed method `getEnglishDate` to `getDateObject`. 75 | - Added methods for Nepali year, month, date of English calendar. 76 | - Added `fromEnglishDate` static method for initializing from English calendar date parameters. 77 | - Updated `toString` format of NepaliDate. 78 | 79 | ## v0.1.0 - (May 15, 2023) 80 | 81 | - Initial release with the features included in 'nepali-date'. 82 | - Typescript support. 83 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guide 2 | 3 | Thank you for your interest in contributing to the **node-nepali-datetime** project! 4 | Your contributions will help improve and enhance this library. 5 | Please take a moment to review the following guidelines before getting started. 6 | 7 | ## Prerequisites 8 | 9 | Before contributing, ensure that you have the following: 10 | 11 | - **Node.js v18 or higher** installed. Download it from the [official Node.js website](https://nodejs.org/) 12 | or use `nvm` to manage multiple Node.js versions. 13 | - **npm** installed (comes with Node.js). 14 | 15 | ## Getting Started 16 | 17 | To set up the project on your local machine, follow these steps: 18 | 19 | 1. **Fork** the repository on GitHub. 20 | 2. **Clone** the forked repository to your local machine: 21 | 22 | ```bash 23 | git clone https://github.com//node-nepali-datetime.git 24 | cd node-nepali-datetime 25 | ``` 26 | 27 | 3. **Install dependencies**: 28 | 29 | ```bash 30 | npm install 31 | ``` 32 | 33 | 4. **Verify your setup**: 34 | 35 | - Run the example script to test the library: 36 | 37 | ```bash 38 | npm run example 39 | ``` 40 | 41 | Modify the [example.ts](./example.ts) file to experiment with your example code. 42 | 43 | - Run lint checks: 44 | 45 | ```bash 46 | npm run lint 47 | ``` 48 | 49 | - Run tests to ensure everything works: 50 | 51 | ```bash 52 | npm run test 53 | ``` 54 | 55 | 5. **Start contributing** by making the necessary changes to the codebase. 56 | 57 | ## Code Style 58 | 59 | - A **Prettier** configuration file ([`.prettierrc`](./.prettierrc)) is provided to maintain a consistent coding style. 60 | - Pre-commit hooks will automatically format your code before committing. Ensure that your code passes lint checks. 61 | 62 | ## Pull Requests 63 | 64 | We welcome and appreciate pull requests from the community. To contribute: 65 | 66 | 1. **Fork** the repository and create a new branch based on the `main` branch: 67 | 68 | ```bash 69 | git checkout -b 70 | ``` 71 | 72 | 2. **Write tests** for your changes if applicable. 73 | 3. **Follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)** for commit messages. 74 | Examples: 75 | 76 | - `feat: add JSON parser` 77 | - `fix(parser): resolve parsing issue` 78 | 79 | 4. **Push** your branch to your forked repository: 80 | 81 | ```bash 82 | git push origin 83 | ``` 84 | 85 | 5. **Create a Pull Request**: 86 | 87 | - Open a pull request from your branch to the `main` branch of the original repository. 88 | - Provide a clear and concise description of the changes, along with relevant context. 89 | 90 | 6. **Review & Feedback**: 91 | 92 | - Participate in the code review process and address any feedback promptly. 93 | 94 | ## License 95 | 96 | By contributing to this project, you agree that your contributions will be licensed under the **GPL-3.0 License**. 97 | Refer to the [LICENSE](./LICENSE) file for more details. 98 | 99 | ## Other Ways to Contribute 100 | 101 | Even if you don’t contribute code, you can still help: 102 | 103 | - **Spread the word** about this library. 104 | - Write a blog or article about how you use this project. 105 | - Share your best practices, examples, or ideas with us. 106 | 107 | Thank you for contributing to **node-nepali-datetime**! 🎉 108 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nepali-datetime 2 | 3 | [![npm version](https://img.shields.io/npm/v/nepali-datetime?color=48c21a)](https://www.npmjs.com/package/nepali-datetime) 4 | [![Github CI](https://github.com/opensource-nepal/node-nepali-datetime/actions/workflows/ci.yml/badge.svg)](https://github.com/opensource-nepal/node-nepali-datetime/actions/workflows/ci.yml) 5 | [![Downloads](https://img.shields.io/npm/dm/nepali-datetime?maxAge=180)](https://www.npmjs.com/package/nepali-datetime) 6 | [![codecov](https://codecov.io/gh/opensource-nepal/node-nepali-datetime/branch/main/graph/badge.svg?token=KAKOA8A036)](https://codecov.io/gh/opensource-nepal/node-nepali-datetime) 7 | [![License](https://img.shields.io/npm/l/nepali-datetime?label=License)](https://github.com/opensource-nepal/node-nepali-datetime/blob/main/LICENSE) 8 | 9 | nepali-datetime is a Node.js package designed to provide native JavaScript-like features for Nepali dates. It includes the 'NepaliDate' class for Nepali date support and the 'dateConverter' module for date conversion. 10 | 11 | ## Examples 12 | 13 | Here are a few examples to get you started: 14 | 15 | ```javascript 16 | import NepaliDate from 'nepali-datetime' 17 | 18 | // Create a NepaliDate object for the current date and time 19 | const now = new NepaliDate() 20 | console.log(now.toString()) // 2080-03-23 15:32:03.643 21 | 22 | // Create a NepaliDate object from a Nepali date string 23 | const date1 = new NepaliDate('2079-02-15 23:11') 24 | console.log(date1.toString()) // 2079-02-15 23:11:00 25 | 26 | // Parse Nepali date string 27 | const date2 = new NepaliDate('Baisakh 18, 2080', 'MMMM D, YYYY') 28 | console.log(date2.toString()) // 2080-01-18 00:00:00 29 | 30 | // Format a NepaliDate object 31 | const formattedDate = now.format('YYYY-MM-DD') 32 | console.log(formattedDate) // 2080-03-23 33 | 34 | // Create a NepaliDate object from an English date string 35 | const date3 = NepaliDate.parseEnglishDate('2023-07-08', 'YYYY-MM-DD') 36 | console.log(date3.toString()) // 2080-03-23 00:00:00 37 | ``` 38 | 39 | ## Installation 40 | 41 | To install nepali-datetime, you can use npm or yarn: 42 | 43 | ```shell 44 | npm install nepali-datetime 45 | ``` 46 | 47 | or 48 | 49 | ```shell 50 | yarn add nepali-datetime 51 | ``` 52 | 53 | ## Usage 54 | 55 | ### NepaliDate 56 | 57 | The `NepaliDate` class represents a Nepali calendar date. It provides various methods and properties to work with Nepali dates. 58 | 59 | #### Creating a NepaliDate object 60 | 61 | You can create a `NepaliDate` object in several ways: 62 | 63 | - Without any parameters: Creates a `NepaliDate` object for the current date and time. 64 | 65 | ```javascript 66 | import NepaliDate from 'nepali-datetime' 67 | 68 | const now = new NepaliDate() 69 | ``` 70 | 71 | - Using a Nepali date string: Parses the string as a Nepali calendar date. 72 | 73 | ```javascript 74 | const date1 = new NepaliDate('2079-02-15') 75 | const date2 = new NepaliDate('2079-02-15 14:00') 76 | ``` 77 | 78 | - Using a Unix timestamp (in milliseconds): 79 | 80 | ```javascript 81 | const date2 = new NepaliDate(1654210800000) 82 | ``` 83 | 84 | - Using a JavaScript `Date` object: Converts the JavaScript `Date` object to a `NepaliDate` object. 85 | 86 | ```javascript 87 | const jsDate = new Date() 88 | const date3 = new NepaliDate(jsDate) 89 | ``` 90 | 91 | - Using an existing `NepaliDate` object: Creates a new `NepaliDate` object with the same values. 92 | 93 | ```javascript 94 | const date4 = new NepaliDate(date3) 95 | ``` 96 | 97 | - Using Nepali calendar date and time parameters: Specifies the components of a Nepali calendar date. 98 | 99 | ```javascript 100 | const date5 = new NepaliDate(year, month, date, hour, minute, second, ms) 101 | const date6 = new NepaliDate(2079, 2, 15, 10, 30) 102 | ``` 103 | 104 | #### Getting the Nepali date components 105 | 106 | You can retrieve various components of a `NepaliDate` object using the following methods: 107 | 108 | - `getDateObject()`: Retrieves the Javascript Date object equivalent to the NepaliDate. 109 | - `getTime()`: Retrieves the Unix timestamp (in milliseconds) of the Nepali date. 110 | - `getYear()`: Retrieves the year of the Nepali date in the Nepali calendar. 111 | - `getEnglishYear()`: Retrieves the year of the Nepali date in the English calendar. 112 | - `getMonth()`: Retrieves the month of the Nepali date in the Nepali calendar. 113 | - `getEnglishMonth()`: Retrieves the month of the Nepali date in the English calendar. 114 | - `getDate()`: Retrieves the day of the month of the Nepali date in the Nepali calendar. 115 | - `getEnglishDate()`: Retrieves the day of the month of the Nepali date in the English calendar. 116 | - `getDay()`: Retrieves the day of the week represented by a numeric value. 117 | - `getHours()`: Retrieves the hour value of the Nepali date. 118 | - `getMinutes()`: Retrieves the minute value of the Nepali date. 119 | - `getSeconds()`: Retrieves the second value of the Nepali date. 120 | - `getMilliseconds()`: Retrieves the millisecond value of the Nepali date. 121 | 122 | #### Setting the Nepali date components 123 | 124 | You can set individual components of a `NepaliDate` object using the following methods: 125 | 126 | - `setYear(year)`: Sets the year of the Nepali date. 127 | - `setMonth(month)`: Sets the month of the Nepali date. 128 | - `setDate(day)`: Sets the day of the month of the Nepali date. 129 | - `setHours(hour)`: Sets the hour of the Nepali date. 130 | - `setMinutes(minute)`: Sets the minute of the Nepali date. 131 | - `setSeconds(second)`: Sets the second of the Nepali date. 132 | - `setMilliseconds(ms)`: Sets the millisecond of the Nepali date. 133 | - `setTime(time)`: Sets the Nepali date and time values using a Unix timestamp. 134 | 135 | #### Formatting the Nepali date 136 | 137 | You can format a `NepaliDate` object as a string using the `format()` and `formatNepali()` methods. 138 | Additionally, you can convert the corresponding English date to a string using the `formatEnglishDate()` and `formatEnglishDateInNepali()` methods. 139 | 140 | - `format(formatStr)`: Returns a string representation (in English) of the `NepaliDate` object in the specified format. 141 | - `formatNepali(formatStr)`: Returns a string representation in the Nepali (Devanagari script) of the `NepaliDate` object in the specified format. 142 | - `formatEnglishDate(formatStr)`: Returns a string representation (in English) of the English Date in the specified format. 143 | - `formatEnglishDateInNepali(formatStr)`: Returns a string representation in the Nepali (Devanagari script) of the English Date in the specified format. 144 | 145 | ```javascript 146 | const date = new NepaliDate(2079, 5, 3, 16, 14) 147 | console.log(date.format('YYYY-MM-DD hh:mm A')) // 2079-06-03 04:14 PM 148 | console.log(date.formatEnglishDate('YYYY-MM-DD hh:mm A')) // 2022-09-19 04:14 PM 149 | ``` 150 | 151 | The date formatting will follow the format codes mentioned below, which are similar to the date formats used in day.js. 152 | 153 | | Format Token | Description | Example | 154 | | ------------ | --------------------------------- | -------- | 155 | | YYYY | 4-digit year | 2023 | 156 | | YY | 2-digit year | 23 | 157 | | MMMM | Full month name | Baisakh | 158 | | MMM | Abbreviated month name | Bai | 159 | | MM | 2-digit month | 01-12 | 160 | | M | Month number, beginning at 1 | 1-12 | 161 | | DD | 2-digit day of the month | 01-31 | 162 | | D | Day of the month | 1-31 | 163 | | dddd | Full day of the week | Monday | 164 | | ddd | Abbreviated day of the week | Mon | 165 | | d | Day of the week, with Sunday as 0 | 0-6 | 166 | | HH | 2-digit hour (24-hour format) | 00-23 | 167 | | H | Hour (24-hour format) | 0-23 | 168 | | hh | 2-digit hour (12-hour format) | 01-12 | 169 | | h | Hour (12-hour format) | 1-12 | 170 | | mm | 2-digit minutes | 00-59 | 171 | | m | Minutes | 0-59 | 172 | | ss | 2-digit seconds | 00-59 | 173 | | s | Seconds | 0-59 | 174 | | SSS | 3-digit milliseconds | 000-999 | 175 | | A | Uppercase AM/PM | AM or PM | 176 | | a | Lowercase am/pm | am or pm | 177 | 178 | Any other character will be printed as it is. If you need to print the special characters (YMDmd), please enclose them within square brackets. Example: `.format("[YMDmd]")` 179 | 180 | For the list of month names and their abbreviations, you can refer to the table below. 181 | 182 | | Value of Month | Abbreviation | Full Name | 183 | | -------------- | ------------ | --------- | 184 | | 0 | Bai | Baisakh | 185 | | 1 | Jes | Jestha | 186 | | 2 | Asa | Asar | 187 | | 3 | Shr | Shrawan | 188 | | 4 | Bhd | Bhadra | 189 | | 5 | Asw | Aswin | 190 | | 6 | Kar | Kartik | 191 | | 7 | Man | Mangsir | 192 | | 8 | Pou | Poush | 193 | | 9 | Mag | Magh | 194 | | 10 | Fal | Falgun | 195 | | 11 | Cha | Chaitra | 196 | 197 | #### Converting to JavaScript Date object 198 | 199 | You can get the equivalent JavaScript `Date` object of a `NepaliDate` object using the `getDateObject()` method. 200 | 201 | ```javascript 202 | const now = new NepaliDate(2079, 5, 3) 203 | console.log(now.getDateObject()) // Date 2022-09-18T18:15:00.000Z 204 | ``` 205 | 206 | #### Creating a NepaliDate object from an English date 207 | 208 | You can create a `NepaliDate` object from an English calendar date using the `parseEnglishDate` or `fromEnglishDate` method. 209 | 210 | ```javascript 211 | const date1 = NepaliDate.parseEnglishDate('2023-07-08', 'YYYY-MM-DD') 212 | console.log(date1.toString()) // 2080-03-23 00:00:00 213 | 214 | const date2 = NepaliDate.fromEnglishDate(2023, 6, 8, 10, 15) 215 | console.log(date2.toString()) // 2080-03-23 10:15:00 216 | ``` 217 | 218 | #### Others 219 | 220 | - `NepaliDate.getDaysOfMonth(year, month)`: Returns the number of days in a specific month of a given year. 221 | - `NepaliDate.minSupportedDate()`: Returns the minimum supported JS Date object. 222 | - `NepaliDate.maxSupportedDate()`: Returns the maximum supported JS Date object. 223 | - `NepaliDate.minSupportedNepaliDate()`: Returns the minimum supported Nepali object. 224 | - `NepaliDate.maxSupportedNepaliDate()`: Returns the maximum supported Nepali object. 225 | 226 | ### dateConverter 227 | 228 | The `dateConverter` module provides core functions for converting dates between the Nepali and English calendars. 229 | 230 | - `englishToNepali(year, month, day)`: Converts an English calendar date to a Nepali calendar date. Returns an array `[npYear, npMonth, npDay]` representing the Nepali date. 231 | - `nepaliToEnglish(year, month, day)`: Converts a Nepali calendar date to an English calendar date. Returns an array `[enYear, enYear, enDay]` representing the English date. 232 | 233 | > Note: Use 0 as the value for the months Baisakh and January (Javascript Logic 🤷). 234 | 235 | ```javascript 236 | import dateConverter from 'nepali-datetime/dateConverter' 237 | 238 | // english to nepali date conversion 239 | const [npYear, npMonth, npDay] = dateConverter.englishToNepali(2023, 5, 27) 240 | 241 | // nepali to english date conversion 242 | const [enYear, enMonth, enDay] = dateConverter.nepaliToEnglish(2080, 2, 15) 243 | ``` 244 | 245 | #### Quick Date conversion using NepaliDate 246 | 247 | The `NepaliDate` class can also be used for direct string-to-string date conversions, eliminating the need for custom parsing or formatting logic. 248 | 249 | **English Date to Nepali Date** 250 | 251 | ```javascript 252 | const enDate = '2024-11-25' 253 | const npDate = NepaliDate.parseEnglishDate(enDate, 'YYYY-MM-DD').format('YYYY-MM-DD') 254 | // 2081-08-10 255 | ``` 256 | 257 | **Nepali Date to English Date** 258 | 259 | ```javascript 260 | const npDate = '2081-08-10' 261 | const enDate = new NepaliDate(npDate).formatEnglishDate('YYYY-MM-DD') 262 | // 2024-11-25 263 | ``` 264 | 265 | ## Acknowledgements 266 | 267 | This project was inspired by [nepali-date](https://github.com/sharingapples/nepali-date). We would like to express our gratitude to their team for their excellent work and ideas, which served as a motivation for this project. 268 | 269 | ## Contribution 270 | 271 | We appreciate feedback and contribution to this package. To get started please see our [contribution guide](CONTRIBUTING.md). 272 | -------------------------------------------------------------------------------- /build.config.ts: -------------------------------------------------------------------------------- 1 | import { defineBuildConfig } from 'unbuild' 2 | 3 | export default defineBuildConfig({ 4 | entries: ['src/index', 'src/dateConverter/index'], 5 | declaration: true, 6 | clean: true, 7 | sourcemap: false, 8 | rollup: { 9 | emitCJS: true, 10 | esbuild: { 11 | minify: true, 12 | }, 13 | }, 14 | }) 15 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | # This files contains codecov configurations. 2 | 3 | # Disabling comments 4 | comment: false 5 | github_checks: false 6 | coverage: 7 | status: 8 | project: off 9 | patch: off 10 | -------------------------------------------------------------------------------- /example.ts: -------------------------------------------------------------------------------- 1 | import NepaliDate from './src/NepaliDate' 2 | 3 | console.log('node-nepali-datetime') 4 | 5 | // Now 6 | const now = new NepaliDate() 7 | console.log('Now:', now.toString()) 8 | 9 | // Try your example codes here 10 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'node', 4 | transform: { 5 | '^.+\\.ts?$': 'ts-jest', 6 | }, 7 | transformIgnorePatterns: ['/node_modules/'], 8 | testPathIgnorePatterns: [], 9 | } 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nepali-datetime", 3 | "version": "1.4.1", 4 | "description": "A Node project designed to support native JavaScript-like features for Nepali dates. It includes features such as 'NepaliDate' for Nepali date support and 'dateConverter' for date conversions.", 5 | "exports": { 6 | ".": { 7 | "types": "./dist/index.d.ts", 8 | "import": "./dist/index.mjs", 9 | "require": "./dist/index.cjs" 10 | }, 11 | "./dateConverter": { 12 | "types": "./dist/dateConverter/index.d.ts", 13 | "import": "./dist/dateConverter/index.mjs", 14 | "require": "./dist/dateConverter/index.cjs" 15 | } 16 | }, 17 | "main": "./dist/index.mjs", 18 | "module": "./dist/index.mjs", 19 | "types": "./dist/index.d.ts", 20 | "files": [ 21 | "dist" 22 | ], 23 | "keywords": [ 24 | "javascript", 25 | "typescript", 26 | "node", 27 | "nepal", 28 | "nepali", 29 | "nepali-date", 30 | "nepali-date-converter", 31 | "nepali-time", 32 | "nepali-timezone", 33 | "date-converter", 34 | "calendar", 35 | "ad-bs", 36 | "ad-to-bs", 37 | "bs-ad", 38 | "bs-to-ad", 39 | "AD to BS", 40 | "BS to AD" 41 | ], 42 | "scripts": { 43 | "build": "unbuild", 44 | "test": "jest", 45 | "coverage": "jest --coverage", 46 | "prepare": "husky && npm run build", 47 | "lint": "prettier --check .", 48 | "format": "prettier --write .", 49 | "example": "ts-node example.ts" 50 | }, 51 | "lint-staged": { 52 | "*": "prettier --ignore-unknown --write" 53 | }, 54 | "repository": { 55 | "url": "https://github.com/opensource-nepal/node-nepali-datetime.git", 56 | "type": "git" 57 | }, 58 | "author": "OpenSource Nepal", 59 | "license": "GPL-3.0", 60 | "devDependencies": { 61 | "@commitlint/cli": "^19.6.1", 62 | "@commitlint/config-conventional": "^19.6.0", 63 | "@types/jest": "^29.5.4", 64 | "@types/node": "^22.10.2", 65 | "husky": "^9.1.7", 66 | "jest": "^29.7.0", 67 | "lint-staged": "^15.2.11", 68 | "prettier": "^3.4.2", 69 | "ts-jest": "^29.2.5", 70 | "ts-node": "^10.9.2", 71 | "tslib": "^2.8.1", 72 | "typescript": "^5.7.2", 73 | "unbuild": "^3.0.1" 74 | }, 75 | "engines": { 76 | "node": ">=18" 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /release-please-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", 3 | "include-component-in-tag": false, 4 | "packages": { 5 | ".": {} 6 | }, 7 | "pull-request-header": "Release PR", 8 | "pull-request-title-pattern": "chore: release v${version}", 9 | "release-type": "node" 10 | } 11 | -------------------------------------------------------------------------------- /src/NepaliDate.ts: -------------------------------------------------------------------------------- 1 | import dateConverter from './dateConverter' 2 | import { NP_MONTHS_DATA } from './dateConverter/constants' 3 | import { 4 | format, 5 | formatEnglishDate, 6 | formatEnglishDateInNepali, 7 | formatNepali, 8 | nepaliDateToString, 9 | } from './format' 10 | 11 | import { parse, parseFormat, parseEnglishDateFormat } from './parse' 12 | import { getDate, getNepalDateAndTime } from './utils' 13 | import { validateTime } from './validators' 14 | 15 | /** 16 | * Represents a Nepali calendar date. 17 | */ 18 | class NepaliDate { 19 | private timestamp: Date 20 | private year: number 21 | private yearEn: number 22 | private month: number 23 | private monthEn: number 24 | private day: number 25 | private dayEn: number 26 | private hour: number 27 | private minute: number 28 | private weekDay: number 29 | 30 | /** 31 | * Creates a NepaliDate instance for the current date and time. 32 | * 33 | * @example 34 | * const now = new NepaliDate() 35 | */ 36 | constructor() 37 | 38 | /** 39 | * Creates a NepaliDate instance from a provided Javascript Date object. 40 | * 41 | * @param {Date} date - The Javascript Date object. 42 | * 43 | * @example 44 | * const jsDate = new Date("2020-01-01") 45 | * const nepaliDate = new NepaliDate(jsDate) 46 | */ 47 | constructor(date: Date) 48 | 49 | /** 50 | * Creates a new NepaliDate instance from another NepaliDate object. 51 | * 52 | * @param {NepaliDate} date - The NepaliDate object. 53 | * @example 54 | * const nepaliDateOld = new NepaliDate('2080-01-01') 55 | * const nepaliDate = new NepaliDate(nepaliDateOld) 56 | */ 57 | constructor(date: NepaliDate) 58 | 59 | /** 60 | * Creates a NepaliDate instance by parsing a provided date-time string. 61 | * 62 | * @param {string} value - The date-time string. 63 | * @example 64 | * const nepaliDate = new NepaliDate('2080-01-01') 65 | */ 66 | constructor(value: string) 67 | 68 | /** 69 | * Creates a NepaliDate instance from a provided Unix timestamp. 70 | * 71 | * @param {number} value - The Unix timestamp. 72 | * @example 73 | * const timestamp = 1695569762 // Unix timestamp in milliseconds 74 | * const nepaliDate = new NepaliDate(timestamp) 75 | */ 76 | constructor(value: number) 77 | 78 | /** 79 | * Creates a NepaliDate instance by parsing a provided date-time string 80 | * with the given format. 81 | * 82 | * @param dateString - The date-time string to parse. 83 | * @param format - The format of the provided date-time string. 84 | * @example 85 | * const dateTimeString = '2080/08/12 14-05-23.789' 86 | * const format = 'YYYY/MM/DD HH-mm-ss.SSS' 87 | * const nepaliDate = new NepaliDate(dateTimeString, format) 88 | */ 89 | constructor(dateString: string, format: string) 90 | 91 | /** 92 | * Creates a NepaliDate instance from a provided Nepali calendar date components. 93 | * 94 | * @constructor 95 | * @param {number} year - The year (e.g., 2080). 96 | * @param {number} month - The month (0-11, where 0 is Baisakh and 11 is Chaitra). 97 | * @param {number} [day=1] - The day of the month (1-31). 98 | * @param {number} [hour=0] - The hour of the day (0-23). 99 | * @param {number} [minute=0] - The minute (0-59). 100 | * @param {number} [second=0] - The second (0-59). 101 | * @param {number} [ms=0] - The milliseconds (0-999). 102 | * 103 | * @example 104 | * const year = 2080 105 | * const month = 1 // Jestha 106 | * const day = 12 107 | * const hour = 12 108 | * const minute = 30 109 | * const second = 45 110 | * const ms = 500 111 | * const nepaliDate = new NepaliDate(year, month, day, hour, minute, second, ms) 112 | */ 113 | constructor( 114 | year: number, 115 | month: number, 116 | day?: number, 117 | hour?: number, 118 | minute?: number, 119 | second?: number, 120 | ms?: number 121 | ) 122 | constructor(...args: any[]) { 123 | if (args.length === 0) { 124 | this.initFromCurrentDate() 125 | } else if (args.length === 1 && args[0] instanceof Date) { 126 | this.initFromEnglishDate(args[0]) 127 | } else if (args.length === 1 && args[0] instanceof NepaliDate) { 128 | this.initFromNepaliDate(args[0]) 129 | } else if (args.length === 1 && typeof args[0] === 'string') { 130 | this.parseFromString(args[0]) 131 | } else if (args.length === 1 && typeof args[0] === 'number') { 132 | this.initFromTimestamp(args[0]) 133 | } else if ( 134 | args.length === 2 && 135 | typeof args[0] === 'string' && 136 | typeof args[1] === 'string' 137 | ) { 138 | this.parseFromStringWithFormat(args[0], args[1]) 139 | } else if ( 140 | args.length >= 2 && 141 | args.length <= 8 && 142 | args.every(arg => typeof arg === 'number') 143 | ) { 144 | this.initFromComponents(args) 145 | } else { 146 | throw new Error('Invalid date argument') 147 | } 148 | } 149 | 150 | /* Object initialization */ 151 | 152 | private initFromCurrentDate() { 153 | this._setDateObject(new Date()) 154 | } 155 | 156 | private initFromEnglishDate(date: Date) { 157 | this._setDateObject(date) 158 | } 159 | 160 | private initFromNepaliDate(date: NepaliDate) { 161 | this.set( 162 | date.year, 163 | date.month, 164 | date.day, 165 | date.hour, 166 | date.minute, 167 | date.getSeconds(), 168 | date.getMilliseconds() 169 | ) 170 | } 171 | 172 | private parseFromString(value: string) { 173 | const parsedResult = parse(value) 174 | this.set( 175 | parsedResult[0], // Year 176 | parsedResult[1], // Month 177 | parsedResult[2], // Date 178 | parsedResult[3], // Hour 179 | parsedResult[4], // Minute 180 | parsedResult[5], // Second 181 | parsedResult[6] // Millisecond 182 | ) 183 | } 184 | 185 | private initFromTimestamp(value: number) { 186 | this._setDateObject(new Date(value)) 187 | } 188 | 189 | private parseFromStringWithFormat(dateString: string, format: string) { 190 | const parsedResult = parseFormat(dateString, format) 191 | this.set( 192 | parsedResult[0], // Year 193 | parsedResult[1], // Month 194 | parsedResult[2], // Date 195 | parsedResult[3], // Hour 196 | parsedResult[4], // Minute 197 | parsedResult[5], // Second 198 | parsedResult[6] // Millisecond 199 | ) 200 | } 201 | 202 | private initFromComponents(args: number[]) { 203 | this.set( 204 | args[0], // year 205 | args[1], // month 206 | args[2] ?? 1, // day 207 | args[3] ?? 0, // hour 208 | args[4] ?? 0, // minute 209 | args[5] ?? 0, // second 210 | args[6] ?? 0 // ms 211 | ) 212 | } 213 | 214 | /* Object methods */ 215 | 216 | /** 217 | * Sets the English date and optionally computes the corresponding Nepali date. 218 | * Handles all the operations and variables while setting the English date. 219 | * 220 | * @param date The English date to set. 221 | * @param computeNepaliDate Flag indicating whether to compute the Nepali date. Default is `true`. 222 | * @returns void 223 | */ 224 | private _setDateObject(date: Date, computeNepaliDate: boolean = true) { 225 | this.timestamp = date 226 | 227 | // getting Nepal's hour, minute, and weekDay 228 | const { year, month0, day, hour, minute, weekDay } = getNepalDateAndTime(date) 229 | this.yearEn = year 230 | this.monthEn = month0 231 | this.dayEn = day 232 | this.hour = hour 233 | this.minute = minute 234 | this.weekDay = weekDay 235 | 236 | if (computeNepaliDate) { 237 | const [yearNp, month0Np, dayNp] = dateConverter.englishToNepali( 238 | year, 239 | month0, 240 | day 241 | ) 242 | this.year = yearNp 243 | this.month = month0Np 244 | this.day = dayNp 245 | } 246 | } 247 | 248 | /** 249 | * Retrieves the Date object equivalent to the NepaliDate. 250 | * 251 | * @returns {Date} The equivalent JavaScript Date object. 252 | */ 253 | getDateObject() { 254 | return this.timestamp 255 | } 256 | 257 | /** 258 | * Retrieves the year of the Nepali date in the Nepali calendar. 259 | * 260 | * @returns {number} The full numeric value representing the year. Eg. 2080 261 | */ 262 | getYear(): number { 263 | return this.year 264 | } 265 | 266 | /** 267 | * Retrieves the year of the Nepali date in the English calendar. 268 | * 269 | * @returns {number} The full numeric value representing the year. Eg. 2009 270 | */ 271 | getEnglishYear(): number { 272 | return this.yearEn 273 | } 274 | 275 | /** 276 | * Retrieves the month of the Nepali date in the Nepali calendar. 277 | * 278 | * @returns {number} The numeric value representing the month. 0 for Baisakh and 11 for Chaitra. 279 | */ 280 | getMonth(): number { 281 | return this.month 282 | } 283 | 284 | /** 285 | * Retrieves the month of the Nepali date in the English calendar. 286 | * 287 | * @returns {number} The numeric value representing the month. 0 for January and 11 for December. 288 | */ 289 | getEnglishMonth(): number { 290 | return this.monthEn 291 | } 292 | 293 | /** 294 | * Retrieves the day of the month represented of Nepali date in Nepali calendar. 295 | * 296 | * @returns {number} The numeric value representing the day of the month. 297 | */ 298 | getDate(): number { 299 | return this.day 300 | } 301 | 302 | /** 303 | * Retrieves the day of the month represented of Nepali date in English calendar. 304 | * 305 | * @returns {number} The numeric value representing the day of the month. 306 | */ 307 | getEnglishDate(): number { 308 | return this.dayEn 309 | } 310 | 311 | /** 312 | * Retrieves the day of the week represented by a numeric value. 313 | * 314 | * @returns The numeric value representing the day of the week. 315 | * 0: Sunday 316 | * 1: Monday 317 | * 2: Tuesday 318 | * 3: Wednesday 319 | * 4: Thursday 320 | * 5: Friday 321 | * 6: Saturday 322 | */ 323 | getDay(): number { 324 | return this.weekDay 325 | } 326 | 327 | /** 328 | * Retrieves the hour value of the Nepali date. 329 | * 330 | * @returns {number} The numeric value representing the hour. 331 | */ 332 | getHours(): number { 333 | return this.hour 334 | } 335 | 336 | /** 337 | * Retrieves the minute value of the Nepali date. 338 | * 339 | * @returns {number} The numeric value representing the minute. 340 | */ 341 | getMinutes(): number { 342 | return this.minute 343 | } 344 | 345 | /** 346 | * Retrieves the second value of the Nepali date. 347 | * 348 | * @returns {number} The numeric value representing the second. 349 | */ 350 | getSeconds(): number { 351 | return this.timestamp.getSeconds() 352 | } 353 | 354 | /** 355 | * Retrieves the millisecond value of the Nepali date. 356 | * 357 | * @returns {number} The numeric value representing the millisecond. 358 | */ 359 | getMilliseconds(): number { 360 | return this.timestamp.getMilliseconds() 361 | } 362 | 363 | /** 364 | * Retrieves the unix timestamp (in milliseconds) of the Nepali date. 365 | * 366 | * @returns {number} The numeric value representing the time in milliseconds. 367 | */ 368 | getTime(): number { 369 | return this.timestamp.getTime() 370 | } 371 | 372 | /** 373 | * Sets the day on the current date and time 374 | * 375 | * @param {number} year - The numeric value representing the year. 376 | * @throws {ValidationError} if year is out of range 377 | */ 378 | setYear(year: number) { 379 | this.set( 380 | year, 381 | this.month, 382 | this.day, 383 | this.hour, 384 | this.minute, 385 | this.timestamp.getSeconds(), 386 | this.timestamp.getMilliseconds() 387 | ) 388 | } 389 | 390 | /** 391 | * Sets the day on the current date and time 392 | * 393 | * @param {number} month - The numeric value representing the month. 394 | * @throws {ValidationError} if month is out of range 395 | */ 396 | setMonth(month: number) { 397 | this.set( 398 | this.year, 399 | month, 400 | this.day, 401 | this.hour, 402 | this.minute, 403 | this.timestamp.getSeconds(), 404 | this.timestamp.getMilliseconds() 405 | ) 406 | } 407 | 408 | /** 409 | * Sets the day on the current date and time 410 | * 411 | * @param {number} day - The numeric value representing the day. 412 | * @throws {ValidationError} if day is out of range 413 | */ 414 | setDate(day: number) { 415 | this.set( 416 | this.year, 417 | this.month, 418 | day, 419 | this.hour, 420 | this.minute, 421 | this.timestamp.getSeconds(), 422 | this.timestamp.getMilliseconds() 423 | ) 424 | } 425 | 426 | /** 427 | * Sets hour on the current date and time 428 | * 429 | * @param hour Hour to set 430 | * @throws {ValidationError} if hour is out of range 431 | */ 432 | setHours(hour: number) { 433 | this.set( 434 | this.year, 435 | this.month, 436 | this.day, 437 | hour, 438 | this.minute, 439 | this.timestamp.getSeconds(), 440 | this.timestamp.getMilliseconds() 441 | ) 442 | } 443 | 444 | /** 445 | * Sets minute on the current date and time 446 | * 447 | * @param minute Minute to set 448 | * @throws {ValidationError} if minute is out of range 449 | */ 450 | setMinutes(minute: number) { 451 | this.set( 452 | this.year, 453 | this.month, 454 | this.day, 455 | this.hour, 456 | minute, 457 | this.timestamp.getSeconds(), 458 | this.timestamp.getMilliseconds() 459 | ) 460 | } 461 | 462 | /** 463 | * Sets second on the current date and time 464 | * 465 | * @param second Second to set 466 | * @throws {ValidationError} if second is out of range 467 | */ 468 | setSeconds(second: number) { 469 | this.set( 470 | this.year, 471 | this.month, 472 | this.day, 473 | this.hour, 474 | this.minute, 475 | second, 476 | this.timestamp.getMilliseconds() 477 | ) 478 | } 479 | 480 | /** 481 | * Sets milliseconds on the current date and time 482 | * 483 | * @param ms Milliseconds to set 484 | * @throws {ValidationError} if milliseconds is out of range 485 | */ 486 | setMilliseconds(ms: number) { 487 | this.set( 488 | this.year, 489 | this.month, 490 | this.day, 491 | this.hour, 492 | this.minute, 493 | this.timestamp.getSeconds(), 494 | ms 495 | ) 496 | } 497 | 498 | /** 499 | * Sets time on the object. 500 | * 501 | * @param time Time to set (timestamp) 502 | */ 503 | setTime(time: number) { 504 | this._setDateObject(new Date(time)) 505 | } 506 | 507 | /** 508 | * Sets the Nepali date and time values. 509 | * 510 | * @param {number} year - The numeric value representing the year. 511 | * @param {number} month - The numeric value representing the month. 512 | * @param {number} date - The numeric value representing the day. 513 | * @param {number} [hour=0] - The numeric value representing the hour. 514 | * @param {number} [minute=0] - The numeric value representing the minute. 515 | * @param {number} [second=0] - The numeric value representing the second. 516 | * @param {number} [ms=0] - The numeric value representing the millisecond. 517 | */ 518 | set( 519 | year: number, 520 | month: number, 521 | date: number, 522 | hour: number, 523 | minute: number, 524 | second: number, 525 | ms: number 526 | ) { 527 | validateTime(hour, minute, second, ms) 528 | const [yearEn, month0EN, dayEn] = dateConverter.nepaliToEnglish( 529 | year, 530 | month, 531 | date 532 | ) 533 | this.year = year 534 | this.month = month 535 | this.day = date 536 | this._setDateObject( 537 | getDate(yearEn, month0EN, dayEn, hour, minute, second, ms), 538 | false 539 | ) 540 | } 541 | 542 | /** 543 | * Sets the Date object on the current NepaliDate object. 544 | * 545 | * @param date The Date object to set. 546 | * @returns void 547 | */ 548 | setDateObject(date: Date) { 549 | this._setDateObject(date, true) // forcing to compute nepali date 550 | } 551 | 552 | /** 553 | * Returns a string representation (in English) of the NepaliDate object in the specified format. 554 | * 555 | * @param {string} formatStr - The format string specifying the desired format. 556 | * @returns {string} The formatted Nepali date string. 557 | */ 558 | format(formatStr: string): string { 559 | return format(this, formatStr) 560 | } 561 | 562 | /** 563 | * Returns a string representation in the Nepali (Devanagari) of the NepaliDate object in the specified format. 564 | * @param formatStr The format string for the desired output. 565 | * @returns {string} The formatted Date string in Nepali (Devanagari). 566 | */ 567 | formatNepali(formatStr: string): string { 568 | return formatNepali(this, formatStr) 569 | } 570 | 571 | /** 572 | * Returns a string representation of the NepaliDate object. 573 | * 574 | * @returns {string} The string representation of the Nepali date. 575 | */ 576 | toString(): string { 577 | return nepaliDateToString(this) 578 | } 579 | 580 | /** 581 | * Returns a string representation (in English) of the English Date in the specified format. 582 | * 583 | * @param {string} formatStr - The format string specifying the desired format. 584 | * @returns {string} The formatted Date string. 585 | */ 586 | formatEnglishDate(formatStr: string): string { 587 | return formatEnglishDate(this, formatStr) 588 | } 589 | 590 | /** 591 | * Returns a string representation in the Nepali (Devanagari) of the English Date in the specified format. 592 | * @param formatStr The format string for the desired output. 593 | * @returns {string} The formatted Date string in Nepali (Devanagari). 594 | */ 595 | formatEnglishDateInNepali(formatStr: string): string { 596 | return formatEnglishDateInNepali(this, formatStr) 597 | } 598 | 599 | /* Static methods */ 600 | 601 | /** 602 | * Creates a new instance of NepaliDate from an English calendar parameters. 603 | * 604 | * @param year - The year in English calendar format. 605 | * @param month0 - The month (0-11) in English calendar format. 606 | * @param date - The day of the month in English calendar format. 607 | * @param hour - The hour (0-23) in English calendar format. Default is 0. 608 | * @param minute - The minute (0-59) in English calendar format. Default is 0. 609 | * @param second - The second (0-59) in English calendar format. Default is 0. 610 | * @param ms - The millisecond (0-999) in English calendar format. Default is 0. 611 | * @returns A new instance of NepaliDate corresponding to the provided English date. 612 | */ 613 | static fromEnglishDate( 614 | year: number, 615 | month0: number, 616 | date: number, 617 | hour: number = 0, 618 | minute: number = 0, 619 | second: number = 0, 620 | ms: number = 0 621 | ): NepaliDate { 622 | const englishDate = getDate(year, month0, date, hour, minute, second, ms) 623 | return new NepaliDate(englishDate) 624 | } 625 | 626 | /** 627 | * Creates a NepaliDate instance by parsing a provided English Date and Time string 628 | * with the given format. 629 | * 630 | * @param dateString - The English Date and time string. 631 | * @param format - The format of the provided date-time string. 632 | * @example 633 | * const dateTimeString = '2024/11/23 14-05-23.789' 634 | * const format = 'YYYY/MM/DD HH-mm-ss.SSS' 635 | * const nepaliDate = NepaliDate.parseEnglishDate(dateTimeString, format) 636 | */ 637 | static parseEnglishDate(dateString: string, format: string): NepaliDate { 638 | const [year, month0, day, hour, minute, second, ms] = parseEnglishDateFormat( 639 | dateString, 640 | format 641 | ) 642 | return NepaliDate.fromEnglishDate(year, month0, day, hour, minute, second, ms) 643 | } 644 | 645 | /** 646 | * Returns the number of days in a specific month of a given year. 647 | * 648 | * @param year - The year to fetch the month from. 649 | * @param month - The month to get the number of days for. 650 | * @returns The number of days in the specified month. 651 | * @throws {Error} If the year or month is out of range. 652 | */ 653 | static getDaysOfMonth(year: number, month: number): number { 654 | if (year < dateConverter.npMinYear() || year > dateConverter.npMaxYear()) { 655 | throw new Error('Year out of range') 656 | } 657 | 658 | if (month < 0 || month > 11) { 659 | throw new Error('Month out of range') 660 | } 661 | 662 | return NP_MONTHS_DATA[year - dateConverter.npMinYear()][0][month] 663 | } 664 | 665 | /** 666 | * Returns the minimum supported JS Date object. 667 | * 668 | * @returns {Date} The minimum supported JS Date object. 669 | */ 670 | static minSupportedDate(): Date { 671 | return NepaliDate.fromEnglishDate( 672 | dateConverter.enMinYear(), 673 | 0, 674 | 1 675 | ).getDateObject() 676 | } 677 | 678 | /** 679 | * Returns the maximum supported JS Date object. 680 | * 681 | * @returns {Date} The maximum supported JS Date object. 682 | */ 683 | static maxSupportedDate(): Date { 684 | return NepaliDate.fromEnglishDate( 685 | dateConverter.enMaxYear(), 686 | 11, 687 | 31 688 | ).getDateObject() 689 | } 690 | 691 | /** 692 | * Returns the minimum supported NepaliDate object. 693 | * 694 | * @returns {Date} The minimum supported NepaliDate object. 695 | */ 696 | static minSupportedNepaliDate(): NepaliDate { 697 | return new NepaliDate(dateConverter.npMinYear(), 0, 1) 698 | } 699 | 700 | /** 701 | * Returns the maximum supported NepaliDate object. 702 | * 703 | * @returns {Date} The maximum supported NepaliDate object. 704 | */ 705 | static maxSupportedNepaliDate(): NepaliDate { 706 | const npMaxYear = dateConverter.npMaxYear() 707 | return new NepaliDate(npMaxYear, 11, this.getDaysOfMonth(npMaxYear, 11)) 708 | } 709 | 710 | static minimum(): Date { 711 | console.warn( 712 | '`NepaliDate.minimum()` is deprecated and will be removed in a future version. Please use `NepaliDate.minSupportedDate()` instead.' 713 | ) 714 | return this.minSupportedDate() 715 | } 716 | 717 | static maximum(): Date { 718 | console.warn( 719 | '`NepaliDate.maximum()` is deprecated and will be removed in a future version. Please use `NepaliDate.maxSupportedDate()` instead.' 720 | ) 721 | return this.maxSupportedDate() 722 | } 723 | } 724 | 725 | export default NepaliDate 726 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export const LOCALE_EN = 'en' 2 | export const LOCALE_NE = 'ne' 3 | 4 | export const UTC_OFFSET_IN_MS = 20700000 // 5 hours 45 minutes in ms 5 | 6 | // timezone reference for +5:30 7 | export const OLD_UTC_OFFSET_IN_MS = 19800000 // 5 hours 40 minutes in ms 8 | 9 | // 504901800000: Wed Jan 01 1986 00:15:00 GMT+0545 (Nepal Time) 10 | // is the timezone transition date on JavaScript 11 | export const TIMEZONE_TRANSITION_TIMESTAMP = 504901800000 12 | export const TIMEZONE_TRANSITION_DATE_REFERENCE = new Date(1986, 0, 1, 0, 15) 13 | 14 | export const NEPALI_MONTHS_EN = [ 15 | 'Baisakh', 16 | 'Jestha', 17 | 'Asar', 18 | 'Shrawan', 19 | 'Bhadra', 20 | 'Aswin', 21 | 'Kartik', 22 | 'Mangsir', 23 | 'Poush', 24 | 'Magh', 25 | 'Falgun', 26 | 'Chaitra', 27 | ] 28 | 29 | export const NEPALI_MONTHS_SHORT_EN = [ 30 | 'Bai', 31 | 'Jes', 32 | 'Asa', 33 | 'Shr', 34 | 'Bhd', 35 | 'Asw', 36 | 'Kar', 37 | 'Man', 38 | 'Pou', 39 | 'Mag', 40 | 'Fal', 41 | 'Cha', 42 | ] 43 | 44 | export const NEPALI_MONTHS_NE = [ 45 | 'बैशाख', 46 | 'जेठ', 47 | 'असार', 48 | 'श्रावण', 49 | 'भाद्र', 50 | 'आश्विन', 51 | 'कार्तिक', 52 | 'मंसिर', 53 | 'पौष', 54 | 'माघ', 55 | 'फाल्गुण', 56 | 'चैत्र', 57 | ] 58 | 59 | export const NEPALI_MONTHS_SHORT_NE = [ 60 | 'बै', 61 | 'जे', 62 | 'अ', 63 | 'श्रा', 64 | 'भा', 65 | 'आ', 66 | 'का', 67 | 'मं', 68 | 'पौ', 69 | 'मा', 70 | 'फा', 71 | 'चै', 72 | ] 73 | 74 | export const ENGLISH_MONTHS_EN = [ 75 | 'January', 76 | 'February', 77 | 'March', 78 | 'April', 79 | 'May', 80 | 'June', 81 | 'July', 82 | 'August', 83 | 'September', 84 | 'October', 85 | 'November', 86 | 'December', 87 | ] 88 | 89 | export const ENGLISH_MONTHS_SHORT_EN = [ 90 | 'Jan', 91 | 'Feb', 92 | 'Mar', 93 | 'Apr', 94 | 'May', 95 | 'Jun', 96 | 'Jul', 97 | 'Aug', 98 | 'Sep', 99 | 'Oct', 100 | 'Nov', 101 | 'Dec', 102 | ] 103 | 104 | export const ENGLISH_MONTHS_NE = [ 105 | 'जनवरी', 106 | 'फेब्रुअरी', 107 | 'मार्च', 108 | 'अप्रिल', 109 | 'मे', 110 | 'जुन', 111 | 'जुलाई', 112 | 'अगस्ट', 113 | 'सेप्टेम्बर', 114 | 'अक्टोबर', 115 | 'नोभेम्बर', 116 | 'डिसेम्बर', 117 | ] 118 | 119 | export const ENGLISH_MONTHS_SHORT_NE = [ 120 | 'जन', 121 | 'फेब', 122 | 'मार', 123 | 'अप्रि', 124 | 'मे', 125 | 'जुन', 126 | 'जुला', 127 | 'अग', 128 | 'सेप', 129 | 'अक्टो', 130 | 'नोभे', 131 | 'डिसे', 132 | ] 133 | 134 | export const NUM_NE = ['०', '१', '२', '३', '४', '५', '६', '७', '८', '९'] 135 | 136 | export const WEEKDAYS_SHORT_EN = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] 137 | 138 | export const WEEKDAYS_LONG_EN = [ 139 | 'Sunday', 140 | 'Monday', 141 | 'Tuesday', 142 | 'Wednesday', 143 | 'Thursday', 144 | 'Friday', 145 | 'Saturday', 146 | ] 147 | 148 | export const WEEKDAYS_SHORT_NE = ['आइत', 'सोम', 'मंगल', 'बुध', 'बिहि', 'शुक्र', 'शनि'] 149 | 150 | export const WEEKDAYS_LONG_NE = [ 151 | 'आइतबार', 152 | 'सोमबार', 153 | 'मंगलबार', 154 | 'बुधबार', 155 | 'बिहिबार', 156 | 'शुक्रबार', 157 | 'शनिबार', 158 | ] 159 | 160 | // Formatting 161 | export const FORMAT_TOKEN_REGEX = 162 | /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DD?|ddd?d?|do?|YYYY|YY|y{2,4}|yo?|a|A|hh?|HH?|mm?|ss?|SSS|x|X|.)/g 163 | -------------------------------------------------------------------------------- /src/dateConverter/constants.ts: -------------------------------------------------------------------------------- 1 | // Reference date for conversion is 2000/01/01 BS and 1943/4/14 AD 2 | export const NP_INITIAL_YEAR = 2000 3 | export const REFERENCE_EN_DATE: [number, number, number] = [1943, 4, 14] 4 | 5 | // English month constant data (will never change) 6 | export const EN_MONTHS: number[] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] 7 | export const EN_LEAP_YEAR_MONTHS: number[] = [ 8 | 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 9 | ] // Leap year months (Just 29 on Feb) 10 | 11 | // Nepali months data 12 | export const NP_MONTHS_DATA: Array<[number[], number]> = [ 13 | [[30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 365], // 2000 BS - 1943/1944 AD 14 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], // 2001 BS 15 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 16 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 17 | [[30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 365], 18 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 19 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 20 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 21 | [[31, 31, 31, 32, 31, 31, 29, 30, 30, 29, 29, 31], 365], 22 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 23 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 24 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 25 | [[31, 31, 31, 32, 31, 31, 29, 30, 30, 29, 30, 30], 365], 26 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 27 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 28 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 29 | [[31, 31, 31, 32, 31, 31, 29, 30, 30, 29, 30, 30], 365], 30 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 31 | [[31, 32, 31, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 32 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 366], 33 | [[31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30], 365], 34 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 35 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30], 365], 36 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 366], 37 | [[31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30], 365], 38 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 39 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 40 | [[30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 365], 41 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 42 | [[31, 31, 32, 31, 32, 30, 30, 29, 30, 29, 30, 30], 365], 43 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 44 | [[30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 365], 45 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 46 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 47 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 48 | [[30, 32, 31, 32, 31, 31, 29, 30, 30, 29, 29, 31], 365], 49 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 50 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 51 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 52 | [[31, 31, 31, 32, 31, 31, 29, 30, 30, 29, 30, 30], 365], 53 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 54 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 55 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 56 | [[31, 31, 31, 32, 31, 31, 29, 30, 30, 29, 30, 30], 365], 57 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 58 | [[31, 32, 31, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 59 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 60 | [[31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30], 365], 61 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 62 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30], 365], 63 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 366], 64 | [[31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30], 365], 65 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 66 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30], 365], 67 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 366], 68 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 69 | [[31, 31, 32, 31, 32, 30, 30, 29, 30, 29, 30, 30], 365], 70 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 71 | [[30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 365], 72 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 73 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 74 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 75 | [[30, 32, 31, 32, 31, 31, 29, 30, 29, 30, 29, 31], 365], 76 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 77 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 78 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 79 | [[31, 31, 31, 32, 31, 31, 29, 30, 30, 29, 29, 31], 365], 80 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 81 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 82 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 83 | [[31, 31, 31, 32, 31, 31, 29, 30, 30, 29, 30, 30], 365], 84 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 85 | [[31, 32, 31, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 86 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 87 | [[31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30], 365], 88 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 89 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30], 365], 90 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 366], 91 | [[31, 31, 31, 32, 31, 31, 30, 29, 30, 29, 30, 30], 365], 92 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 93 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 30], 365], // 2080 94 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 366], // 2081 95 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], // 2082 96 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 97 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 98 | [[30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 365], 99 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 100 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 101 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 102 | [[30, 32, 31, 32, 31, 30, 30, 30, 29, 30, 29, 31], 365], 103 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 104 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 105 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 106 | [[31, 31, 31, 32, 31, 31, 29, 30, 30, 29, 29, 31], 365], 107 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 108 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], 109 | [[31, 32, 31, 32, 31, 30, 30, 30, 29, 29, 30, 31], 366], 110 | [[31, 31, 31, 32, 31, 31, 29, 30, 30, 29, 30, 30], 365], 111 | [[31, 31, 32, 31, 31, 31, 30, 29, 30, 29, 30, 30], 365], 112 | [[31, 31, 32, 32, 31, 30, 30, 29, 30, 29, 30, 30], 365], // 2099 BS - 2042/2043 AD 113 | ] 114 | -------------------------------------------------------------------------------- /src/dateConverter/dateConverter.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * dateConverter.ts 3 | * 4 | * This module provides functions for converting dates between the English (Gregorian) and Nepali calendars. 5 | * It includes functions for converting English to Nepali dates, Nepali to English dates, and validating date ranges. 6 | * The conversion is based on the official Nepali calendar data and reference date. 7 | * 8 | * Functions: 9 | * 10 | * - `englishToNepali(year: number, month0: number, day: number): [number, number, number]` 11 | * Converts a given English (Gregorian) date to Nepali date. 12 | * 13 | * - `nepaliToEnglish(year: number, month0: number, day: number): [number, number, number]` 14 | * Converts a given Nepali date to English (Gregorian) date. 15 | * 16 | * - `DateOutOfRangeError` 17 | * Custom error class thrown when a date is out of the valid range. 18 | * 19 | * - Other helper functions and constants for date calculations and validations. 20 | * 21 | * Usage Example: 22 | * 23 | * ```typescript 24 | * import dateConverter from './dateConverter'; 25 | * 26 | * const [npYear, npMonth, npDay] = dateConverter.englishToNepali(2023, 5, 27); 27 | * console.log(`Nepali Date: ${npYear}-${npMonth}-${npDay}`); 28 | * 29 | * const [enYear, enMonth, enDay] = dateConverter.nepaliToEnglish(2080, 2, 15); 30 | * console.log(`English Date: ${enYear}-${enMonth}-${enDay}`); 31 | * ``` 32 | * 33 | * Note: There are two types of month variables used in this file. 34 | * The first is `month0`, which represents month values starting from 0, 35 | * for example, 0 for January and 0 for Baishakh. 36 | * The second is `month`, which represents month values starting from 1. 37 | */ 38 | import { 39 | NP_INITIAL_YEAR, 40 | REFERENCE_EN_DATE, 41 | EN_MONTHS, 42 | EN_LEAP_YEAR_MONTHS, 43 | NP_MONTHS_DATA, 44 | } from './constants' 45 | 46 | /** 47 | * Custom error class for representing date out of range error. 48 | */ 49 | class DateOutOfRangeError extends Error { 50 | constructor(message: string) { 51 | super(message) 52 | this.name = 'DateOutOfRangeError' 53 | } 54 | } 55 | 56 | /* 57 | * utility methods */ 58 | 59 | /** 60 | * Returns the minimum valid year for date conversion. 61 | * @returns The minimum valid year for date conversion. 62 | */ 63 | const enMinYear = (): number => { 64 | return REFERENCE_EN_DATE[0] + 1 65 | } 66 | 67 | /** 68 | * Returns the maximum valid year for date conversion. 69 | * @returns The maximum valid year for date conversion. 70 | */ 71 | const enMaxYear = (): number => { 72 | return REFERENCE_EN_DATE[0] + NP_MONTHS_DATA.length - 1 73 | } 74 | 75 | /** 76 | * Returns the minimum valid year for date conversion. 77 | * @returns The minimum valid year for date conversion. 78 | */ 79 | const npMinYear = (): number => { 80 | return NP_INITIAL_YEAR 81 | } 82 | 83 | /** 84 | * Returns the maximum valid year for date conversion. 85 | * @returns The maximum valid year for date conversion. 86 | */ 87 | const npMaxYear = (): number => { 88 | return NP_INITIAL_YEAR + NP_MONTHS_DATA.length - 1 89 | } 90 | 91 | /** 92 | * Checks if a given year is a leap year in English calendar. 93 | * @param year - The year to check. 94 | * @returns A boolean indicating whether the year is a leap year. 95 | */ 96 | const _isLeapYear = (year: number): boolean => { 97 | return year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0) 98 | } 99 | 100 | /** 101 | * Returns the number of days in each month of a given year in English calendar. 102 | * @param year - The year for which to retrieve the months. 103 | * @returns An array containing the number of days in each month of the year. 104 | */ 105 | const _getEnMonths = (year: number): number[] => { 106 | return _isLeapYear(year) ? EN_LEAP_YEAR_MONTHS : EN_MONTHS 107 | } 108 | 109 | /* 110 | * ENGLISH TO NEPALI DATE CONVERSION */ 111 | 112 | /** 113 | * Checks if the provided English date is valid. 114 | * @param year - The year in English calendar. 115 | * @param month - The month in English calendar. Starting from 1, 1 for January. 116 | * @param day - The day in English calendar. 117 | * @returns True if the date is valid, false otherwise. 118 | */ 119 | const _checkEnglishDate = (year: number, month: number, day: number): boolean => { 120 | if (year < enMinYear() || year > enMaxYear()) return false 121 | 122 | if (month < 1 || month > 12) return false 123 | 124 | if (day < 1 || day > _getEnMonths(year)[month - 1]) return false 125 | 126 | return true 127 | } 128 | 129 | /** 130 | * Calculates the total number of days from the given English date. 131 | * @param year - The year in English calendar. 132 | * @param month - The month in English calendar. Starting from 1, 1 for January. 133 | * @param day - The day in English calendar. 134 | * @returns The total number of days. 135 | */ 136 | const _getTotalDaysFromEnglishDate = ( 137 | year: number, 138 | month: number, 139 | day: number 140 | ): number => { 141 | let total_days = year * 365 + day 142 | for (let i = 0; i < month - 1; i++) { 143 | total_days += EN_MONTHS[i] 144 | } 145 | 146 | // adding leap days (ie. leap year count) 147 | if (month <= 2) { 148 | year -= 1 149 | } 150 | total_days += Math.floor(year / 4) - Math.floor(year / 100) + Math.floor(year / 400) 151 | 152 | return total_days 153 | } 154 | 155 | /** 156 | * Converts an English date to Nepali date. 157 | * @param year - The year in English calendar. 158 | * @param month0 - The month in English calendar. Starting from 0, 0 for January. 159 | * @param day - The day in English calendar. 160 | * @returns The corresponding Nepali date as an array of [year, month, day]. 161 | * @throws {DateOutOfRangeError} If the provided date is out of range. 162 | */ 163 | function englishToNepali( 164 | year: number, 165 | month0: number, 166 | day: number 167 | ): [number, number, number] { 168 | const month = month0 + 1 169 | 170 | // VALIDATION 171 | // checking if date is in range 172 | if (!_checkEnglishDate(year, month, day)) { 173 | throw new DateOutOfRangeError('Date out of range') 174 | } 175 | 176 | // REFERENCE 177 | let np_year: number = NP_INITIAL_YEAR 178 | let np_month: number = 1 179 | let np_day: number = 1 180 | 181 | // DIFFERENCE 182 | // calculating days count from the reference date 183 | let difference: number = Math.abs( 184 | _getTotalDaysFromEnglishDate(year, month, day) - 185 | _getTotalDaysFromEnglishDate(...REFERENCE_EN_DATE) 186 | ) 187 | 188 | // YEAR 189 | // Incrementing year until the difference remains less than 365 190 | let year_data_index: number = 0 191 | while (difference >= NP_MONTHS_DATA[year_data_index][1]) { 192 | difference -= NP_MONTHS_DATA[year_data_index][1] 193 | np_year += 1 194 | year_data_index += 1 195 | } 196 | 197 | // MONTH 198 | // Incrementing month until the difference remains less than next nepali month days (mostly 31) 199 | let i: number = 0 200 | while (difference >= NP_MONTHS_DATA[year_data_index][0][i]) { 201 | difference -= NP_MONTHS_DATA[year_data_index][0][i] 202 | np_month += 1 203 | i += 1 204 | } 205 | 206 | // DAY 207 | // Remaining difference is the day 208 | np_day += difference 209 | 210 | return [np_year, np_month - 1, np_day] 211 | } 212 | 213 | /* 214 | * NEPALI TO ENGLISH DATE CONVERSION */ 215 | 216 | /** 217 | * Checks if the provided Nepali date is valid and within the range. 218 | * @param year - The year in Nepali calendar. 219 | * @param month - The month in Nepali calendar. Starting from 1, 1 for Baishakh. 220 | * @param day - The day in Nepali calendar. 221 | * @returns True if the date is valid and within the range, false otherwise. 222 | */ 223 | const _checkNepaliDate = (year: number, month: number, day: number): boolean => { 224 | if (year < npMinYear() || year > npMaxYear()) return false 225 | 226 | if (month < 1 || month > 12) return false 227 | 228 | if (day < 1 || day > NP_MONTHS_DATA[year - NP_INITIAL_YEAR][0][month - 1]) 229 | return false 230 | 231 | return true 232 | } 233 | 234 | /** 235 | * Calculates the total number of days from the Nepali reference date to the provided Nepali date. 236 | * @param year - The year in Nepali calendar. 237 | * @param month - The month in Nepali calendar. Starting from 1, 1 for Baishakh. 238 | * @param day - The day in Nepali calendar. 239 | * @returns The total number of days from the reference date to the provided Nepali date. 240 | */ 241 | const _getTotalDaysFromNepaliDate = ( 242 | year: number, 243 | month: number, 244 | day: number 245 | ): number => { 246 | let total_days = day - 1 247 | 248 | const year_index = year - NP_INITIAL_YEAR 249 | for (let i = 0; i < month - 1; i++) { 250 | total_days += NP_MONTHS_DATA[year_index][0][i] 251 | } 252 | 253 | for (let i = 0; i < year_index; i++) { 254 | total_days += NP_MONTHS_DATA[i][1] 255 | } 256 | 257 | return total_days 258 | } 259 | 260 | /** 261 | * Converts a Nepali date to the corresponding English date. 262 | * @param year - The year in Nepali calendar. 263 | * @param month - The month in Nepali calendar. 264 | * @param day - The day in Nepali calendar. Starting from 0, 0 for Baishakh. 265 | * @returns An array containing the corresponding English year, month, and day. 266 | * @throws {DateOutOfRangeError} If the provided Nepali date is out of range. 267 | */ 268 | const nepaliToEnglish = ( 269 | year: number, 270 | month0: number, 271 | day: number 272 | ): [number, number, number] => { 273 | const month = month0 + 1 274 | 275 | // VALIDATION 276 | if (!_checkNepaliDate(year, month, day)) { 277 | throw new DateOutOfRangeError('Date out of range') 278 | } 279 | 280 | // REFERENCE 281 | // For absolute reference, moving date to Jan 1 282 | // Eg. ref: 1943/4/14 => 1943/01/01 283 | let [en_year, en_month, en_day] = [REFERENCE_EN_DATE[0], 1, 1] 284 | // calculating difference from the adjusted reference (eg. 1943/4/14 - 1943/01/01) 285 | const ref_year_months = _getEnMonths(en_year) 286 | const reference_diff: number = 287 | ref_year_months 288 | .slice(0, REFERENCE_EN_DATE[1] - 1) 289 | .reduce((acc, curr) => acc + curr, 0) + 290 | REFERENCE_EN_DATE[2] - 291 | 1 // day - 1 292 | 293 | // DIFFERENCE 294 | // calculating days count from the reference date 295 | let difference: number = Math.abs( 296 | _getTotalDaysFromNepaliDate(year, month, day) + reference_diff 297 | ) 298 | 299 | // YEAR 300 | // Incrementing year until the difference remains less than 365 (or 365) 301 | while ( 302 | (difference >= 366 && _isLeapYear(en_year)) || 303 | (difference >= 365 && !_isLeapYear(en_year)) 304 | ) { 305 | difference -= _isLeapYear(en_year) ? 366 : 365 306 | en_year += 1 307 | } 308 | 309 | // MONTH 310 | // Incrementing month until the difference remains less than next english month (mostly 31) 311 | const month_days: number[] = _getEnMonths(en_year) 312 | let i = 0 313 | while (difference >= month_days[i]) { 314 | difference -= month_days[i] 315 | en_month += 1 316 | i += 1 317 | } 318 | 319 | // DAY 320 | // Remaining difference is the day 321 | en_day += difference 322 | 323 | return [en_year, en_month - 1, en_day] 324 | } 325 | 326 | export default { 327 | enMinYear, 328 | enMaxYear, 329 | npMinYear, 330 | npMaxYear, 331 | englishToNepali, 332 | nepaliToEnglish, 333 | } 334 | -------------------------------------------------------------------------------- /src/dateConverter/index.ts: -------------------------------------------------------------------------------- 1 | import dateConverter from './dateConverter' 2 | export default dateConverter 3 | -------------------------------------------------------------------------------- /src/format/format.ts: -------------------------------------------------------------------------------- 1 | import { LOCALE_EN, LOCALE_NE } from '../constants' 2 | import { parseFormatTokens } from '../utils' 3 | import { 4 | amPmLowerCase, 5 | amPmUpperCase, 6 | Formatter, 7 | fullNepaliYear, 8 | halfNepaliYear, 9 | hour12Number, 10 | hour12TwoDigit, 11 | hour24Number, 12 | hour24TwoDigit, 13 | INepaliDate, 14 | Locale, 15 | millisecondThreeDigit, 16 | millisecondZeroPad, 17 | minuteNumber, 18 | minuteTwoDigit, 19 | nepaliDayNumber, 20 | nepaliDayTwoDigit, 21 | nepaliMonthAbbrName, 22 | nepaliMonthFullName, 23 | nepaliMonthNumber, 24 | nepaliMonthTwoDigit, 25 | secondNumber, 26 | secondTwoDigit, 27 | weekDayFullName, 28 | weekDayNumber, 29 | weekDayShortName, 30 | zeroPad, 31 | } from './tokenFormatters' 32 | 33 | const TOKENS_TO_FORMATTER: { [key: string]: Formatter } = { 34 | YY: halfNepaliYear, 35 | YYYY: fullNepaliYear, 36 | M: nepaliMonthNumber, 37 | MM: nepaliMonthTwoDigit, 38 | MMM: nepaliMonthAbbrName, 39 | MMMM: nepaliMonthFullName, 40 | D: nepaliDayNumber, 41 | DD: nepaliDayTwoDigit, 42 | d: weekDayNumber, 43 | dd: weekDayShortName, 44 | ddd: weekDayShortName, 45 | dddd: weekDayFullName, 46 | H: hour24Number, 47 | HH: hour24TwoDigit, 48 | h: hour12Number, 49 | hh: hour12TwoDigit, 50 | m: minuteNumber, 51 | mm: minuteTwoDigit, 52 | s: secondNumber, 53 | ss: secondTwoDigit, 54 | SSS: millisecondThreeDigit, 55 | A: amPmUpperCase, 56 | a: amPmLowerCase, 57 | } 58 | 59 | /** 60 | * Converts a Nepali date object to a formatted string. 61 | * 62 | * @param {INepaliDate} nepaliDate - The Nepali date object to be formatted. 63 | * @param {string} format - The format string to specify the desired output format. 64 | * @param {Locale} locale - The locale specifying the localization (e.g., 'en' or 'ne'). 65 | * @returns {string} The formatted date in string format. 66 | */ 67 | const formatDate = ( 68 | nepaliDate: INepaliDate, 69 | format: string, 70 | locale: Locale 71 | ): string => { 72 | const tokens = parseFormatTokens(format) 73 | const formatToken = (token: string) => { 74 | if (!(token in TOKENS_TO_FORMATTER)) { 75 | return token 76 | } 77 | return TOKENS_TO_FORMATTER[token](nepaliDate, locale) 78 | } 79 | return tokens.map(formatToken).join('') 80 | } 81 | 82 | /** 83 | * Returns a string representation (in English) of the NepaliDate object in the specified format. 84 | * 85 | * @param {INepaliDate} nepaliDate - The Nepali date object to be formatted. 86 | * @param {string} format - The format string for the desired output. 87 | * @returns {string} - The formatted Nepali date string. 88 | */ 89 | export const format = (nepaliDate: INepaliDate, format: string): string => 90 | formatDate(nepaliDate, format, LOCALE_EN) 91 | 92 | /** 93 | * Returns a string representation in the Nepali (Devanagari) of the NepaliDate object in the specified format. 94 | * 95 | * @param {INepaliDate} nepaliDate - The Nepali date object to be formatted. 96 | * @param {string} format - The format string for the desired output. 97 | * @returns {string} - A string representation of the NepaliDate object in the specified format. 98 | */ 99 | export const formatNepali = (nepaliDate: INepaliDate, format: string): string => 100 | formatDate(nepaliDate, format, LOCALE_NE) 101 | 102 | /** 103 | * Converts a NepaliDate object to a toString() representation. 104 | * Returns in format "YYYY-MM-DD HH:mm:ss[.SSS]". 105 | * This method is lightweight compared to the format/formatNepali method. 106 | * 107 | * @param {INepaliDate} nepaliDate - The NepaliDate object to be converted. 108 | * @returns {string} The formatted string representation of the NepaliDate. 109 | */ 110 | export const nepaliDateToString = (nepaliDate: INepaliDate): string => { 111 | const year = zeroPad(nepaliDate.getYear()) 112 | const month = zeroPad(nepaliDate.getMonth() + 1) 113 | const date = zeroPad(nepaliDate.getDate()) 114 | const hours = zeroPad(nepaliDate.getHours()) 115 | const minutes = zeroPad(nepaliDate.getMinutes()) 116 | const seconds = zeroPad(nepaliDate.getSeconds()) 117 | const milliseconds = nepaliDate.getMilliseconds() 118 | const millisecondString = 119 | milliseconds === 0 ? '' : `.${millisecondZeroPad(milliseconds)}` 120 | 121 | return `${year}-${month}-${date} ${hours}:${minutes}:${seconds}${millisecondString}` 122 | } 123 | -------------------------------------------------------------------------------- /src/format/formatEnglishDate.ts: -------------------------------------------------------------------------------- 1 | import { LOCALE_EN, LOCALE_NE } from '../constants' 2 | import { parseFormatTokens } from '../utils' 3 | import { 4 | amPmLowerCase, 5 | amPmUpperCase, 6 | englishDayNumber, 7 | englishDayTwoDigit, 8 | englishMonthAbbrName, 9 | englishMonthFullName, 10 | englishMonthNumber, 11 | englishMonthTwoDigit, 12 | Formatter, 13 | fullEnglishYear, 14 | halfEnglishYear, 15 | hour12Number, 16 | hour12TwoDigit, 17 | hour24Number, 18 | hour24TwoDigit, 19 | INepaliDate, 20 | Locale, 21 | millisecondThreeDigit, 22 | minuteNumber, 23 | minuteTwoDigit, 24 | secondNumber, 25 | secondTwoDigit, 26 | weekDayFullName, 27 | weekDayNumber, 28 | weekDayShortName, 29 | } from './tokenFormatters' 30 | 31 | const TOKENS_TO_FORMATTER: { [key: string]: Formatter } = { 32 | YY: halfEnglishYear, 33 | YYYY: fullEnglishYear, 34 | M: englishMonthNumber, 35 | MM: englishMonthTwoDigit, 36 | MMM: englishMonthAbbrName, 37 | MMMM: englishMonthFullName, 38 | D: englishDayNumber, 39 | DD: englishDayTwoDigit, 40 | d: weekDayNumber, 41 | dd: weekDayShortName, 42 | ddd: weekDayShortName, 43 | dddd: weekDayFullName, 44 | H: hour24Number, 45 | HH: hour24TwoDigit, 46 | h: hour12Number, 47 | hh: hour12TwoDigit, 48 | m: minuteNumber, 49 | mm: minuteTwoDigit, 50 | s: secondNumber, 51 | ss: secondTwoDigit, 52 | SSS: millisecondThreeDigit, 53 | A: amPmUpperCase, 54 | a: amPmLowerCase, 55 | } 56 | 57 | /** 58 | * Converts a NepaliDate object's English Date to a formatted string. 59 | * 60 | * @param {INepaliDate} nepaliDate - The Nepali date object to be formatted. 61 | * @param {string} format - The format string to specify the desired output format. 62 | * @param {Locale} locale - The locale specifying the localization (e.g., 'en' or 'ne'). 63 | * @returns {string} The formatted date in string format. 64 | */ 65 | const formatDate = ( 66 | nepaliDate: INepaliDate, 67 | format: string, 68 | locale: Locale 69 | ): string => { 70 | const tokens = parseFormatTokens(format) 71 | const formatToken = (token: string) => { 72 | if (!(token in TOKENS_TO_FORMATTER)) { 73 | return token 74 | } 75 | return TOKENS_TO_FORMATTER[token](nepaliDate, locale) 76 | } 77 | return tokens.map(formatToken).join('') 78 | } 79 | 80 | /** 81 | * Returns a string representation (in English) of the English Date from NepaliDate object 82 | * in the specified format. 83 | * 84 | * @param {INepaliDate} nepaliDate - The Nepali date object to be formatted. 85 | * @param {string} format - The format string for the desired output. 86 | * @returns {string} - The formatted Nepali date string. 87 | */ 88 | export const formatEnglishDate = (nepaliDate: INepaliDate, format: string): string => 89 | formatDate(nepaliDate, format, LOCALE_EN) 90 | 91 | /** 92 | * Returns a string representation in the Nepali (Devanagari) of English Date from the 93 | * NepaliDate object in the specified format. 94 | * 95 | * @param {INepaliDate} nepaliDate - The Nepali date object to be formatted. 96 | * @param {string} format - The format string for the desired output. 97 | * @returns {string} - A string representation of the NepaliDate object in the specified format. 98 | */ 99 | export const formatEnglishDateInNepali = ( 100 | nepaliDate: INepaliDate, 101 | format: string 102 | ): string => formatDate(nepaliDate, format, LOCALE_NE) 103 | -------------------------------------------------------------------------------- /src/format/index.ts: -------------------------------------------------------------------------------- 1 | export { format, formatNepali, nepaliDateToString } from './format' 2 | export { formatEnglishDate, formatEnglishDateInNepali } from './formatEnglishDate' 3 | -------------------------------------------------------------------------------- /src/format/tokenFormatters.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ENGLISH_MONTHS_EN, 3 | ENGLISH_MONTHS_NE, 4 | ENGLISH_MONTHS_SHORT_EN, 5 | ENGLISH_MONTHS_SHORT_NE, 6 | LOCALE_EN, 7 | LOCALE_NE, 8 | NEPALI_MONTHS_EN, 9 | NEPALI_MONTHS_NE, 10 | NEPALI_MONTHS_SHORT_EN, 11 | NEPALI_MONTHS_SHORT_NE, 12 | NUM_NE, 13 | WEEKDAYS_LONG_EN, 14 | WEEKDAYS_LONG_NE, 15 | WEEKDAYS_SHORT_EN, 16 | WEEKDAYS_SHORT_NE, 17 | } from '../constants' 18 | 19 | export interface INepaliDate { 20 | getDateObject(): Date 21 | getYear(): number 22 | getEnglishYear(): number 23 | getMonth(): number 24 | getEnglishMonth(): number 25 | getDate(): number 26 | getEnglishDate(): number 27 | getDay(): number 28 | getHours(): number 29 | getMinutes(): number 30 | getSeconds(): number 31 | getMilliseconds(): number 32 | getTime(): number 33 | } 34 | 35 | export type Locale = typeof LOCALE_EN | typeof LOCALE_NE 36 | 37 | export interface Formatter { 38 | (nepaliDate: INepaliDate, locale: Locale): string 39 | } 40 | 41 | /* Helper functions */ 42 | 43 | /** 44 | * Pads a number with a leading zero if it is less than 10. 45 | * 46 | * Output: 1 => 01, 11 => 11 47 | * 48 | * @param value - The number to be padded. 49 | * @returns The padded number as a string. 50 | */ 51 | export const zeroPad = (value: number) => value.toString().padStart(2, '0') 52 | 53 | /** 54 | * Pads a number with a leading zero if it is less than 100. 55 | * 56 | * Output: 1 => 001, 11 => 011, 111 => 111 57 | * 58 | * @param value - The number to be padded. 59 | * @returns The padded number as a string. 60 | */ 61 | export const millisecondZeroPad = (value: number) => value.toString().padStart(3, '0') 62 | 63 | /** 64 | * Converts English digits to Nepali digits (Devanagari script). 65 | * 66 | * @param {string} str - English digits in string format. 67 | * @returns {string} Nepali digits in string format. 68 | */ 69 | const npDigit = (str: string): string => { 70 | return str 71 | .split('') 72 | .map(chr => NUM_NE[chr.charCodeAt(0) - 48]) 73 | .join('') 74 | } 75 | 76 | /** 77 | * Returns a localized number (digit) in string format. 78 | * Converts to Nepali digits for Nepali localization. 79 | * 80 | * @param {string | number} obj - The string or number to be localized. 81 | * @param {Locale} locale - The locale specifying the localization (e.g., 'en' or 'ne'). 82 | * @returns {string} The localized number in string format. 83 | */ 84 | const localizedNumberString = (obj: string | number, locale: Locale): string => { 85 | const objInString = typeof obj === 'string' ? obj : String(obj) 86 | if (locale !== LOCALE_NE) { 87 | return objInString 88 | } 89 | return npDigit(objInString) 90 | } 91 | 92 | /* FORMATTERS */ 93 | 94 | export const halfNepaliYear: Formatter = (nepaliDate, locale) => 95 | localizedNumberString(nepaliDate.getYear(), locale).substring(2) 96 | 97 | export const fullNepaliYear: Formatter = (nepaliDate, locale) => 98 | localizedNumberString(nepaliDate.getYear(), locale) 99 | 100 | export const halfEnglishYear: Formatter = (nepaliDate, locale) => 101 | localizedNumberString(nepaliDate.getEnglishYear(), locale).substring(2) 102 | 103 | export const fullEnglishYear: Formatter = (nepaliDate, locale) => 104 | localizedNumberString(nepaliDate.getEnglishYear(), locale) 105 | 106 | export const nepaliMonthNumber: Formatter = (nepaliDate, locale) => 107 | localizedNumberString(nepaliDate.getMonth() + 1, locale) 108 | 109 | export const nepaliMonthTwoDigit: Formatter = (nepaliDate, locale) => 110 | localizedNumberString(zeroPad(nepaliDate.getMonth() + 1), locale) 111 | 112 | export const nepaliMonthAbbrName: Formatter = (nepaliDate, locale) => { 113 | if (locale === LOCALE_NE) { 114 | return NEPALI_MONTHS_SHORT_NE[nepaliDate.getMonth()] 115 | } 116 | return NEPALI_MONTHS_SHORT_EN[nepaliDate.getMonth()] 117 | } 118 | 119 | export const nepaliMonthFullName: Formatter = (nepaliDate, locale) => { 120 | if (locale === LOCALE_NE) { 121 | return NEPALI_MONTHS_NE[nepaliDate.getMonth()] 122 | } 123 | return NEPALI_MONTHS_EN[nepaliDate.getMonth()] 124 | } 125 | 126 | export const englishMonthNumber: Formatter = (nepaliDate, locale) => 127 | localizedNumberString(nepaliDate.getEnglishMonth() + 1, locale) 128 | 129 | export const englishMonthTwoDigit: Formatter = (nepaliDate, locale) => 130 | localizedNumberString(zeroPad(nepaliDate.getEnglishMonth() + 1), locale) 131 | 132 | export const englishMonthAbbrName: Formatter = (nepaliDate, locale) => { 133 | if (locale === LOCALE_NE) { 134 | return ENGLISH_MONTHS_SHORT_NE[nepaliDate.getEnglishMonth()] 135 | } 136 | return ENGLISH_MONTHS_SHORT_EN[nepaliDate.getEnglishMonth()] 137 | } 138 | 139 | export const englishMonthFullName: Formatter = (nepaliDate, locale) => { 140 | if (locale === LOCALE_NE) { 141 | return ENGLISH_MONTHS_NE[nepaliDate.getEnglishMonth()] 142 | } 143 | return ENGLISH_MONTHS_EN[nepaliDate.getEnglishMonth()] 144 | } 145 | 146 | export const nepaliDayNumber: Formatter = (nepaliDate, locale) => 147 | localizedNumberString(nepaliDate.getDate(), locale) 148 | 149 | export const nepaliDayTwoDigit: Formatter = (nepaliDate, locale) => 150 | localizedNumberString(zeroPad(nepaliDate.getDate()), locale) 151 | 152 | export const englishDayNumber: Formatter = (nepaliDate, locale) => 153 | localizedNumberString(nepaliDate.getEnglishDate(), locale) 154 | 155 | export const englishDayTwoDigit: Formatter = (nepaliDate, locale) => 156 | localizedNumberString(zeroPad(nepaliDate.getEnglishDate()), locale) 157 | 158 | export const weekDayNumber: Formatter = (nepaliDate, locale) => 159 | localizedNumberString(nepaliDate.getDay(), locale) 160 | 161 | export const weekDayShortName: Formatter = (nepaliDate, locale) => { 162 | if (locale === LOCALE_NE) { 163 | return WEEKDAYS_SHORT_NE[nepaliDate.getDay()] 164 | } 165 | return WEEKDAYS_SHORT_EN[nepaliDate.getDay()] 166 | } 167 | 168 | export const weekDayFullName: Formatter = (nepaliDate, locale) => { 169 | if (locale === LOCALE_NE) { 170 | return WEEKDAYS_LONG_NE[nepaliDate.getDay()] 171 | } 172 | return WEEKDAYS_LONG_EN[nepaliDate.getDay()] 173 | } 174 | 175 | export const hour24Number: Formatter = (nepaliDate, locale) => 176 | localizedNumberString(nepaliDate.getHours(), locale) 177 | 178 | export const hour24TwoDigit: Formatter = (nepaliDate, locale) => 179 | localizedNumberString(zeroPad(nepaliDate.getHours()), locale) 180 | 181 | export const hour12Number: Formatter = (nepaliDate, locale) => { 182 | const hour24 = nepaliDate.getHours() 183 | const hour = hour24 > 12 ? hour24 - 12 : hour24 184 | return localizedNumberString(hour, locale) 185 | } 186 | 187 | export const hour12TwoDigit: Formatter = (nepaliDate, locale) => { 188 | const hour24 = nepaliDate.getHours() 189 | const hour = hour24 > 12 ? hour24 - 12 : hour24 190 | return localizedNumberString(zeroPad(hour), locale) 191 | } 192 | 193 | export const minuteNumber: Formatter = (nepaliDate, locale) => 194 | localizedNumberString(nepaliDate.getMinutes(), locale) 195 | 196 | export const minuteTwoDigit: Formatter = (nepaliDate, locale) => 197 | localizedNumberString(zeroPad(nepaliDate.getMinutes()), locale) 198 | 199 | export const secondNumber: Formatter = (nepaliDate, locale) => 200 | localizedNumberString(nepaliDate.getSeconds(), locale) 201 | 202 | export const secondTwoDigit: Formatter = (nepaliDate, locale) => 203 | localizedNumberString(zeroPad(nepaliDate.getSeconds()), locale) 204 | 205 | export const millisecondThreeDigit: Formatter = (nepaliDate, locale) => 206 | localizedNumberString(millisecondZeroPad(nepaliDate.getMilliseconds()), locale) 207 | 208 | export const amPmUpperCase: Formatter = (nepaliDate, locale) => { 209 | if (locale === LOCALE_NE) { 210 | return nepaliDate.getHours() >= 12 ? 'पिम' : 'एम' 211 | } 212 | return nepaliDate.getHours() >= 12 ? 'PM' : 'AM' 213 | } 214 | 215 | export const amPmLowerCase: Formatter = (nepaliDate, locale) => { 216 | if (locale === LOCALE_NE) { 217 | return nepaliDate.getHours() >= 12 ? 'पिम' : 'एम' 218 | } 219 | return nepaliDate.getHours() >= 12 ? 'pm' : 'am' 220 | } 221 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import NepaliDate from './NepaliDate' 2 | 3 | export default NepaliDate 4 | -------------------------------------------------------------------------------- /src/parse/index.ts: -------------------------------------------------------------------------------- 1 | export { parseFormat, parse } from './parse' 2 | export { parseEnglishDateFormat } from './parseEnglishDate' 3 | -------------------------------------------------------------------------------- /src/parse/parse.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * parse.ts 3 | * 4 | * This module provides methods for parsing dates and times from strings. 5 | * 6 | * Functions: 7 | * 8 | * parse(dateTimeString) 9 | * - Parses date and time from the given string. 10 | * 11 | * Further extension is needed in this module as there are limited formats supported for parsing. 12 | * Developers should consider extending the module to support additional date and time formats. 13 | */ 14 | 15 | import { 16 | NEPALI_MONTHS_EN, 17 | NEPALI_MONTHS_SHORT_EN, 18 | WEEKDAYS_LONG_EN, 19 | WEEKDAYS_SHORT_EN, 20 | } from '../constants' 21 | import { parseFormatTokens, seqToRE } from '../utils' 22 | 23 | /** 24 | * Parses date from the given string. 25 | * 26 | * Supported formats are: 27 | * YYYY-MM-DD, 28 | * YYYY.MM.DD, 29 | * YYYY/MM/DD 30 | * 31 | * @param dateString date string to be parsed. 32 | * @throws {Error} if date string is invalid 33 | * @returns return array of date information [year, month0, day]. 34 | */ 35 | function parseDateString(dateString: string): number[] { 36 | // Expected date formats are yyyy-mm-dd, yyyy.mm.dd yyyy/mm/dd 37 | const parts: string[] = dateString.split(/[-./]/, 3) 38 | const [year, month = 1, day = 1] = parts.map(d => { 39 | const n = parseInt(d, 10) 40 | if (Number.isNaN(n)) { 41 | throw new Error('Invalid date') 42 | } 43 | return n 44 | }) 45 | 46 | return [year, month - 1, day] 47 | } 48 | 49 | /** 50 | * Parses time from the given string. 51 | * 52 | * Supported formats are: 53 | * HH:mm, 54 | * HH:mm:ss, 55 | * HH:mm:ss:SSS 56 | * 57 | * @param timeString time string to be parsed. 58 | * @throws {Error} if time string is invalid 59 | * @returns return array of date information [hour, minute, second, ms]. 60 | */ 61 | function parseTimeString(timeString: string): number[] { 62 | if (!timeString) return [0, 0, 0, 0] 63 | 64 | // fetching milliseconds first 65 | const [hmsString, msString = '0'] = timeString.split('.', 2) 66 | 67 | const parts: string[] = hmsString.split(':', 3) 68 | const [hour, minute = 0, second = 0] = parts.map(d => { 69 | const n = parseInt(d, 10) 70 | if (Number.isNaN(n)) { 71 | throw new Error('Invalid time') 72 | } 73 | return n 74 | }) 75 | 76 | // converting milliseconds into numbers 77 | let ms = parseInt(msString, 10) 78 | if (Number.isNaN(ms)) ms = 0 79 | 80 | return [hour, minute, second, ms] 81 | } 82 | 83 | /** 84 | * Parses date and time from the given string. 85 | * 86 | * Supported formats are: 87 | * YYYY-MM-DD HH[:mm][:ss][:SSS], 88 | * YYYY.MM.DD HH[:mm][:ss][:SSS], 89 | * YYYY/MM/DD HH[:mm][:ss][:SSS] 90 | * 91 | * @param dateTimeString time string to be parsed. 92 | * @throws {Error} if date or time string is invalid 93 | * @returns return array of date information [hour, minute, second, ms]. 94 | */ 95 | export function parse(dateTimeString: string): number[] { 96 | const [dateString, timeString] = dateTimeString.split(' ', 2) 97 | const [year, month0, day] = parseDateString(dateString) 98 | const [hour, minute, second, ms] = parseTimeString(timeString) 99 | return [year, month0, day, hour, minute, second, ms] 100 | } 101 | 102 | /* parse v2 */ 103 | 104 | const TOKEN_TO_REGEX: { [key: string]: RegExp } = { 105 | YY: /(\d\d)/, 106 | YYYY: /(\d\d\d\d)/, 107 | M: /(1[0-2]|0[1-9]|[1-9])/, 108 | MM: /(1[0-2]|0[1-9]|[1-9])/, 109 | D: /(3[0-2]|[1-2]\d|0[1-9]|[1-9]| [1-9])/, 110 | DD: /(3[0-2]|[1-2]\d|0[1-9]|[1-9]| [1-9])/, 111 | H: /(2[0-3]|[0-1]\d|\d)/, 112 | HH: /(2[0-3]|[0-1]\d|\d)/, 113 | hh: /(1[0-2]|0[1-9]|[1-9])/, 114 | mm: /([0-5]\d|\d)/, 115 | ss: /([0-5]\d|\d)/, 116 | SSS: /(\d\d\d)/, 117 | A: /(AM|PM)/, 118 | a: /(am|pm)/, 119 | MMMM: seqToRE(NEPALI_MONTHS_EN), 120 | MMM: seqToRE(NEPALI_MONTHS_SHORT_EN), 121 | dddd: seqToRE(WEEKDAYS_LONG_EN), 122 | ddd: seqToRE(WEEKDAYS_SHORT_EN), 123 | dd: seqToRE(WEEKDAYS_SHORT_EN), 124 | d: /([0-6])/, 125 | } 126 | 127 | function tokensToRegex(arr: string[]): { dateTokens: string[]; regex: RegExp } { 128 | const dateTokens: string[] = [] 129 | const regexParts: string[] = [] 130 | 131 | for (const token of arr) { 132 | if (token in TOKEN_TO_REGEX) { 133 | dateTokens.push(token) 134 | regexParts.push(TOKEN_TO_REGEX[token].source) 135 | } else { 136 | regexParts.push(token.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')) 137 | } 138 | } 139 | 140 | const regexString = regexParts.join('') 141 | 142 | return { 143 | dateTokens, 144 | regex: new RegExp(`^${regexString}$`), 145 | } 146 | } 147 | 148 | function getDateParams( 149 | dateTokens: string[], 150 | match: RegExpMatchArray 151 | ): { [key: string]: number } { 152 | // month and day are set to 1 in default 153 | let [year, month, day, hour, hour12, minute, second, ms] = [0, 1, 1, 0, 0, 0, 0, 0] 154 | let isPM = false 155 | let is12hourFormat = false 156 | 157 | for (let i = 0; i < dateTokens.length; i++) { 158 | const token = dateTokens[i] 159 | const matchData = parseInt(match[i + 1]) 160 | switch (token) { 161 | case 'YYYY': 162 | year = matchData 163 | break 164 | case 'YY': 165 | year = 2000 + parseInt(match[i]) 166 | break 167 | case 'MM': 168 | case 'M': 169 | month = matchData 170 | break 171 | case 'MMMM': 172 | month = NEPALI_MONTHS_EN.indexOf(match[i + 1]) + 1 173 | break 174 | case 'MMM': 175 | month = NEPALI_MONTHS_SHORT_EN.indexOf(match[i + 1]) + 1 176 | break 177 | case 'DD': 178 | case 'D': 179 | day = matchData 180 | break 181 | case 'HH': 182 | case 'H': 183 | hour = matchData 184 | break 185 | case 'hh': 186 | case 'h': 187 | hour12 = matchData 188 | is12hourFormat = true 189 | break 190 | case 'mm': 191 | case 'm': 192 | minute = matchData 193 | break 194 | case 'ss': 195 | case 's': 196 | second = matchData 197 | break 198 | case 'SSS': 199 | ms = matchData 200 | break 201 | case 'A': 202 | case 'a': 203 | isPM = match[i + 1].toLowerCase() === 'pm' 204 | } 205 | } 206 | 207 | if (is12hourFormat) { 208 | hour = hour12 + (isPM ? 12 : 0) 209 | } 210 | 211 | return { 212 | year, 213 | month0: month - 1, 214 | day, 215 | hour, 216 | minute, 217 | second, 218 | ms, 219 | } 220 | } 221 | 222 | export function parseFormat(dateString: string, format: string): number[] { 223 | const formatTokens = parseFormatTokens(format) 224 | const { dateTokens, regex: formatRegex } = tokensToRegex(formatTokens) 225 | const match = RegExp(formatRegex).exec(dateString) 226 | if (!match) { 227 | throw new Error('Invalid date format') 228 | } 229 | 230 | const { year, month0, day, hour, minute, second, ms } = getDateParams( 231 | dateTokens, 232 | match 233 | ) 234 | return [year, month0, day, hour, minute, second, ms] 235 | } 236 | -------------------------------------------------------------------------------- /src/parse/parseEnglishDate.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ENGLISH_MONTHS_EN, 3 | ENGLISH_MONTHS_SHORT_EN, 4 | WEEKDAYS_LONG_EN, 5 | WEEKDAYS_SHORT_EN, 6 | } from '../constants' 7 | import { parseFormatTokens, seqToRE } from '../utils' 8 | 9 | const TOKEN_TO_REGEX: { [key: string]: RegExp } = { 10 | YY: /(\d\d)/, 11 | YYYY: /(\d\d\d\d)/, 12 | M: /(1[0-2]|0[1-9]|[1-9])/, 13 | MM: /(1[0-2]|0[1-9]|[1-9])/, 14 | D: /(3[0-2]|[1-2]\d|0[1-9]|[1-9]| [1-9])/, 15 | DD: /(3[0-2]|[1-2]\d|0[1-9]|[1-9]| [1-9])/, 16 | H: /(2[0-3]|[0-1]\d|\d)/, 17 | HH: /(2[0-3]|[0-1]\d|\d)/, 18 | hh: /(1[0-2]|0[1-9]|[1-9])/, 19 | mm: /([0-5]\d|\d)/, 20 | ss: /([0-5]\d|\d)/, 21 | SSS: /(\d\d\d)/, 22 | A: /(AM|PM)/, 23 | a: /(am|pm)/, 24 | MMMM: seqToRE(ENGLISH_MONTHS_EN), 25 | MMM: seqToRE(ENGLISH_MONTHS_SHORT_EN), 26 | dddd: seqToRE(WEEKDAYS_LONG_EN), 27 | ddd: seqToRE(WEEKDAYS_SHORT_EN), 28 | dd: seqToRE(WEEKDAYS_SHORT_EN), 29 | d: /([0-6])/, 30 | } 31 | 32 | function tokensToRegex(arr: string[]): { dateTokens: string[]; regex: RegExp } { 33 | const dateTokens: string[] = [] 34 | const regexParts: string[] = [] 35 | 36 | for (const token of arr) { 37 | if (token in TOKEN_TO_REGEX) { 38 | dateTokens.push(token) 39 | regexParts.push(TOKEN_TO_REGEX[token].source) 40 | } else { 41 | regexParts.push(token.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')) 42 | } 43 | } 44 | 45 | const regexString = regexParts.join('') 46 | 47 | return { 48 | dateTokens, 49 | regex: new RegExp(`^${regexString}$`), 50 | } 51 | } 52 | 53 | function getDateParams( 54 | dateTokens: string[], 55 | match: RegExpMatchArray 56 | ): { [key: string]: number } { 57 | // month and day are set to 1 in default 58 | let [year, month, day, hour, hour12, minute, second, ms] = [0, 1, 1, 0, 0, 0, 0, 0] 59 | let isPM = false 60 | let is12hourFormat = false 61 | 62 | for (let i = 0; i < dateTokens.length; i++) { 63 | const token = dateTokens[i] 64 | const matchData = parseInt(match[i + 1]) 65 | switch (token) { 66 | case 'YYYY': 67 | year = matchData 68 | break 69 | case 'YY': 70 | year = 2000 + parseInt(match[i]) 71 | break 72 | case 'MM': 73 | case 'M': 74 | month = matchData 75 | break 76 | case 'MMMM': 77 | month = ENGLISH_MONTHS_EN.indexOf(match[i + 1]) + 1 78 | break 79 | case 'MMM': 80 | month = ENGLISH_MONTHS_SHORT_EN.indexOf(match[i + 1]) + 1 81 | break 82 | case 'DD': 83 | case 'D': 84 | day = matchData 85 | break 86 | case 'HH': 87 | case 'H': 88 | hour = matchData 89 | break 90 | case 'hh': 91 | case 'h': 92 | hour12 = matchData 93 | is12hourFormat = true 94 | break 95 | case 'mm': 96 | case 'm': 97 | minute = matchData 98 | break 99 | case 'ss': 100 | case 's': 101 | second = matchData 102 | break 103 | case 'SSS': 104 | ms = matchData 105 | break 106 | case 'A': 107 | case 'a': 108 | isPM = match[i + 1].toLowerCase() === 'pm' 109 | } 110 | } 111 | 112 | if (is12hourFormat) { 113 | hour = hour12 + (isPM ? 12 : 0) 114 | } 115 | 116 | return { 117 | year, 118 | month0: month - 1, 119 | day, 120 | hour, 121 | minute, 122 | second, 123 | ms, 124 | } 125 | } 126 | 127 | export function parseEnglishDateFormat(dateString: string, format: string): number[] { 128 | const formatTokens = parseFormatTokens(format) 129 | const { dateTokens, regex: formatRegex } = tokensToRegex(formatTokens) 130 | const match = RegExp(formatRegex).exec(dateString) 131 | if (!match) { 132 | throw new Error('Invalid date format') 133 | } 134 | 135 | const { year, month0, day, hour, minute, second, ms } = getDateParams( 136 | dateTokens, 137 | match 138 | ) 139 | return [year, month0, day, hour, minute, second, ms] 140 | } 141 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { 2 | FORMAT_TOKEN_REGEX, 3 | OLD_UTC_OFFSET_IN_MS, 4 | TIMEZONE_TRANSITION_TIMESTAMP, 5 | TIMEZONE_TRANSITION_DATE_REFERENCE, 6 | UTC_OFFSET_IN_MS, 7 | } from './constants' 8 | 9 | /** 10 | * Get the Nepali date and time components (Gregorian calendar) from a given date. 11 | * The input can be any date from any timezone, it is converted into the Nepal's timezone (Asia/Kathmandu). 12 | * 13 | * @param date - The input date for which to retrieve the Nepali date and time. 14 | * @returns An object containing the Nepali date and time components. 15 | */ 16 | export const getNepalDateAndTime = ( 17 | date: Date 18 | ): { 19 | year: number 20 | month0: number 21 | day: number 22 | hour: number 23 | minute: number 24 | second: number 25 | ms: number 26 | weekDay: number 27 | } => { 28 | const time = date.getTime() 29 | 30 | // Handling the timezone switch from GMT+5:30 to GMT+5:45 31 | // In javascript the switched time is 32 | // 504901800000: Wed Jan 01 1986 00:15:00 GMT+0545 (Nepal Time) : Adjusted time 33 | const utcOffsetInMs = 34 | time < TIMEZONE_TRANSITION_TIMESTAMP ? OLD_UTC_OFFSET_IN_MS : UTC_OFFSET_IN_MS 35 | 36 | // Calculate the Nepali reference date by adding the offset to the input date's unix timestamp 37 | const nepaliRefDate = new Date(time + utcOffsetInMs) 38 | 39 | // Extract the Nepali date and time components 40 | const npYear = nepaliRefDate.getUTCFullYear() 41 | const npMonth0 = nepaliRefDate.getUTCMonth() 42 | const npDay = nepaliRefDate.getUTCDate() 43 | const npHour = nepaliRefDate.getUTCHours() 44 | const npMinutes = nepaliRefDate.getUTCMinutes() 45 | const npSeconds = nepaliRefDate.getUTCSeconds() 46 | const npMs = nepaliRefDate.getUTCMilliseconds() 47 | const npWeekDay = nepaliRefDate.getUTCDay() 48 | 49 | // Return the Nepali date and time components as an object 50 | return { 51 | year: npYear, 52 | month0: npMonth0, 53 | day: npDay, 54 | hour: npHour, 55 | minute: npMinutes, 56 | second: npSeconds, 57 | ms: npMs, 58 | weekDay: npWeekDay, 59 | } 60 | } 61 | 62 | /** 63 | * Get the Date object from the given Nepali date and time components. 64 | * 65 | * @param year - The year component of the Nepali date. 66 | * @param month0 - The month component of the Nepali date (1-12). 67 | * @param date - The day component of the Nepali date. 68 | * @param hour - The hour component of the Nepali time. 69 | * @param minute - The minute component of the Nepali time. 70 | * @param second - The second component of the Nepali time. 71 | * @param ms - The millisecond component of the Nepali time. 72 | * @returns A `Date` object representing the UTC date and time. 73 | */ 74 | export const getDate = ( 75 | year: number, 76 | month: number, 77 | day: number, 78 | hour: number, 79 | minute: number, 80 | second: number, 81 | ms: number 82 | ): Date => { 83 | // Create a new Date object using the given Nepali date and time parameters 84 | const nepaliRefDate = new Date(year, month, day, hour, minute, second, ms) 85 | 86 | let utcOffsetInMs = 87 | nepaliRefDate < TIMEZONE_TRANSITION_DATE_REFERENCE 88 | ? OLD_UTC_OFFSET_IN_MS 89 | : UTC_OFFSET_IN_MS 90 | 91 | // Getting current timezone offset (in milliseconds) 92 | const currentOffsetInMS = -1 * nepaliRefDate.getTimezoneOffset() * 60 * 1000 93 | 94 | // Subtracting Nepali ref date by Nepali timezone offset and current timezone Offset 95 | const date = new Date(nepaliRefDate.getTime() - utcOffsetInMs + currentOffsetInMS) 96 | 97 | // Return the date object 98 | return date 99 | } 100 | 101 | /** 102 | * Parses a format string and extracts individual format tokens. 103 | * 104 | * The format string can contain various tokens, which are represented 105 | * by certain characters or character sequences. Tokens can be single 106 | * characters, multiple characters, or character sequences enclosed within 107 | * square brackets. 108 | * 109 | * @param {string} format - The format string to be parsed. 110 | * @returns {string[]} - An array of parsed tokens. 111 | * Each element in the array represents a single token extracted from the format string. 112 | * 113 | * @example 114 | * const formatString = 'YYYY-MM-DD'; 115 | * const parsedTokens = parseFormatTokens(formatString); 116 | * // Output: ['YYYY', '-', 'MM', '-', 'DD'] 117 | * 118 | * @example 119 | * const formatString = "YYYY 'ello DD"; 120 | * const parsedTokens = parseFormatTokens(formatString); 121 | * // Output: ['YYYY', " 'ello ", 'DD'] 122 | */ 123 | 124 | export const parseFormatTokens = (format: string): string[] => { 125 | const tokens: RegExpMatchArray | null = format.match(FORMAT_TOKEN_REGEX) 126 | if (!tokens) return [] 127 | 128 | return tokens.map(token => { 129 | return token.startsWith('[') && token.endsWith(']') ? token.slice(1, -1) : token 130 | }) 131 | } 132 | 133 | /** 134 | * Converts a list of strings to a regex string. 135 | * It takes possible matching values to be from longest to shortest. This 136 | * prevents the possibility of a match occurring for a value that also 137 | * a substring of a larger value that should have matched (e.g., 'abc' 138 | * matching when 'abcdef' should have been the match). 139 | * 140 | * @param toConvert - An array of string containing all the required regex values 141 | */ 142 | export const seqToRE = (toConvert: Array): RegExp => { 143 | // returns /(?:)/ regex for empty array 144 | if (toConvert.length === 0) { 145 | return new RegExp('') 146 | } 147 | 148 | // deepcopy the passed array so as not to change it 149 | let toConvertCopy = [...toConvert] 150 | toConvertCopy = toConvertCopy.sort((a, b) => b.length - a.length) 151 | 152 | // means that the list only contains empty string(s) 153 | if (toConvertCopy[0] === '') { 154 | return new RegExp('') // returns /(?:)/ 155 | } 156 | 157 | const regexString = `(${toConvertCopy.join('|')})` 158 | 159 | return new RegExp(regexString) 160 | } 161 | -------------------------------------------------------------------------------- /src/validators.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * validators.ts 3 | * 4 | * This file contains utility functions for validating data. 5 | */ 6 | 7 | /** 8 | * Custom validation error. 9 | */ 10 | export class ValidationError extends Error { 11 | constructor(message: string) { 12 | super(message) 13 | this.name = 'ValidationError' 14 | } 15 | } 16 | 17 | /** 18 | * Validates the given hour value. 19 | * 20 | * @param hour - The hour value to validate. 21 | * @throws {ValidationError} - If the hour is not within the range of 0-23. 22 | */ 23 | export const validateHour = (hour: number) => { 24 | if (hour < 0 || hour > 23) 25 | throw new ValidationError('Hour should be in the range 0-23') 26 | } 27 | 28 | /** 29 | * Validates the given minute value. 30 | * 31 | * @param minute - The minute value to validate. 32 | * @throws {ValidationError} - If the minute is not within the range of 0-59. 33 | */ 34 | export const validateMinute = (minute: number) => { 35 | if (minute < 0 || minute > 59) 36 | throw new ValidationError('Minute should be in the range 0-59') 37 | } 38 | 39 | /** 40 | * Validates the given second value. 41 | * 42 | * @param second - The second value to validate. 43 | * @throws {ValidationError} - If the second is not within the range of 0-59. 44 | */ 45 | export const validateSecond = (second: number) => { 46 | if (second < 0 || second > 59) 47 | throw new ValidationError('Second should be in the range 0-59') 48 | } 49 | 50 | /** 51 | * Validates the given millisecond value. 52 | * 53 | * @param millisecond - The millisecond value to validate. 54 | * @throws {ValidationError} - If the millisecond is not within the range of 0-999. 55 | */ 56 | export const validateMillisecond = (millisecond: number) => { 57 | if (millisecond < 0 || millisecond > 999) 58 | throw new ValidationError('Millisecond should be in the range 0-999') 59 | } 60 | 61 | /** 62 | * Validates the time components. 63 | * @param hour - The hour component of the time. 64 | * @param minute - The minute component of the time. 65 | * @param second - The second component of the time. 66 | * @param ms - The millisecond component of the time. 67 | * @throws {ValidationError} if any of the time components are out of range. 68 | */ 69 | export const validateTime = ( 70 | hour: number, 71 | minute: number, 72 | second: number, 73 | ms: number 74 | ) => { 75 | validateHour(hour) 76 | validateMinute(minute) 77 | validateSecond(second) 78 | validateMillisecond(ms) 79 | } 80 | -------------------------------------------------------------------------------- /tests/NepaliDate.test.ts: -------------------------------------------------------------------------------- 1 | import dateConverter from '../src/dateConverter' 2 | import NepaliDate from '../src/NepaliDate' 3 | import { ValidationError } from '../src/validators' 4 | 5 | describe('NepaliDate', () => { 6 | it('should throw error if initializes from invalid object', () => { 7 | expect(() => { 8 | const _ = new NepaliDate({} as string) 9 | }).toThrow('Invalid date argument') 10 | }) 11 | 12 | it('should throw error if initializes from invalid object: boolean', () => { 13 | expect(() => { 14 | const _ = new NepaliDate(true as unknown as number) 15 | }).toThrow('Invalid date argument') 16 | }) 17 | 18 | it('should throw error if initializes from null', () => { 19 | expect(() => { 20 | const _ = new NepaliDate(null as unknown as string) 21 | }).toThrow('Invalid date argument') 22 | }) 23 | 24 | it('should throw error if initializes from undefined', () => { 25 | expect(() => { 26 | const _ = new NepaliDate(undefined as unknown as number) 27 | }).toThrow('Invalid date argument') 28 | }) 29 | 30 | it('should throw error if initializes from invalid date as string', () => { 31 | expect(() => { 32 | const _ = new NepaliDate('hello') 33 | }).toThrow('Invalid date') 34 | }) 35 | 36 | it('should initialize from full date and time params', () => { 37 | const n = new NepaliDate(2080, 2, 26, 21, 2, 23, 689) 38 | expect(n.toString()).toBe('2080-03-26 21:02:23.689') 39 | }) 40 | 41 | it('should initialize from year and month params', () => { 42 | const n = new NepaliDate(2080, 2) 43 | expect(n.toString()).toBe('2080-03-01 00:00:00') 44 | }) 45 | 46 | it('should initialize from another NepaliDate object', () => { 47 | const n1 = new NepaliDate(2080, 2, 26, 21, 2, 23, 689) 48 | const n2 = new NepaliDate(n1) 49 | expect(n2.toString()).toBe('2080-03-26 21:02:23.689') 50 | }) 51 | 52 | /* date format parsing tests */ 53 | 54 | it('should initialize by parsing string with given format', () => { 55 | const n1 = new NepaliDate('2042/08/12 14-05-23.789', 'YYYY/MM/DD HH-mm-ss.SSS') 56 | expect(n1.toString()).toBe('2042-08-12 14:05:23.789') 57 | }) 58 | 59 | it('should initialize by parsing year string with default month, day and time params', () => { 60 | const n1 = new NepaliDate('2042', 'YYYY') 61 | expect(n1.toString()).toBe('2042-01-01 00:00:00') 62 | }) 63 | 64 | it('should throw error if year component is missed during parsing', () => { 65 | expect(() => { 66 | const _ = new NepaliDate('08/12 14-05-23.789', 'MM/DD HH-mm-ss.SSS') 67 | }).toThrow('Date out of range') 68 | }) 69 | 70 | it('should initialize by parsing English Date string with given format', () => { 71 | const n1 = NepaliDate.parseEnglishDate( 72 | '2024 August 13 14-05-23.789', 73 | 'YYYY MMMM DD HH-mm-ss.SSS' 74 | ) 75 | expect(n1.toString()).toBe('2081-04-29 14:05:23.789') 76 | }) 77 | 78 | it("should initialize by parsing English Date's year string with default month, day and time params", () => { 79 | const n1 = NepaliDate.parseEnglishDate('2024', 'YYYY') 80 | expect(n1.toString()).toBe('2080-09-16 00:00:00') 81 | }) 82 | 83 | it("should throw error if English Date's year component is missed during parsing", () => { 84 | expect(() => { 85 | const _ = NepaliDate.parseEnglishDate( 86 | '08/13 14-05-23.789', 87 | 'MM/DD HH-mm-ss.SSS' 88 | ) 89 | }).toThrow('Date out of range') 90 | }) 91 | 92 | it('checks for nepali date validity', () => { 93 | // 373314600000 94 | // Fri Oct 30 1981 18:30:00 GMT+0000 95 | // Sat Oct 31 1981 00:00:00 GMT+0530 (Nepal Time) 96 | const n = new NepaliDate(new Date(373314600000)) 97 | expect(n.toString()).toBe('2038-07-15 00:00:00') 98 | expect(n.getYear()).toBe(2038) 99 | expect(n.getEnglishYear()).toBe(1981) 100 | expect(n.getMonth()).toBe(6) 101 | expect(n.getEnglishMonth()).toBe(9) 102 | expect(n.getDate()).toBe(15) 103 | expect(n.getEnglishDate()).toBe(31) 104 | expect(n.getDateObject().getUTCDate()).toEqual(30) 105 | expect(n.getDay()).toBe(6) 106 | }) 107 | 108 | it('checks parser for date only', () => { 109 | const n = new NepaliDate('2038-07-15') 110 | expect(n.toString()).toBe('2038-07-15 00:00:00') 111 | 112 | const n2 = new NepaliDate('2075.03.22') 113 | expect(n2.toString()).toBe('2075-03-22 00:00:00') 114 | expect(n2.getDateObject().toISOString()).toEqual('2018-07-05T18:15:00.000Z') 115 | expect(n2.getEnglishYear()).toBe(2018) 116 | expect(n2.getEnglishMonth()).toBe(6) 117 | expect(n2.getEnglishDate()).toBe(6) 118 | }) 119 | 120 | it('checks parser for date and time', () => { 121 | const n = new NepaliDate('2080-07-15 7:18') 122 | expect(n.toString()).toBe('2080-07-15 07:18:00') 123 | expect(n.getHours()).toBe(7) 124 | expect(n.getMinutes()).toBe(18) 125 | expect(n.getSeconds()).toBe(0) 126 | expect(n.getMilliseconds()).toBe(0) 127 | 128 | const n1 = new NepaliDate('2080-07-15 17:07:1.888') 129 | expect(n1.toString()).toBe('2080-07-15 17:07:01.888') 130 | expect(n1.getHours()).toBe(17) 131 | expect(n1.getMinutes()).toBe(7) 132 | expect(n1.getSeconds()).toBe(1) 133 | expect(n1.getMilliseconds()).toBe(888) 134 | }) 135 | 136 | it('checks format', () => { 137 | const n = new NepaliDate('2038-07-15') 138 | expect(n.formatNepali('YYYY/MM/DD')).toBe('२०३८/०७/१५') 139 | expect(n.formatNepali('YY-M-D')).toBe('३८-७-१५') 140 | expect(n.format('YYYY-MM-DD')).toBe('2038-07-15') 141 | expect(n.format('YY-M-D')).toBe('38-7-15') 142 | expect(n.formatNepali('YYYY-MMMM-ddd')).toBe('२०३८-कार्तिक-शनि') 143 | expect(n.format('[YYY] YYYY')).toBe('YYY 2038') 144 | }) 145 | 146 | it('checks format English Date', () => { 147 | const n = new NepaliDate('2038-07-16') 148 | expect(n.formatEnglishDate('YYYY-MM-DD')).toBe('1981-11-01') 149 | expect(n.formatEnglishDate('YY-M-D')).toBe('81-11-1') 150 | expect(n.formatEnglishDate('[YYY] YYYY')).toBe('YYY 1981') 151 | expect(n.formatEnglishDateInNepali('YYYY/MM/DD')).toBe('१९८१/११/०१') 152 | expect(n.formatEnglishDateInNepali('YY-M-D')).toBe('८१-११-१') 153 | expect(n.formatEnglishDateInNepali('YYYY-MMMM-ddd')).toBe('१९८१-नोभेम्बर-आइत') 154 | }) 155 | 156 | it('checks month, date setting', () => { 157 | const n = new NepaliDate(2075, 11, 3) 158 | expect(n.toString()).toBe('2075-12-03 00:00:00') 159 | n.setYear(2074) 160 | expect(n.toString()).toBe('2074-12-03 00:00:00') 161 | n.setMonth(3) 162 | expect(n.toString()).toBe('2074-04-03 00:00:00') 163 | const n2 = new NepaliDate(2075, 2, 32) 164 | n2.setDate(10) 165 | expect(n2.toString()).toBe('2075-03-10 00:00:00') 166 | n2.setDate(1) 167 | expect(n2.toString()).toBe('2075-03-01 00:00:00') 168 | }) 169 | 170 | it('checks for all methods', () => { 171 | const d = new Date('2017-10-31T12:30:25.789Z') 172 | const n = new NepaliDate(d) 173 | 174 | expect(n.getTime()).toBe(1509453025789) 175 | expect(n.getDay()).toBe(2) 176 | expect(n.getHours()).toBe(18) 177 | expect(n.getMinutes()).toBe(15) 178 | expect(n.getSeconds()).toBe(25) 179 | expect(n.getMilliseconds()).toBe(789) 180 | }) 181 | 182 | it('should set date object using setDateObject', () => { 183 | const d = new Date(373314600000) 184 | const n = new NepaliDate() 185 | n.setDateObject(d) 186 | expect(n.toString()).toBe('2038-07-15 00:00:00') 187 | expect(n.getYear()).toBe(2038) 188 | expect(n.getEnglishYear()).toBe(1981) 189 | expect(n.getMonth()).toBe(6) 190 | expect(n.getEnglishMonth()).toBe(9) 191 | expect(n.getDate()).toBe(15) 192 | expect(n.getEnglishDate()).toBe(31) 193 | expect(n.getDateObject().getUTCDate()).toEqual(30) 194 | expect(n.getDay()).toBe(6) 195 | }) 196 | 197 | it('should be initialized from fromEnglishDate', () => { 198 | const n = NepaliDate.fromEnglishDate(2019, 2, 11, 3, 29, 38, 689) 199 | 200 | // checking nepali calendar date time 201 | expect(n.toString()).toBe('2075-11-27 03:29:38.689') 202 | 203 | // checking date object 204 | expect(n.getTime()).toEqual(1552254278689) 205 | expect(n.getDateObject().toISOString()).toEqual('2019-03-10T21:44:38.689Z') 206 | 207 | // checking english calendar date 208 | expect(n.getEnglishYear()).toBe(2019) 209 | expect(n.getEnglishMonth()).toBe(2) 210 | expect(n.getEnglishDate()).toBe(11) 211 | expect(n.getDay()).toBe(1) 212 | }) 213 | 214 | it('should be initialized from fromEnglishDate date params only', () => { 215 | const n = NepaliDate.fromEnglishDate(2019, 2, 11) 216 | 217 | // checking nepali calendar date time 218 | expect(n.toString()).toBe('2075-11-27 00:00:00') 219 | 220 | // checking date object 221 | expect(n.getTime()).toEqual(1552241700000) 222 | expect(n.getDateObject().toISOString()).toEqual('2019-03-10T18:15:00.000Z') 223 | 224 | // checking english calendar date 225 | expect(n.getEnglishYear()).toBe(2019) 226 | expect(n.getEnglishMonth()).toBe(2) 227 | expect(n.getEnglishDate()).toBe(11) 228 | expect(n.getDay()).toBe(1) 229 | }) 230 | 231 | it('should be initialized from fromEnglishDate for +5:30 timezone', () => { 232 | const n = NepaliDate.fromEnglishDate(1944, 2, 11, 3, 29, 38, 689) 233 | 234 | // checking nepali calendar date time 235 | expect(n.toString()).toBe('2000-11-28 03:29:38.689') 236 | 237 | // checking date object 238 | expect(n.getTime()).toEqual(-814500021311) 239 | expect(n.getDateObject().toISOString()).toEqual('1944-03-10T21:59:38.689Z') 240 | 241 | // checking english calendar date 242 | expect(n.getEnglishYear()).toBe(1944) 243 | expect(n.getEnglishMonth()).toBe(2) 244 | expect(n.getEnglishDate()).toBe(11) 245 | expect(n.getDay()).toBe(6) 246 | }) 247 | }) 248 | 249 | describe('NepaliDate parsing on initialization', () => { 250 | it('should throw error if invalid date format is given', () => { 251 | expect(() => { 252 | const _ = new NepaliDate('YYYY-MM-DD') 253 | }).toThrow('Invalid date') 254 | }) 255 | 256 | it('should throw error if invalid date format is given', () => { 257 | expect(() => { 258 | const _ = new NepaliDate('2080-03-26 HH:SS:MM') 259 | }).toThrow('Invalid time') 260 | }) 261 | 262 | it('should parse both date and time', () => { 263 | const n = new NepaliDate('2080-03-26 18:15:24') 264 | expect(n.toString()).toBe('2080-03-26 18:15:24') 265 | }) 266 | 267 | it('should parse without time', () => { 268 | const n = new NepaliDate('2080-03-26') 269 | expect(n.toString()).toBe('2080-03-26 00:00:00') 270 | }) 271 | 272 | it('should parse without month and date and times', () => { 273 | const n = new NepaliDate('2080') 274 | expect(n.toString()).toBe('2080-01-01 00:00:00') 275 | }) 276 | 277 | it('should parse without minute and seconds', () => { 278 | const n = new NepaliDate('2080-03-26 14') 279 | expect(n.toString()).toBe('2080-03-26 14:00:00') 280 | }) 281 | 282 | it('should parse both date and time with milliseconds', () => { 283 | const n = new NepaliDate('2080-03-26 18:15:24.689') 284 | expect(n.toString()).toBe('2080-03-26 18:15:24.689') 285 | }) 286 | 287 | it('should parse both date and time ignoring invalid milliseconds', () => { 288 | const n = new NepaliDate('2080-03-26 18:15:24.hello') 289 | expect(n.toString()).toBe('2080-03-26 18:15:24') 290 | }) 291 | }) 292 | 293 | describe('NepaliDate with Time feature initialization', () => { 294 | // Test case for time support 295 | it('should support hours', () => { 296 | const n = new NepaliDate(2080, 1, 12, 1) 297 | expect(n.getHours()).toBe(1) 298 | expect(n.getMinutes()).toBe(0) 299 | expect(n.getSeconds()).toBe(0) 300 | expect(n.getMilliseconds()).toBe(0) 301 | }) 302 | 303 | it('should support minutes', () => { 304 | const n = new NepaliDate(2080, 1, 12, 1, 2) 305 | expect(n.getHours()).toBe(1) 306 | expect(n.getMinutes()).toBe(2) 307 | expect(n.getSeconds()).toBe(0) 308 | expect(n.getMilliseconds()).toBe(0) 309 | }) 310 | 311 | it('should support seconds', () => { 312 | const n = new NepaliDate(2080, 1, 12, 1, 2, 3) 313 | expect(n.getHours()).toBe(1) 314 | expect(n.getMinutes()).toBe(2) 315 | expect(n.getSeconds()).toBe(3) 316 | expect(n.getMilliseconds()).toBe(0) 317 | }) 318 | 319 | it('should support milliseconds', () => { 320 | const n = new NepaliDate(2080, 1, 12, 1, 2, 3, 4) 321 | expect(n.getHours()).toBe(1) 322 | expect(n.getMinutes()).toBe(2) 323 | expect(n.getSeconds()).toBe(3) 324 | expect(n.getMilliseconds()).toBe(4) 325 | }) 326 | 327 | // Test case for valid time components 328 | it('should not throw an error for valid time components', () => { 329 | const [year, month, day] = [2080, 1, 12] 330 | const hour = 12 331 | const minute = 30 332 | const second = 45 333 | const ms = 500 334 | 335 | expect(() => { 336 | const _ = new NepaliDate(year, month, day, hour, minute, second, ms) 337 | }).not.toThrow() 338 | }) 339 | 340 | // Test cases for invalid time components 341 | it('should throw a ValidationError for invalid hour', () => { 342 | const [year, month, day] = [2080, 1, 12] 343 | const hour = 24 344 | const minute = 30 345 | const second = 45 346 | const ms = 500 347 | 348 | expect(() => { 349 | const _ = new NepaliDate(year, month, day, hour, minute, second, ms) 350 | }).toThrowError(new ValidationError('Hour should be in the range 0-23')) 351 | }) 352 | 353 | it('should throw a ValidationError for invalid negative hour', () => { 354 | const [year, month, day] = [2080, 1, 12] 355 | const hour = -1 356 | const minute = 30 357 | const second = 45 358 | const ms = 500 359 | 360 | expect(() => { 361 | const _ = new NepaliDate(year, month, day, hour, minute, second, ms) 362 | }).toThrowError(new ValidationError('Hour should be in the range 0-23')) 363 | }) 364 | 365 | it('should throw a ValidationError for invalid minute', () => { 366 | const [year, month, day] = [2080, 1, 12] 367 | const hour = 12 368 | const minute = 60 369 | const second = 45 370 | const ms = 500 371 | 372 | expect(() => { 373 | const _ = new NepaliDate(year, month, day, hour, minute, second, ms) 374 | }).toThrowError(new ValidationError('Minute should be in the range 0-59')) 375 | }) 376 | 377 | it('should throw a ValidationError for invalid negative minute', () => { 378 | const [year, month, day] = [2080, 1, 12] 379 | const hour = 12 380 | const minute = -1 381 | const second = 45 382 | const ms = 500 383 | 384 | expect(() => { 385 | const _ = new NepaliDate(year, month, day, hour, minute, second, ms) 386 | }).toThrowError(new ValidationError('Minute should be in the range 0-59')) 387 | }) 388 | 389 | it('should throw a ValidationError for invalid second', () => { 390 | const [year, month, day] = [2080, 1, 12] 391 | const hour = 12 392 | const minute = 30 393 | const second = 60 394 | const ms = 500 395 | 396 | expect(() => { 397 | const _ = new NepaliDate(year, month, day, hour, minute, second, ms) 398 | }).toThrowError(new ValidationError('Second should be in the range 0-59')) 399 | }) 400 | 401 | it('should throw a ValidationError for invalid negative second', () => { 402 | const [year, month, day] = [2080, 1, 12] 403 | const hour = 12 404 | const minute = 30 405 | const second = -1 406 | const ms = 500 407 | 408 | expect(() => { 409 | const _ = new NepaliDate(year, month, day, hour, minute, second, ms) 410 | }).toThrowError(new ValidationError('Second should be in the range 0-59')) 411 | }) 412 | 413 | it('should throw a ValidationError for invalid millisecond', () => { 414 | const [year, month, day] = [2080, 1, 12] 415 | const hour = 12 416 | const minute = 30 417 | const second = 45 418 | const ms = 1000 419 | 420 | expect(() => { 421 | const _ = new NepaliDate(year, month, day, hour, minute, second, ms) 422 | }).toThrowError(new ValidationError('Millisecond should be in the range 0-999')) 423 | }) 424 | 425 | it('should throw a ValidationError for invalid negative millisecond', () => { 426 | const [year, month, day] = [2080, 1, 12] 427 | const hour = 12 428 | const minute = 30 429 | const second = 45 430 | const ms = -1 431 | 432 | expect(() => { 433 | const _ = new NepaliDate(year, month, day, hour, minute, second, ms) 434 | }).toThrowError(new ValidationError('Millisecond should be in the range 0-999')) 435 | }) 436 | 437 | // timezone support 438 | 439 | it('should set the Nepali hours and minutes from a given time when running on a different timezone system', () => { 440 | const t = 1686501122598 // Sun Jun 11 2023 22:17:02 GMT+0545 (Nepal Time) 441 | const n = new NepaliDate(t) 442 | 443 | expect(n.getHours()).toBe(22) 444 | expect(n.getMinutes()).toBe(17) 445 | }) 446 | 447 | it('should set the unix timestamp from a given nepali params when running on a different timezone system', () => { 448 | const n = new NepaliDate(2080, 1, 28, 22, 17, 2, 598) 449 | 450 | expect(n.getTime()).toBe(1686501122598) // Sun Jun 11 2023 22:17:02 GMT+0545 (Nepal Time) 451 | expect(n.getHours()).toBe(22) 452 | expect(n.getMinutes()).toBe(17) 453 | }) 454 | 455 | it('should support date and time params of past year with GMT+5:30', () => { 456 | // -807708794322 457 | // Sun May 28 1944 12:26:45 GMT+0000 458 | // Sun May 28 1944 17:56:45 GMT+0530 (Nepal Time) 459 | 460 | const n = new NepaliDate(2001, 1, 15, 17, 56, 45, 678) 461 | 462 | // checking timestamp 463 | expect(n.getTime()).toBe(-807708794322) 464 | 465 | // checking nepali calendar date 466 | expect(n.toString()).toBe('2001-02-15 17:56:45.678') 467 | 468 | // checking english calendar date 469 | expect(n.getEnglishYear()).toBe(1944) 470 | expect(n.getEnglishMonth()).toBe(4) 471 | expect(n.getEnglishDate()).toBe(28) 472 | expect(n.getDay()).toBe(0) 473 | }) 474 | 475 | it('should support timestamp of past year with GMT+5:30', () => { 476 | // -807708794322 477 | // Sun May 28 1944 12:26:45 GMT+0000 478 | // Sun May 28 1944 17:56:45 GMT+0530 (Nepal Time) 479 | 480 | const n = new NepaliDate(-807708794322) 481 | 482 | // checking timestamp 483 | expect(n.getTime()).toBe(-807708794322) 484 | 485 | // checking nepali calendar date 486 | expect(n.toString()).toBe('2001-02-15 17:56:45.678') 487 | 488 | // checking english calendar date 489 | expect(n.getEnglishYear()).toBe(1944) 490 | expect(n.getEnglishMonth()).toBe(4) 491 | expect(n.getEnglishDate()).toBe(28) 492 | expect(n.getDay()).toBe(0) 493 | }) 494 | 495 | it('should support date and time of recent year with GMT+5:45', () => { 496 | // 1685362305678 497 | // Mon May 29 2023 12:11:45 GMT+0000 498 | // Mon May 29 2023 17:56:45 GMT+0545 (Nepal Time) 499 | 500 | const n = new NepaliDate(2080, 1, 15, 17, 56, 45, 678) 501 | 502 | // checking timestamp 503 | expect(n.getTime()).toBe(1685362305678) 504 | 505 | // checking nepali calendar date 506 | expect(n.toString()).toBe('2080-02-15 17:56:45.678') 507 | 508 | // checking english calendar date 509 | expect(n.getEnglishYear()).toBe(2023) 510 | expect(n.getEnglishMonth()).toBe(4) 511 | expect(n.getEnglishDate()).toBe(29) 512 | expect(n.getDay()).toBe(1) 513 | }) 514 | 515 | it('should support timestamp of recent year with GMT+5:45', () => { 516 | // 1685362305678 517 | // Mon May 29 2023 12:11:45 GMT+0000 518 | // Mon May 29 2023 17:56:45 GMT+0545 (Nepal Time) 519 | 520 | const n = new NepaliDate(1685362305678) 521 | 522 | // checking timestamp 523 | expect(n.getTime()).toBe(1685362305678) 524 | 525 | // checking nepali calendar date 526 | expect(n.toString()).toBe('2080-02-15 17:56:45.678') 527 | 528 | // checking english calendar date 529 | expect(n.getEnglishYear()).toBe(2023) 530 | expect(n.getEnglishMonth()).toBe(4) 531 | expect(n.getEnglishDate()).toBe(29) 532 | expect(n.getDay()).toBe(1) 533 | }) 534 | 535 | it('should support date and time of edge of GMT+5:45', () => { 536 | // 504901800000 537 | // Tue Dec 31 1985 18:30:00 GMT+0000 538 | // Wed Jan 1 1986 00:15:00 GMT+05:45 (Nepal Time) 539 | 540 | const n = new NepaliDate(2042, 8, 17, 0, 0) 541 | 542 | // checking timestamp 543 | expect(n.getTime()).toBe(504901800000) 544 | 545 | // checking nepali calendar date 546 | expect(n.toString()).toBe('2042-09-17 00:15:00') 547 | 548 | // checking english calendar date 549 | expect(n.getEnglishYear()).toBe(1986) 550 | expect(n.getEnglishMonth()).toBe(0) 551 | expect(n.getEnglishDate()).toBe(1) 552 | expect(n.getDay()).toBe(3) 553 | }) 554 | 555 | it('should support timestamp of edge of GMT+5:45', () => { 556 | // 504901800000 557 | // Tue Dec 31 1985 18:30:00 GMT+0000 558 | // Wed Jan 1 1986 00:15:00 GMT+05:45 (Nepal Time) 559 | 560 | const n = new NepaliDate(504901800000) 561 | 562 | // checking timestamp 563 | expect(n.getTime()).toBe(504901800000) 564 | 565 | // checking nepali calendar date 566 | expect(n.toString()).toBe('2042-09-17 00:15:00') 567 | 568 | // checking english calendar date 569 | expect(n.getEnglishYear()).toBe(1986) 570 | expect(n.getEnglishMonth()).toBe(0) 571 | expect(n.getEnglishDate()).toBe(1) 572 | expect(n.getDay()).toBe(3) 573 | }) 574 | 575 | it('should support date and time of edge of GMT+5:30', () => { 576 | // 504901799999 577 | // Tue Dec 31 1985 18:29:59.999 GMT+0000 578 | // Tue Dec 31 1985 23:59:59.999 GMT+05:30 (Nepal Time) 579 | 580 | const n = new NepaliDate(2042, 8, 16, 23, 59, 59, 999) 581 | 582 | // checking timestamp 583 | expect(n.getTime()).toBe(504901799999) 584 | 585 | // checking nepali calendar date 586 | expect(n.toString()).toBe('2042-09-16 23:59:59.999') 587 | 588 | // checking english calendar date 589 | expect(n.getEnglishYear()).toBe(1985) 590 | expect(n.getEnglishMonth()).toBe(11) 591 | expect(n.getEnglishDate()).toBe(31) 592 | expect(n.getDay()).toBe(2) 593 | }) 594 | 595 | it('should support timestamp of edge of GMT+5:30', () => { 596 | // 504901799999 597 | // Tue Dec 31 1985 18:29:59.999 GMT+0000 598 | // Tue Dec 31 1985 23:59:59.999 GMT+05:30 (Nepal Time) 599 | 600 | const n = new NepaliDate(504901799999) 601 | 602 | // checking timestamp 603 | expect(n.getTime()).toBe(504901799999) 604 | 605 | // checking nepali calendar date 606 | expect(n.toString()).toBe('2042-09-16 23:59:59.999') 607 | 608 | // checking english calendar date 609 | expect(n.getEnglishYear()).toBe(1985) 610 | expect(n.getEnglishMonth()).toBe(11) 611 | expect(n.getEnglishDate()).toBe(31) 612 | expect(n.getDay()).toBe(2) 613 | }) 614 | 615 | it('should support date and time of edge of GMT+5:45 after 15 minutes', () => { 616 | // 504901860000 617 | // Tue Dec 31 1985 18:31:00 GMT+0000 618 | // Wed Jan 1 1986 00:16:00 GMT+05:45 (Nepal Time) 619 | 620 | const n = new NepaliDate(2042, 8, 17, 0, 16) 621 | 622 | // checking timestamp 623 | expect(n.getTime()).toBe(504901860000) 624 | 625 | // checking nepali calendar date 626 | expect(n.toString()).toBe('2042-09-17 00:16:00') 627 | 628 | // checking english calendar date 629 | expect(n.getEnglishYear()).toBe(1986) 630 | expect(n.getEnglishMonth()).toBe(0) 631 | expect(n.getEnglishDate()).toBe(1) 632 | expect(n.getDay()).toBe(3) 633 | }) 634 | 635 | it('should support timestamp of edge of GMT+5:45 after 15 minutes', () => { 636 | // 504901860000 637 | // Tue Dec 31 1985 18:31:00 GMT+0000 638 | // Wed Jan 1 1986 00:16:00 GMT+05:45 (Nepal Time) 639 | 640 | const n = new NepaliDate(504901860000) 641 | 642 | // checking timestamp 643 | expect(n.getTime()).toBe(504901860000) 644 | 645 | // checking nepali calendar date 646 | expect(n.toString()).toBe('2042-09-17 00:16:00') 647 | 648 | // checking english calendar date 649 | expect(n.getEnglishYear()).toBe(1986) 650 | expect(n.getEnglishMonth()).toBe(0) 651 | expect(n.getEnglishDate()).toBe(1) 652 | expect(n.getDay()).toBe(3) 653 | }) 654 | }) 655 | 656 | describe('NepaliDate with Time feature: set methods', () => { 657 | let nepaliDate: NepaliDate 658 | 659 | beforeEach(() => { 660 | nepaliDate = new NepaliDate() 661 | }) 662 | 663 | describe('setHours', () => { 664 | it('should set the hour on the current date and time', () => { 665 | const hour = 9 666 | nepaliDate.setHours(hour) 667 | 668 | expect(nepaliDate.getHours()).toBe(hour) 669 | }) 670 | 671 | it('should throw a ValidationError for invalid hour', () => { 672 | const invalidHour = 24 673 | expect(() => { 674 | nepaliDate.setHours(invalidHour) 675 | }).toThrowError(new ValidationError('Hour should be in the range 0-23')) 676 | }) 677 | }) 678 | 679 | describe('setMinutes', () => { 680 | it('should set the minute on the current date and time', () => { 681 | const minute = 30 682 | nepaliDate.setMinutes(minute) 683 | 684 | expect(nepaliDate.getMinutes()).toBe(minute) 685 | }) 686 | 687 | it('should throw a ValidationError for invalid minute', () => { 688 | const invalidMinute = 60 689 | expect(() => { 690 | nepaliDate.setMinutes(invalidMinute) 691 | }).toThrowError(new ValidationError('Minute should be in the range 0-59')) 692 | }) 693 | }) 694 | 695 | describe('setSeconds', () => { 696 | it('should set the second on the current date and time', () => { 697 | const second = 30 698 | nepaliDate.setSeconds(second) 699 | 700 | expect(nepaliDate.getSeconds()).toBe(second) 701 | }) 702 | 703 | it('should throw a ValidationError for invalid second', () => { 704 | const invalidSecond = 60 705 | expect(() => { 706 | nepaliDate.setSeconds(invalidSecond) 707 | }).toThrowError(new ValidationError('Second should be in the range 0-59')) 708 | }) 709 | }) 710 | 711 | describe('setMilliseconds', () => { 712 | it('should set the milliseconds on the current date and time', () => { 713 | const milliseconds = 30 714 | nepaliDate.setMilliseconds(milliseconds) 715 | 716 | expect(nepaliDate.getMilliseconds()).toBe(milliseconds) 717 | }) 718 | 719 | it('should throw a ValidationError for invalid milliseconds', () => { 720 | const invalidMillisecond = 1000 721 | expect(() => { 722 | nepaliDate.setMilliseconds(invalidMillisecond) 723 | }).toThrowError( 724 | new ValidationError('Millisecond should be in the range 0-999') 725 | ) 726 | }) 727 | }) 728 | 729 | describe('setTime', () => { 730 | it('should set the timestamp', () => { 731 | const timestamp = 1625097600000 // June 30, 2021 00:00:00 UTC 732 | nepaliDate.setTime(timestamp) 733 | expect(nepaliDate.getTime()).toBe(timestamp) 734 | }) 735 | }) 736 | }) 737 | 738 | describe('NepaliDate.getDaysOfMonth', () => { 739 | it('should return the correct number of days for a valid year and month', () => { 740 | const days = NepaliDate.getDaysOfMonth(2081, 8) 741 | expect(days).toBe(29) 742 | }) 743 | 744 | it('should return the correct number of days for a year 2000 and month 0', () => { 745 | const days = NepaliDate.getDaysOfMonth(2000, 0) 746 | expect(days).toBe(30) 747 | }) 748 | 749 | it('should return the correct number of days for a year 2099 and month 11', () => { 750 | const days = NepaliDate.getDaysOfMonth(2099, 11) 751 | expect(days).toBe(30) 752 | }) 753 | 754 | it('should throw an error if the year is below the valid range', () => { 755 | const invalidYear = dateConverter.npMinYear() - 1 756 | expect(() => NepaliDate.getDaysOfMonth(invalidYear, 0)).toThrow( 757 | 'Year out of range' 758 | ) 759 | }) 760 | 761 | it('should throw an error if the year is above the valid range', () => { 762 | const invalidYear = dateConverter.npMaxYear() + 1 763 | expect(() => NepaliDate.getDaysOfMonth(invalidYear, 0)).toThrow( 764 | 'Year out of range' 765 | ) 766 | }) 767 | 768 | it('should throw an error if the month is below 0', () => { 769 | const validYear = dateConverter.npMinYear() 770 | expect(() => NepaliDate.getDaysOfMonth(validYear, -1)).toThrow( 771 | 'Month out of range' 772 | ) 773 | }) 774 | 775 | it('should throw an error if the month is greater than 11', () => { 776 | const validYear = dateConverter.npMinYear() 777 | expect(() => NepaliDate.getDaysOfMonth(validYear, 12)).toThrow( 778 | 'Month out of range' 779 | ) 780 | }) 781 | }) 782 | 783 | describe('NepaliDate min max supported dates', () => { 784 | it('minSupportedDate should return the minimum English Date converted to Nepali Date', () => { 785 | const result = NepaliDate.minSupportedDate() 786 | 787 | expect(result).toBeInstanceOf(Date) 788 | expect(result.toISOString()).toEqual('1943-12-31T18:30:00.000Z') // comparing UTC time 789 | }) 790 | 791 | it('maxSupportedDate should return the maximum English Date converted to Nepali Date', () => { 792 | const result = NepaliDate.maxSupportedDate() 793 | 794 | expect(result).toBeInstanceOf(Date) 795 | expect(result.toISOString()).toEqual('2042-12-30T18:15:00.000Z') // comparing UTC time 796 | }) 797 | 798 | it('minSupportedNepaliDate should return the minimum NepaliDate object', () => { 799 | const expectedYear = dateConverter.npMinYear() 800 | const result = NepaliDate.minSupportedNepaliDate() 801 | 802 | expect(result).toBeInstanceOf(NepaliDate) 803 | expect(result.getYear()).toBe(expectedYear) 804 | expect(result.getMonth()).toBe(0) 805 | expect(result.getDate()).toBe(1) 806 | }) 807 | 808 | it('maxSupportedNepaliDate should return the maximum NepaliDate object', () => { 809 | const expectedYear = dateConverter.npMaxYear() 810 | const expectedMonth = 11 811 | const expectedDays = NepaliDate.getDaysOfMonth(expectedYear, expectedMonth) 812 | 813 | const result = NepaliDate.maxSupportedNepaliDate() 814 | 815 | expect(result).toBeInstanceOf(NepaliDate) 816 | expect(result.getYear()).toBe(expectedYear) 817 | expect(result.getMonth()).toBe(expectedMonth) 818 | expect(result.getDate()).toBe(expectedDays) 819 | }) 820 | 821 | it("should return minimum date 1944 of Nepal's time", () => { 822 | const originalWarn = console.warn 823 | console.warn = () => {} // hide deprecation warning 824 | expect(NepaliDate.minimum().toISOString()).toEqual( 825 | NepaliDate.minSupportedDate().toISOString() 826 | ) 827 | console.warn = originalWarn 828 | }) 829 | 830 | it("should return maximum date 2042 Dec last of Nepal's time", () => { 831 | const originalWarn = console.warn 832 | console.warn = () => {} // hide deprecation warning 833 | expect(NepaliDate.maximum().toISOString()).toEqual( 834 | NepaliDate.maxSupportedDate().toISOString() 835 | ) 836 | console.warn = originalWarn 837 | }) 838 | }) 839 | -------------------------------------------------------------------------------- /tests/dateConverter/dateConverter.test.ts: -------------------------------------------------------------------------------- 1 | import dateConverter from '../../src/dateConverter' 2 | 3 | describe('dateConverter date range', () => { 4 | it('test for dateConverter english date range', () => { 5 | expect(dateConverter.enMinYear()).toBe(1944) 6 | expect(dateConverter.enMaxYear()).toBe(2042) 7 | }) 8 | 9 | it('test for dateConverter english date range', () => { 10 | expect(dateConverter.npMinYear()).toBe(2000) 11 | expect(dateConverter.npMaxYear()).toBe(2099) 12 | }) 13 | }) 14 | 15 | describe('dateConverter englishToNepali', () => { 16 | test('should throw error on max year range', () => { 17 | expect(() => { 18 | dateConverter.englishToNepali(2060, 1, 4) 19 | }).toThrow('Date out of range') 20 | }) 21 | 22 | test('should throw error on min year range', () => { 23 | expect(() => { 24 | dateConverter.englishToNepali(1920, 1, 4) 25 | }).toThrow('Date out of range') 26 | }) 27 | 28 | test('should throw error on min month range', () => { 29 | expect(() => { 30 | dateConverter.englishToNepali(2023, -1, 4) 31 | }).toThrow('Date out of range') 32 | }) 33 | 34 | test('should throw error on max month range', () => { 35 | expect(() => { 36 | dateConverter.englishToNepali(2023, 12, 4) 37 | }).toThrow('Date out of range') 38 | }) 39 | 40 | test('should throw error on min day range', () => { 41 | expect(() => { 42 | dateConverter.englishToNepali(2023, 1, 0) 43 | }).toThrow('Date out of range') 44 | }) 45 | 46 | test('should throw error on max day range', () => { 47 | expect(() => { 48 | dateConverter.englishToNepali(2023, 1, 40) 49 | }).toThrow('Date out of range') 50 | }) 51 | 52 | test('should return valid past Nepali date', () => { 53 | const [y, m, d] = dateConverter.englishToNepali(1994, 7, 13) 54 | expect(y).toBe(2051) 55 | expect(m).toBe(3) 56 | expect(d).toBe(29) 57 | }) 58 | 59 | test('should return valid past Nepali date 2', () => { 60 | const [y, m, d] = dateConverter.englishToNepali(1944, 4, 28) 61 | expect(y).toBe(2001) 62 | expect(m).toBe(1) 63 | expect(d).toBe(15) 64 | }) 65 | 66 | test('should return valid recent Nepali date', () => { 67 | const [y, m, d] = dateConverter.englishToNepali(2023, 0, 28) 68 | expect(y).toBe(2079) 69 | expect(m).toBe(9) 70 | expect(d).toBe(14) 71 | }) 72 | 73 | test('should return valid future Nepali date', () => { 74 | const [y, m, d] = dateConverter.englishToNepali(2030, 10, 26) 75 | expect(y).toBe(2087) 76 | expect(m).toBe(7) 77 | expect(d).toBe(10) 78 | }) 79 | 80 | test('should return valid Nepali date for min edge date', () => { 81 | const [y, m, d] = dateConverter.englishToNepali(1944, 0, 1) 82 | expect(y).toBe(2000) 83 | expect(m).toBe(8) 84 | expect(d).toBe(17) 85 | }) 86 | 87 | test('should return valid Nepali date for max edge date', () => { 88 | const [y, m, d] = dateConverter.englishToNepali(2042, 11, 31) 89 | expect(y).toBe(2099) 90 | expect(m).toBe(8) 91 | expect(d).toBe(16) 92 | }) 93 | }) 94 | 95 | describe('dateConverter nepaliToEnglish', () => { 96 | it('should throw an error on max year range', () => { 97 | expect(() => { 98 | dateConverter.nepaliToEnglish(3000, 1, 4) 99 | }).toThrow('Date out of range') 100 | }) 101 | 102 | it('should throw an error on min year range', () => { 103 | expect(() => { 104 | dateConverter.nepaliToEnglish(1920, 1, 4) 105 | }).toThrow('Date out of range') 106 | }) 107 | 108 | it('should throw an error on min month range', () => { 109 | expect(() => { 110 | dateConverter.nepaliToEnglish(2079, -1, 4) 111 | }).toThrow('Date out of range') 112 | }) 113 | 114 | it('should throw an error on max month range', () => { 115 | expect(() => { 116 | dateConverter.nepaliToEnglish(2079, 12, 4) 117 | }).toThrow('Date out of range') 118 | }) 119 | 120 | it('should throw an error on min day range', () => { 121 | expect(() => { 122 | dateConverter.nepaliToEnglish(2079, 1, 0) 123 | }).toThrow('Date out of range') 124 | }) 125 | 126 | it('should throw an error on max day range', () => { 127 | expect(() => { 128 | dateConverter.nepaliToEnglish(2079, 1, 40) 129 | }).toThrow('Date out of range') 130 | }) 131 | 132 | it('should return valid past English date', () => { 133 | const [y, m, d] = dateConverter.nepaliToEnglish(2051, 3, 29) 134 | expect(y).toBe(1994) 135 | expect(m).toBe(7) 136 | expect(d).toBe(13) 137 | }) 138 | 139 | test('should return valid past English date 2', () => { 140 | const [y, m, d] = dateConverter.nepaliToEnglish(2001, 1, 15) 141 | expect(y).toBe(1944) 142 | expect(m).toBe(4) 143 | expect(d).toBe(28) 144 | }) 145 | 146 | it('should return valid recent English date', () => { 147 | const [y, m, d] = dateConverter.nepaliToEnglish(2079, 9, 14) 148 | expect(y).toBe(2023) 149 | expect(m).toBe(0) 150 | expect(d).toBe(28) 151 | }) 152 | 153 | it('should return valid future English date', () => { 154 | const [y, m, d] = dateConverter.nepaliToEnglish(2087, 7, 10) 155 | expect(y).toBe(2030) 156 | expect(m).toBe(10) 157 | expect(d).toBe(26) 158 | }) 159 | 160 | it('should return valid English leap year date', () => { 161 | const [y, m, d] = dateConverter.nepaliToEnglish(2080, 11, 15) 162 | expect(y).toBe(2024) 163 | expect(m).toBe(2) 164 | expect(d).toBe(28) 165 | }) 166 | 167 | it('should return valid English date for min edge date', () => { 168 | const [y, m, d] = dateConverter.nepaliToEnglish(2000, 0, 1) 169 | expect(y).toBe(1943) 170 | expect(m).toBe(3) 171 | expect(d).toBe(14) 172 | }) 173 | 174 | it('should return valid English date for max edge date', () => { 175 | const [y, m, d] = dateConverter.nepaliToEnglish(2099, 11, 30) 176 | expect(y).toBe(2043) 177 | expect(m).toBe(3) 178 | expect(d).toBe(13) 179 | }) 180 | }) 181 | -------------------------------------------------------------------------------- /tests/format/format.test.ts: -------------------------------------------------------------------------------- 1 | import { format, formatNepali, nepaliDateToString } from '../../src/format' 2 | import NepaliDate from '../../src/NepaliDate' 3 | 4 | describe('format', () => { 5 | const nepaliDate1 = new NepaliDate(2080, 1, 32, 7, 40) 6 | const nepaliDate2 = new NepaliDate(2080, 1, 8, 20, 55, 32) 7 | const nepaliDate3 = new NepaliDate(2080, 8, 15, 16, 9, 40, 413) 8 | 9 | it('should format NepaliDate for the provided format string', () => { 10 | const formatStr = 'YYYY-MM-DD' 11 | const formattedDate = format(nepaliDate1, formatStr) 12 | expect(formattedDate).toEqual('2080-02-32') 13 | }) 14 | 15 | it('should format NepaliDate for the provided format string with normal text', () => { 16 | const formatStr = '[Hello] YYYY-MM-DD [World]!' 17 | const formattedDate = format(nepaliDate1, formatStr) 18 | expect(formattedDate).toEqual('Hello 2080-02-32 World!') 19 | }) 20 | 21 | it('should handle a format string with repeated formats', () => { 22 | const formatStr = 'YYYY YYYY' 23 | const formattedDate = format(nepaliDate1, formatStr) 24 | expect(formattedDate).toEqual('2080 2080') 25 | }) 26 | 27 | it('should handle a format string with multiple formats', () => { 28 | const formatStr = 'YYYY-MM-DD HH:mm' 29 | const formattedDate = format(nepaliDate1, formatStr) 30 | expect(formattedDate).toEqual('2080-02-32 07:40') 31 | }) 32 | 33 | it('should handle a format string with unknown formats', () => { 34 | const formatStr = 'YYYY-QQ-DD HH:mm:ss' 35 | const formattedDate = format(nepaliDate1, formatStr) 36 | expect(formattedDate).toEqual('2080-QQ-32 07:40:00') 37 | }) 38 | 39 | it('should format NepaliDate with the non leading zeros format', () => { 40 | const formatStr = 'YYYY-M-D' 41 | const formattedDate = format(nepaliDate2, formatStr) 42 | expect(formattedDate).toEqual('2080-2-8') 43 | }) 44 | 45 | it('should not format NepaliDate for extended format size', () => { 46 | const formatStr = 'YYYYY-MMMMM-DDD dddddd HHH hhh:mmm:sss:SSSS AA aa' 47 | const formattedDate = format(nepaliDate1, formatStr) 48 | expect(formattedDate).toEqual( 49 | '2080Y-Jestha2-3232 ThursdayThu 077 077:4040:000:000S AMAM amam' 50 | ) 51 | }) 52 | 53 | /* individual format tests (positive cases) */ 54 | 55 | it('should format NepaliDate for YYYY: 4 digit year', () => { 56 | const formatStr = 'YYYY' 57 | const formattedDate = format(nepaliDate1, formatStr) 58 | expect(formattedDate).toEqual('2080') 59 | }) 60 | 61 | it('should format NepaliDate for YY: 2 digit year', () => { 62 | const formatStr = 'YY' 63 | const formattedDate = format(nepaliDate1, formatStr) 64 | expect(formattedDate).toEqual('80') 65 | }) 66 | 67 | it('should format NepaliDate for MMMM: full month name', () => { 68 | const formatStr = 'MMMM' 69 | const formattedDate = format(nepaliDate1, formatStr) 70 | expect(formattedDate).toEqual('Jestha') 71 | }) 72 | 73 | it('should format NepaliDate for MMM: month abbr name', () => { 74 | const formatStr = 'MMM' 75 | const formattedDate = format(nepaliDate1, formatStr) 76 | expect(formattedDate).toEqual('Jes') 77 | }) 78 | 79 | it('should format NepaliDate for MM: month', () => { 80 | const formatStr = 'MM' 81 | const formattedDate = format(nepaliDate1, formatStr) 82 | expect(formattedDate).toEqual('02') 83 | }) 84 | 85 | it('should format NepaliDate for M: month with non leading zero', () => { 86 | const formatStr = 'M' 87 | const formattedDate = format(nepaliDate1, formatStr) 88 | expect(formattedDate).toEqual('2') 89 | }) 90 | 91 | it('should format NepaliDate for DD: day', () => { 92 | const formatStr = 'DD' 93 | const formattedDate = format(nepaliDate1, formatStr) 94 | expect(formattedDate).toEqual('32') 95 | }) 96 | 97 | it('should format NepaliDate for D: day', () => { 98 | const formatStr = 'D' 99 | const formattedDate = format(nepaliDate1, formatStr) 100 | expect(formattedDate).toEqual('32') 101 | }) 102 | 103 | it('should format NepaliDate for dddd: week day name', () => { 104 | const formatStr = 'dddd' 105 | const formattedDate = format(nepaliDate1, formatStr) 106 | expect(formattedDate).toEqual('Thursday') 107 | }) 108 | 109 | it('should format NepaliDate for ddd: week day abbr name', () => { 110 | const formatStr = 'ddd' 111 | const formattedDate = format(nepaliDate1, formatStr) 112 | expect(formattedDate).toEqual('Thu') 113 | }) 114 | 115 | it('should format NepaliDate for dd: week day abbr name', () => { 116 | const formatStr = 'dd' 117 | const formattedDate = format(nepaliDate1, formatStr) 118 | expect(formattedDate).toEqual('Thu') 119 | }) 120 | 121 | it('should format NepaliDate for d: week day number', () => { 122 | const formatStr = 'd' 123 | const formattedDate = format(nepaliDate1, formatStr) 124 | expect(formattedDate).toEqual('4') 125 | }) 126 | 127 | it('should format NepaliDate for HH: 24-hour', () => { 128 | const formatStr = 'HH' 129 | const formattedDate = format(nepaliDate1, formatStr) 130 | expect(formattedDate).toEqual('07') 131 | }) 132 | 133 | it('should format NepaliDate for H: 24-hour', () => { 134 | const formatStr = 'H' 135 | const formattedDate = format(nepaliDate3, formatStr) 136 | expect(formattedDate).toEqual('16') 137 | }) 138 | 139 | it('should format NepaliDate for hh: 12-hour', () => { 140 | const formatStr = 'hh' 141 | const formattedDate = format(nepaliDate2, formatStr) 142 | expect(formattedDate).toEqual('08') 143 | }) 144 | 145 | it("should format NepaliDate for hh: 12-hour after 12 o'clock", () => { 146 | const formatStr = 'hh' 147 | const formattedDate = format(nepaliDate1, formatStr) 148 | expect(formattedDate).toEqual('07') 149 | }) 150 | 151 | it('should format NepaliDate for h: 12-hour', () => { 152 | const formatStr = 'h' 153 | const formattedDate = format(nepaliDate3, formatStr) 154 | expect(formattedDate).toEqual('4') 155 | }) 156 | 157 | it('should format NepaliDate for mm: minute', () => { 158 | const formatStr = 'mm' 159 | const formattedDate = format(nepaliDate3, formatStr) 160 | expect(formattedDate).toEqual('09') 161 | }) 162 | 163 | it('should format NepaliDate for m: minute', () => { 164 | const formatStr = 'm' 165 | const formattedDate = format(nepaliDate2, formatStr) 166 | expect(formattedDate).toEqual('55') 167 | }) 168 | 169 | it('should format NepaliDate for ss: second', () => { 170 | const formatStr = 'ss' 171 | const formattedDate = format(nepaliDate1, formatStr) 172 | expect(formattedDate).toEqual('00') 173 | }) 174 | 175 | it('should format NepaliDate for s: second', () => { 176 | const formatStr = 's' 177 | const formattedDate = format(nepaliDate3, formatStr) 178 | expect(formattedDate).toEqual('40') 179 | }) 180 | 181 | it('should format NepaliDate for SSS: millisecond', () => { 182 | const formatStr = 'SSS' 183 | const formattedDate = format(nepaliDate3, formatStr) 184 | expect(formattedDate).toEqual('413') 185 | }) 186 | 187 | it('should format NepaliDate of 1digit ms for SSS: millisecond', () => { 188 | const formatStr = 'SSS' 189 | const d = new NepaliDate(2080, 2, 26, 1, 2, 3, 4) 190 | const formattedDate = format(d, formatStr) 191 | expect(formattedDate).toEqual('004') 192 | }) 193 | 194 | it('should format NepaliDate of 2digit ms for SSS: millisecond', () => { 195 | const formatStr = 'SSS' 196 | const d = new NepaliDate(2080, 2, 26, 1, 2, 3, 41) 197 | const formattedDate = format(d, formatStr) 198 | expect(formattedDate).toEqual('041') 199 | }) 200 | 201 | it('should format NepaliDate (AM) for A: Uppercase AM/PM indicator (e.g., AM, PM)', () => { 202 | const formatStr = 'A' 203 | const formattedDate = format(nepaliDate1, formatStr) 204 | expect(formattedDate).toEqual('AM') 205 | }) 206 | 207 | it('should format NepaliDate (PM) for A: Uppercase AM/PM indicator (e.g., AM, PM)', () => { 208 | const formatStr = 'A' 209 | const formattedDate = format(nepaliDate3, formatStr) 210 | expect(formattedDate).toEqual('PM') 211 | }) 212 | 213 | it('should format NepaliDate (AM) for a: Lowercase AM/PM indicator (e.g., am, pm)', () => { 214 | const formatStr = 'a' 215 | const formattedDate = format(nepaliDate1, formatStr) 216 | expect(formattedDate).toEqual('am') 217 | }) 218 | 219 | it('should format NepaliDate (PM) for a: Lowercase AM/PM indicator (e.g., am, pm)', () => { 220 | const formatStr = 'a' 221 | const formattedDate = format(nepaliDate3, formatStr) 222 | expect(formattedDate).toEqual('pm') 223 | }) 224 | 225 | it('should format NepaliDate (AM) for midnight', () => { 226 | const nepaliDate = new NepaliDate(2079, 5, 3) 227 | const formatStr = 'A' 228 | const formattedDate = format(nepaliDate, formatStr) 229 | expect(formattedDate).toEqual('AM') 230 | }) 231 | 232 | it('should format NepaliDate (PM) for noon', () => { 233 | const nepaliDate = new NepaliDate(2079, 5, 3, 12) 234 | const formatStr = 'A' 235 | const formattedDate = format(nepaliDate, formatStr) 236 | expect(formattedDate).toEqual('PM') 237 | }) 238 | }) 239 | 240 | describe('formatNepali', () => { 241 | const nepaliDate1 = new NepaliDate(2080, 1, 32, 7, 40) 242 | const nepaliDate2 = new NepaliDate(2080, 1, 8, 20, 55, 32) 243 | const nepaliDate3 = new NepaliDate(2080, 8, 15, 16, 9, 40, 413) 244 | 245 | it('should format NepaliDate for the provided format string', () => { 246 | const formatStr = 'YYYY-MM-DD' 247 | const formattedDate = formatNepali(nepaliDate1, formatStr) 248 | expect(formattedDate).toEqual('२०८०-०२-३२') 249 | }) 250 | 251 | it('should format NepaliDate for the provided format string with normal text', () => { 252 | const formatStr = '[Hello] YYYY-MM-DD [World!]' 253 | const formattedDate = formatNepali(nepaliDate1, formatStr) 254 | expect(formattedDate).toEqual('Hello २०८०-०२-३२ World!') 255 | }) 256 | 257 | it('should handle a format string with repeated formats', () => { 258 | const formatStr = 'YYYY YYYY' 259 | const formattedDate = formatNepali(nepaliDate1, formatStr) 260 | expect(formattedDate).toEqual('२०८० २०८०') 261 | }) 262 | 263 | it('should handle a format string with multiple formats', () => { 264 | const formatStr = 'YYYY-MM-DD HH:mm' 265 | const formattedDate = formatNepali(nepaliDate1, formatStr) 266 | expect(formattedDate).toEqual('२०८०-०२-३२ ०७:४०') 267 | }) 268 | 269 | it('should handle a format string with unknown formats', () => { 270 | const formatStr = 'YYYY-QQ-DD HH:mm:ss' 271 | const formattedDate = formatNepali(nepaliDate1, formatStr) 272 | expect(formattedDate).toEqual('२०८०-QQ-३२ ०७:४०:००') 273 | }) 274 | 275 | it('should format NepaliDate with the non leading zeros format', () => { 276 | const formatStr = 'YYYY-M-D' 277 | const formattedDate = formatNepali(nepaliDate2, formatStr) 278 | expect(formattedDate).toEqual('२०८०-२-८') 279 | }) 280 | 281 | it('should not format NepaliDate for extended format size', () => { 282 | const formatStr = 'YYYYY-MMMMM-DDD dddddd HHH hhh:mmm:sss:SSSS A a' 283 | const formattedDate = formatNepali(nepaliDate1, formatStr) 284 | expect(formattedDate).toEqual( 285 | '२०८०Y-जेठ२-३२३२ बिहिबारबिहि ०७७ ०७७:४०४०:०००:०००S एम एम' 286 | ) 287 | }) 288 | 289 | /* individual format tests (positive cases) */ 290 | 291 | it('should format NepaliDate for YYYY: 4 digit year', () => { 292 | const formatStr = 'YYYY' 293 | const formattedDate = formatNepali(nepaliDate1, formatStr) 294 | expect(formattedDate).toEqual('२०८०') 295 | }) 296 | 297 | it('should format NepaliDate for YY: 2 digit year', () => { 298 | const formatStr = 'YY' 299 | const formattedDate = formatNepali(nepaliDate1, formatStr) 300 | expect(formattedDate).toEqual('८०') 301 | }) 302 | 303 | it('should format NepaliDate for MMMM: full month name', () => { 304 | const formatStr = 'MMMM' 305 | const formattedDate = formatNepali(nepaliDate1, formatStr) 306 | expect(formattedDate).toEqual('जेठ') 307 | }) 308 | 309 | it('should format NepaliDate for MMM: month abbr name', () => { 310 | const formatStr = 'MMM' 311 | const formattedDate = formatNepali(nepaliDate1, formatStr) 312 | expect(formattedDate).toEqual('जे') 313 | }) 314 | 315 | it('should format NepaliDate for MM: month', () => { 316 | const formatStr = 'MM' 317 | const formattedDate = formatNepali(nepaliDate1, formatStr) 318 | expect(formattedDate).toEqual('०२') 319 | }) 320 | 321 | it('should format NepaliDate for M: month with non leading zero', () => { 322 | const formatStr = 'M' 323 | const formattedDate = formatNepali(nepaliDate1, formatStr) 324 | expect(formattedDate).toEqual('२') 325 | }) 326 | 327 | it('should format NepaliDate for DD: day', () => { 328 | const formatStr = 'DD' 329 | const formattedDate = formatNepali(nepaliDate1, formatStr) 330 | expect(formattedDate).toEqual('३२') 331 | }) 332 | 333 | it('should format NepaliDate for D: day', () => { 334 | const formatStr = 'D' 335 | const formattedDate = formatNepali(nepaliDate1, formatStr) 336 | expect(formattedDate).toEqual('३२') 337 | }) 338 | 339 | it('should format NepaliDate for dddd: week day name', () => { 340 | const formatStr = 'dddd' 341 | const formattedDate = formatNepali(nepaliDate1, formatStr) 342 | expect(formattedDate).toEqual('बिहिबार') 343 | }) 344 | 345 | it('should format NepaliDate for ddd: week day abbr name', () => { 346 | const formatStr = 'ddd' 347 | const formattedDate = formatNepali(nepaliDate1, formatStr) 348 | expect(formattedDate).toEqual('बिहि') 349 | }) 350 | 351 | it('should format NepaliDate for dd: week day abbr name', () => { 352 | const formatStr = 'dd' 353 | const formattedDate = formatNepali(nepaliDate1, formatStr) 354 | expect(formattedDate).toEqual('बिहि') 355 | }) 356 | 357 | it('should format NepaliDate for d: week day number', () => { 358 | const formatStr = 'd' 359 | const formattedDate = formatNepali(nepaliDate1, formatStr) 360 | expect(formattedDate).toEqual('४') 361 | }) 362 | 363 | it('should format NepaliDate for HH: 24-hour', () => { 364 | const formatStr = 'HH' 365 | const formattedDate = formatNepali(nepaliDate1, formatStr) 366 | expect(formattedDate).toEqual('०७') 367 | }) 368 | 369 | it('should format NepaliDate for H: 24-hour', () => { 370 | const formatStr = 'H' 371 | const formattedDate = formatNepali(nepaliDate3, formatStr) 372 | expect(formattedDate).toEqual('१६') 373 | }) 374 | 375 | it('should format NepaliDate for hh: 12-hour', () => { 376 | const formatStr = 'hh' 377 | const formattedDate = formatNepali(nepaliDate1, formatStr) 378 | expect(formattedDate).toEqual('०७') 379 | }) 380 | 381 | it('should format NepaliDate for hh: 12-hour', () => { 382 | const formatStr = 'hh' 383 | const formattedDate = formatNepali(nepaliDate2, formatStr) 384 | expect(formattedDate).toEqual('०८') 385 | }) 386 | 387 | it('should format NepaliDate for h: 12-hour', () => { 388 | const formatStr = 'h' 389 | const formattedDate = formatNepali(nepaliDate3, formatStr) 390 | expect(formattedDate).toEqual('४') 391 | }) 392 | 393 | it('should format NepaliDate for mm: minute', () => { 394 | const formatStr = 'mm' 395 | const formattedDate = formatNepali(nepaliDate3, formatStr) 396 | expect(formattedDate).toEqual('०९') 397 | }) 398 | 399 | it('should format NepaliDate for m: minute', () => { 400 | const formatStr = 'm' 401 | const formattedDate = formatNepali(nepaliDate2, formatStr) 402 | expect(formattedDate).toEqual('५५') 403 | }) 404 | 405 | it('should format NepaliDate for ss: second', () => { 406 | const formatStr = 'ss' 407 | const formattedDate = formatNepali(nepaliDate1, formatStr) 408 | expect(formattedDate).toEqual('००') 409 | }) 410 | 411 | it('should format NepaliDate for s: second', () => { 412 | const formatStr = 's' 413 | const formattedDate = formatNepali(nepaliDate3, formatStr) 414 | expect(formattedDate).toEqual('४०') 415 | }) 416 | 417 | it('should format NepaliDate for SSS: millisecond', () => { 418 | const formatStr = 'SSS' 419 | const formattedDate = formatNepali(nepaliDate3, formatStr) 420 | expect(formattedDate).toEqual('४१३') 421 | }) 422 | 423 | it('should format NepaliDate of 1digit ms for SSS: millisecond', () => { 424 | const formatStr = 'SSS' 425 | const d = new NepaliDate(2080, 2, 26, 1, 2, 3, 4) 426 | const formattedDate = formatNepali(d, formatStr) 427 | expect(formattedDate).toEqual('००४') 428 | }) 429 | 430 | it('should format NepaliDate of 2digit ms for SSS: millisecond', () => { 431 | const formatStr = 'SSS' 432 | const d = new NepaliDate(2080, 2, 26, 1, 2, 3, 41) 433 | const formattedDate = formatNepali(d, formatStr) 434 | expect(formattedDate).toEqual('०४१') 435 | }) 436 | 437 | it('should format NepaliDate (AM) for A', () => { 438 | const formatStr = 'A' 439 | const formattedDate = formatNepali(nepaliDate1, formatStr) 440 | expect(formattedDate).toEqual('एम') 441 | }) 442 | 443 | it('should format NepaliDate (PM) for A', () => { 444 | const formatStr = 'A' 445 | const formattedDate = formatNepali(nepaliDate3, formatStr) 446 | expect(formattedDate).toEqual('पिम') 447 | }) 448 | 449 | it('should format NepaliDate (AM) for a', () => { 450 | const formatStr = 'a' 451 | const formattedDate = formatNepali(nepaliDate1, formatStr) 452 | expect(formattedDate).toEqual('एम') 453 | }) 454 | 455 | it('should format NepaliDate (PM) for a', () => { 456 | const formatStr = 'a' 457 | const formattedDate = formatNepali(nepaliDate3, formatStr) 458 | expect(formattedDate).toEqual('पिम') 459 | }) 460 | }) 461 | 462 | describe('nepaliDateToString', () => { 463 | it('should format NepaliDate in YYYY-MM-DD HH:mm:ss format', () => { 464 | const nepaliDate = new NepaliDate(2080, 2, 26, 21, 2, 23) 465 | const toString = nepaliDateToString(nepaliDate) 466 | expect(toString).toBe('2080-03-26 21:02:23') 467 | }) 468 | 469 | it('should format NepaliDate in YYYY-MM-DD HH:mm:ss.SSS format', () => { 470 | const nepaliDate = new NepaliDate(2080, 2, 26, 21, 2, 23, 689) 471 | const toString = nepaliDateToString(nepaliDate) 472 | expect(toString).toBe('2080-03-26 21:02:23.689') 473 | }) 474 | }) 475 | -------------------------------------------------------------------------------- /tests/format/formatEnglishDate.test.ts: -------------------------------------------------------------------------------- 1 | import { formatEnglishDate, formatEnglishDateInNepali } from '../../src/format' 2 | import NepaliDate from '../../src/NepaliDate' 3 | 4 | describe('formatEnglishDate', () => { 5 | const nepaliDate1 = new NepaliDate(2080, 1, 32, 7, 40) 6 | const nepaliDate2 = new NepaliDate(2080, 1, 8, 20, 55, 32) 7 | const nepaliDate3 = new NepaliDate(2080, 8, 15, 16, 9, 40, 413) 8 | 9 | it('should format NepaliDate for the provided format string', () => { 10 | const formatStr = 'YYYY-MM-DD' 11 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 12 | expect(formattedDate).toEqual('2023-06-15') 13 | }) 14 | 15 | it('should format NepaliDate for the provided format string with normal text', () => { 16 | const formatStr = '[Hello] YYYY-MM-DD [World]!' 17 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 18 | expect(formattedDate).toEqual('Hello 2023-06-15 World!') 19 | }) 20 | 21 | it('should handle a format string with repeated formats', () => { 22 | const formatStr = 'YYYY YYYY' 23 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 24 | expect(formattedDate).toEqual('2023 2023') 25 | }) 26 | 27 | it('should handle a format string with multiple formats', () => { 28 | const formatStr = 'YYYY-MM-DD HH:mm' 29 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 30 | expect(formattedDate).toEqual('2023-06-15 07:40') 31 | }) 32 | 33 | it('should handle a format string with unknown formats', () => { 34 | const formatStr = 'YYYY-QQ-DD HH:mm:ss' 35 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 36 | expect(formattedDate).toEqual('2023-QQ-15 07:40:00') 37 | }) 38 | 39 | it('should format NepaliDate with the non leading zeros format', () => { 40 | const formatStr = 'YYYY-M-D' 41 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 42 | expect(formattedDate).toEqual('2023-6-15') 43 | }) 44 | 45 | it('should not format NepaliDate for extended format size', () => { 46 | const formatStr = 'YYYYY-MMMMM-DDD dddddd HHH hhh:mmm:sss:SSSS AA aa' 47 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 48 | expect(formattedDate).toEqual( 49 | '2023Y-June6-1515 ThursdayThu 077 077:4040:000:000S AMAM amam' 50 | ) 51 | }) 52 | 53 | /* individual format tests (positive cases) */ 54 | 55 | it('should format NepaliDate for YYYY: 4 digit year', () => { 56 | const formatStr = 'YYYY' 57 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 58 | expect(formattedDate).toEqual('2023') 59 | }) 60 | 61 | it('should format NepaliDate for YY: 2 digit year', () => { 62 | const formatStr = 'YY' 63 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 64 | expect(formattedDate).toEqual('23') 65 | }) 66 | 67 | it('should format NepaliDate for MMMM: full month name', () => { 68 | const formatStr = 'MMMM' 69 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 70 | expect(formattedDate).toEqual('June') 71 | }) 72 | 73 | it('should format NepaliDate for MMM: month abbr name', () => { 74 | const formatStr = 'MMM' 75 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 76 | expect(formattedDate).toEqual('Jun') 77 | }) 78 | 79 | it('should format NepaliDate for MM: month', () => { 80 | const formatStr = 'MM' 81 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 82 | expect(formattedDate).toEqual('06') 83 | }) 84 | 85 | it('should format NepaliDate for M: month with non leading zero', () => { 86 | const formatStr = 'M' 87 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 88 | expect(formattedDate).toEqual('6') 89 | }) 90 | 91 | it('should format NepaliDate for DD: day', () => { 92 | const formatStr = 'DD' 93 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 94 | expect(formattedDate).toEqual('15') 95 | }) 96 | 97 | it('should format NepaliDate for D: day', () => { 98 | const formatStr = 'D' 99 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 100 | expect(formattedDate).toEqual('15') 101 | }) 102 | 103 | it('should format NepaliDate for dddd: week day name', () => { 104 | const formatStr = 'dddd' 105 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 106 | expect(formattedDate).toEqual('Thursday') 107 | }) 108 | 109 | it('should format NepaliDate for ddd: week day abbr name', () => { 110 | const formatStr = 'ddd' 111 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 112 | expect(formattedDate).toEqual('Thu') 113 | }) 114 | 115 | it('should format NepaliDate for dd: week day abbr name', () => { 116 | const formatStr = 'dd' 117 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 118 | expect(formattedDate).toEqual('Thu') 119 | }) 120 | 121 | it('should format NepaliDate for d: week day number', () => { 122 | const formatStr = 'd' 123 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 124 | expect(formattedDate).toEqual('4') 125 | }) 126 | 127 | it('should format NepaliDate for HH: 24-hour', () => { 128 | const formatStr = 'HH' 129 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 130 | expect(formattedDate).toEqual('07') 131 | }) 132 | 133 | it('should format NepaliDate for H: 24-hour', () => { 134 | const formatStr = 'H' 135 | const formattedDate = formatEnglishDate(nepaliDate3, formatStr) 136 | expect(formattedDate).toEqual('16') 137 | }) 138 | 139 | it('should format NepaliDate for hh: 12-hour', () => { 140 | const formatStr = 'hh' 141 | const formattedDate = formatEnglishDate(nepaliDate2, formatStr) 142 | expect(formattedDate).toEqual('08') 143 | }) 144 | 145 | it("should format NepaliDate for hh: 12-hour after 12 o'clock", () => { 146 | const formatStr = 'hh' 147 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 148 | expect(formattedDate).toEqual('07') 149 | }) 150 | 151 | it('should format NepaliDate for h: 12-hour', () => { 152 | const formatStr = 'h' 153 | const formattedDate = formatEnglishDate(nepaliDate3, formatStr) 154 | expect(formattedDate).toEqual('4') 155 | }) 156 | 157 | it('should format NepaliDate for mm: minute', () => { 158 | const formatStr = 'mm' 159 | const formattedDate = formatEnglishDate(nepaliDate3, formatStr) 160 | expect(formattedDate).toEqual('09') 161 | }) 162 | 163 | it('should format NepaliDate for m: minute', () => { 164 | const formatStr = 'm' 165 | const formattedDate = formatEnglishDate(nepaliDate2, formatStr) 166 | expect(formattedDate).toEqual('55') 167 | }) 168 | 169 | it('should format NepaliDate for ss: second', () => { 170 | const formatStr = 'ss' 171 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 172 | expect(formattedDate).toEqual('00') 173 | }) 174 | 175 | it('should format NepaliDate for s: second', () => { 176 | const formatStr = 's' 177 | const formattedDate = formatEnglishDate(nepaliDate3, formatStr) 178 | expect(formattedDate).toEqual('40') 179 | }) 180 | 181 | it('should format NepaliDate for SSS: millisecond', () => { 182 | const formatStr = 'SSS' 183 | const formattedDate = formatEnglishDate(nepaliDate3, formatStr) 184 | expect(formattedDate).toEqual('413') 185 | }) 186 | 187 | it('should format NepaliDate of 1digit ms for SSS: millisecond', () => { 188 | const formatStr = 'SSS' 189 | const d = new NepaliDate(2080, 2, 26, 1, 2, 3, 4) 190 | const formattedDate = formatEnglishDate(d, formatStr) 191 | expect(formattedDate).toEqual('004') 192 | }) 193 | 194 | it('should format NepaliDate of 2digit ms for SSS: millisecond', () => { 195 | const formatStr = 'SSS' 196 | const d = new NepaliDate(2080, 2, 26, 1, 2, 3, 41) 197 | const formattedDate = formatEnglishDate(d, formatStr) 198 | expect(formattedDate).toEqual('041') 199 | }) 200 | 201 | it('should format NepaliDate (AM) for A: Uppercase AM/PM indicator (e.g., AM, PM)', () => { 202 | const formatStr = 'A' 203 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 204 | expect(formattedDate).toEqual('AM') 205 | }) 206 | 207 | it('should format NepaliDate (PM) for A: Uppercase AM/PM indicator (e.g., AM, PM)', () => { 208 | const formatStr = 'A' 209 | const formattedDate = formatEnglishDate(nepaliDate3, formatStr) 210 | expect(formattedDate).toEqual('PM') 211 | }) 212 | 213 | it('should format NepaliDate (AM) for a: Lowercase AM/PM indicator (e.g., am, pm)', () => { 214 | const formatStr = 'a' 215 | const formattedDate = formatEnglishDate(nepaliDate1, formatStr) 216 | expect(formattedDate).toEqual('am') 217 | }) 218 | 219 | it('should format NepaliDate (PM) for a: Lowercase AM/PM indicator (e.g., am, pm)', () => { 220 | const formatStr = 'a' 221 | const formattedDate = formatEnglishDate(nepaliDate3, formatStr) 222 | expect(formattedDate).toEqual('pm') 223 | }) 224 | 225 | it('should format NepaliDate (AM) for midnight', () => { 226 | const nepaliDate = new NepaliDate(2079, 5, 3) 227 | const formatStr = 'A' 228 | const formattedDate = formatEnglishDate(nepaliDate, formatStr) 229 | expect(formattedDate).toEqual('AM') 230 | }) 231 | 232 | it('should format NepaliDate (PM) for noon', () => { 233 | const nepaliDate = new NepaliDate(2079, 5, 3, 12) 234 | const formatStr = 'A' 235 | const formattedDate = formatEnglishDate(nepaliDate, formatStr) 236 | expect(formattedDate).toEqual('PM') 237 | }) 238 | }) 239 | 240 | describe('formatEnglishDateInNepali', () => { 241 | const nepaliDate1 = new NepaliDate(2080, 1, 32, 7, 40) 242 | const nepaliDate2 = new NepaliDate(2080, 1, 8, 20, 55, 32) 243 | const nepaliDate3 = new NepaliDate(2080, 8, 15, 16, 9, 40, 413) 244 | 245 | it('should format NepaliDate for the provided format string', () => { 246 | const formatStr = 'YYYY-MM-DD' 247 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 248 | expect(formattedDate).toEqual('२०२३-०६-१५') 249 | }) 250 | 251 | it('should format NepaliDate for the provided format string with normal text', () => { 252 | const formatStr = '[Hello] YYYY-MM-DD [World]!' 253 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 254 | expect(formattedDate).toEqual('Hello २०२३-०६-१५ World!') 255 | }) 256 | 257 | it('should handle a format string with repeated formats', () => { 258 | const formatStr = 'YYYY YYYY' 259 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 260 | expect(formattedDate).toEqual('२०२३ २०२३') 261 | }) 262 | 263 | it('should handle a format string with multiple formats', () => { 264 | const formatStr = 'YYYY-MM-DD HH:mm' 265 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 266 | expect(formattedDate).toEqual('२०२३-०६-१५ ०७:४०') 267 | }) 268 | 269 | it('should handle a format string with unknown formats', () => { 270 | const formatStr = 'YYYY-QQ-DD HH:mm:ss' 271 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 272 | expect(formattedDate).toEqual('२०२३-QQ-१५ ०७:४०:००') 273 | }) 274 | 275 | it('should format NepaliDate with the non leading zeros format', () => { 276 | const formatStr = 'YYYY-M-D' 277 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 278 | expect(formattedDate).toEqual('२०२३-६-१५') 279 | }) 280 | 281 | it('should not format NepaliDate for extended format size', () => { 282 | const formatStr = 'YYYYY-MMMMM-DDD dddddd HHH hhh:mmm:sss:SSSS A a' 283 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 284 | expect(formattedDate).toEqual( 285 | '२०२३Y-जुन६-१५१५ बिहिबारबिहि ०७७ ०७७:४०४०:०००:०००S एम एम' 286 | ) 287 | }) 288 | 289 | /* individual format tests (positive cases) */ 290 | 291 | it('should format NepaliDate for YYYY: 4 digit year', () => { 292 | const formatStr = 'YYYY' 293 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 294 | expect(formattedDate).toEqual('२०२३') 295 | }) 296 | 297 | it('should format NepaliDate for YY: 2 digit year', () => { 298 | const formatStr = 'YY' 299 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 300 | expect(formattedDate).toEqual('२३') 301 | }) 302 | 303 | it('should format NepaliDate for MMMM: full month name', () => { 304 | const formatStr = 'MMMM' 305 | const formattedDate = formatEnglishDateInNepali(nepaliDate3, formatStr) 306 | expect(formattedDate).toEqual('डिसेम्बर') 307 | }) 308 | 309 | it('should format NepaliDate for MMM: month abbr name', () => { 310 | const formatStr = 'MMM' 311 | const formattedDate = formatEnglishDateInNepali(nepaliDate3, formatStr) 312 | expect(formattedDate).toEqual('डिसे') 313 | }) 314 | 315 | it('should format NepaliDate for MM: month', () => { 316 | const formatStr = 'MM' 317 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 318 | expect(formattedDate).toEqual('०६') 319 | }) 320 | 321 | it('should format NepaliDate for M: month with non leading zero', () => { 322 | const formatStr = 'M' 323 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 324 | expect(formattedDate).toEqual('६') 325 | }) 326 | 327 | it('should format NepaliDate for DD: day', () => { 328 | const formatStr = 'DD' 329 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 330 | expect(formattedDate).toEqual('१५') 331 | }) 332 | 333 | it('should format NepaliDate for D: day', () => { 334 | const formatStr = 'D' 335 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 336 | expect(formattedDate).toEqual('१५') 337 | }) 338 | 339 | it('should format NepaliDate for dddd: week day name', () => { 340 | const formatStr = 'dddd' 341 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 342 | expect(formattedDate).toEqual('बिहिबार') 343 | }) 344 | 345 | it('should format NepaliDate for ddd: week day abbr name', () => { 346 | const formatStr = 'ddd' 347 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 348 | expect(formattedDate).toEqual('बिहि') 349 | }) 350 | 351 | it('should format NepaliDate for dd: week day abbr name', () => { 352 | const formatStr = 'dd' 353 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 354 | expect(formattedDate).toEqual('बिहि') 355 | }) 356 | 357 | it('should format NepaliDate for d: week day number', () => { 358 | const formatStr = 'd' 359 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 360 | expect(formattedDate).toEqual('४') 361 | }) 362 | 363 | it('should format NepaliDate for HH: 24-hour', () => { 364 | const formatStr = 'HH' 365 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 366 | expect(formattedDate).toEqual('०७') 367 | }) 368 | 369 | it('should format NepaliDate for H: 24-hour', () => { 370 | const formatStr = 'H' 371 | const formattedDate = formatEnglishDateInNepali(nepaliDate3, formatStr) 372 | expect(formattedDate).toEqual('१६') 373 | }) 374 | 375 | it('should format NepaliDate for hh: 12-hour', () => { 376 | const formatStr = 'hh' 377 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 378 | expect(formattedDate).toEqual('०७') 379 | }) 380 | 381 | it('should format NepaliDate for hh: 12-hour', () => { 382 | const formatStr = 'hh' 383 | const formattedDate = formatEnglishDateInNepali(nepaliDate2, formatStr) 384 | expect(formattedDate).toEqual('०८') 385 | }) 386 | 387 | it('should format NepaliDate for h: 12-hour', () => { 388 | const formatStr = 'h' 389 | const formattedDate = formatEnglishDateInNepali(nepaliDate3, formatStr) 390 | expect(formattedDate).toEqual('४') 391 | }) 392 | 393 | it('should format NepaliDate for mm: minute', () => { 394 | const formatStr = 'mm' 395 | const formattedDate = formatEnglishDateInNepali(nepaliDate3, formatStr) 396 | expect(formattedDate).toEqual('०९') 397 | }) 398 | 399 | it('should format NepaliDate for m: minute', () => { 400 | const formatStr = 'm' 401 | const formattedDate = formatEnglishDateInNepali(nepaliDate2, formatStr) 402 | expect(formattedDate).toEqual('५५') 403 | }) 404 | 405 | it('should format NepaliDate for ss: second', () => { 406 | const formatStr = 'ss' 407 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 408 | expect(formattedDate).toEqual('००') 409 | }) 410 | 411 | it('should format NepaliDate for s: second', () => { 412 | const formatStr = 's' 413 | const formattedDate = formatEnglishDateInNepali(nepaliDate3, formatStr) 414 | expect(formattedDate).toEqual('४०') 415 | }) 416 | 417 | it('should format NepaliDate for SSS: millisecond', () => { 418 | const formatStr = 'SSS' 419 | const formattedDate = formatEnglishDateInNepali(nepaliDate3, formatStr) 420 | expect(formattedDate).toEqual('४१३') 421 | }) 422 | 423 | it('should format NepaliDate of 1digit ms for SSS: millisecond', () => { 424 | const formatStr = 'SSS' 425 | const d = new NepaliDate(2080, 2, 26, 1, 2, 3, 4) 426 | const formattedDate = formatEnglishDateInNepali(d, formatStr) 427 | expect(formattedDate).toEqual('००४') 428 | }) 429 | 430 | it('should format NepaliDate of 2digit ms for SSS: millisecond', () => { 431 | const formatStr = 'SSS' 432 | const d = new NepaliDate(2080, 2, 26, 1, 2, 3, 41) 433 | const formattedDate = formatEnglishDateInNepali(d, formatStr) 434 | expect(formattedDate).toEqual('०४१') 435 | }) 436 | 437 | it('should format NepaliDate (AM) for A', () => { 438 | const formatStr = 'A' 439 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 440 | expect(formattedDate).toEqual('एम') 441 | }) 442 | 443 | it('should format NepaliDate (PM) for A', () => { 444 | const formatStr = 'A' 445 | const formattedDate = formatEnglishDateInNepali(nepaliDate3, formatStr) 446 | expect(formattedDate).toEqual('पिम') 447 | }) 448 | 449 | it('should format NepaliDate (AM) for a', () => { 450 | const formatStr = 'a' 451 | const formattedDate = formatEnglishDateInNepali(nepaliDate1, formatStr) 452 | expect(formattedDate).toEqual('एम') 453 | }) 454 | 455 | it('should format NepaliDate (PM) for a', () => { 456 | const formatStr = 'a' 457 | const formattedDate = formatEnglishDateInNepali(nepaliDate3, formatStr) 458 | expect(formattedDate).toEqual('पिम') 459 | }) 460 | }) 461 | -------------------------------------------------------------------------------- /tests/parse/parse.test.ts: -------------------------------------------------------------------------------- 1 | import { parseFormat } from '../../src/parse' 2 | 3 | describe('parseFormat', () => { 4 | it('should parse date string in valid format correctly', () => { 5 | expect(parseFormat('2080-08-02 12:34:56', 'YYYY-MM-DD HH:mm:ss')).toEqual([ 6 | 2080, 7, 2, 12, 34, 56, 0, 7 | ]) 8 | }) 9 | 10 | it('should parse date string with milliseconds', () => { 11 | expect( 12 | parseFormat('2080-08-02 12:34:56.789', 'YYYY-MM-DD HH:mm:ss.SSS') 13 | ).toEqual([2080, 7, 2, 12, 34, 56, 789]) 14 | }) 15 | 16 | it('should parse date string with leading zeros in format', () => { 17 | expect(parseFormat('2080-08-02 09:05:07', 'YYYY-MM-DD HH:mm:ss')).toEqual([ 18 | 2080, 7, 2, 9, 5, 7, 0, 19 | ]) 20 | }) 21 | 22 | it('should parse date string with 2digit year and single-digit month and day', () => { 23 | expect(parseFormat('80-8-2 12:34:56', 'YY-M-D HH:mm:ss')).toEqual([ 24 | 2080, 7, 2, 12, 34, 56, 0, 25 | ]) 26 | }) 27 | 28 | it('should parse date string with 12-hour format', () => { 29 | expect(parseFormat('2080-08-02 05:34:56 PM', 'YYYY-MM-DD hh:mm:ss A')).toEqual([ 30 | 2080, 7, 2, 17, 34, 56, 0, 31 | ]) 32 | }) 33 | 34 | it("should parse date string with 12-hour format before 12 o'clock", () => { 35 | expect(parseFormat('2080-08-02 05:34:56 AM', 'YYYY-MM-DD hh:mm:ss A')).toEqual([ 36 | 2080, 7, 2, 5, 34, 56, 0, 37 | ]) 38 | }) 39 | 40 | it('should parse date string with static text in format', () => { 41 | expect( 42 | parseFormat( 43 | 'Year: 2080, Month: 08, Day: 02', 44 | '[Year]: YYYY, [Month]: MM, [Day]: DD' 45 | ) 46 | ).toEqual([2080, 7, 2, 0, 0, 0, 0]) 47 | }) 48 | 49 | it('should throw error for invalid format, missing time components', () => { 50 | expect(() => { 51 | parseFormat('2080-08-02', 'YYYY-MM-DD HH:mm:ss') 52 | }).toThrowError(Error) 53 | }) 54 | 55 | it('should throw error for invalid format, without static text', () => { 56 | expect(() => { 57 | parseFormat('2080-08-02 12:34:56 test', 'YYYY-MM-DD HH:mm:ss') 58 | }).toThrowError(Error) 59 | }) 60 | 61 | it('should parse date string with month in Devanagari format', () => { 62 | expect(parseFormat('2080, Shrawan 23', 'YYYY, MMMM DD')).toEqual([ 63 | 2080, 3, 23, 0, 0, 0, 0, 64 | ]) 65 | }) 66 | 67 | it('should parse date string with month in Devanagari format with time', () => { 68 | expect( 69 | parseFormat('2080, Shrawan 23, 10:16:30', 'YYYY, MMMM DD, HH:mm:ss') 70 | ).toEqual([2080, 3, 23, 10, 16, 30, 0]) 71 | }) 72 | 73 | it('should throw error with month in Devanagari format and missing literals', () => { 74 | expect(() => 75 | parseFormat('2080/Shrawan/23', 'YYYY/MMMM/DD HH:mm:ss') 76 | ).toThrowError(Error) 77 | }) 78 | 79 | it('should parse date string with month in short Devanagari format', () => { 80 | expect(parseFormat('2080, Shr 23', 'YYYY, MMM DD')).toEqual([ 81 | 2080, 3, 23, 0, 0, 0, 0, 82 | ]) 83 | }) 84 | 85 | it('should parse date string with month in short Devanagari format with time', () => { 86 | expect(parseFormat('2080, Shr 23, 10:16:30', 'YYYY, MMM DD, HH:mm:ss')).toEqual( 87 | [2080, 3, 23, 10, 16, 30, 0] 88 | ) 89 | }) 90 | 91 | it('should throw error with month in short Devanagari format and missing literals', () => { 92 | expect(() => parseFormat('2080/Shr/23', 'YYYY/MMM/DD HH:mm:ss')).toThrowError( 93 | Error 94 | ) 95 | }) 96 | 97 | it('should parse weekday fullname', () => { 98 | expect(parseFormat('Wednesday', 'dddd')).toEqual([0, 0, 1, 0, 0, 0, 0]) 99 | }) 100 | 101 | it('should parse weekday short name', () => { 102 | expect(parseFormat('Wed', 'ddd')).toEqual([0, 0, 1, 0, 0, 0, 0]) 103 | }) 104 | 105 | it('should parse weekday short 2 letter name', () => { 106 | expect(parseFormat('Wed', 'dd')).toEqual([0, 0, 1, 0, 0, 0, 0]) 107 | }) 108 | 109 | it('should parse weekday number', () => { 110 | expect(parseFormat('3', 'd')).toEqual([0, 0, 1, 0, 0, 0, 0]) 111 | }) 112 | 113 | it('should throw error on random weekday number', () => { 114 | expect(() => parseFormat('7', 'd')).toThrowError(Error) 115 | }) 116 | 117 | it('should throw error on random weekday name', () => { 118 | expect(() => parseFormat('we', 'dd')).toThrowError(Error) 119 | }) 120 | 121 | it('should parse nothing', () => { 122 | expect(parseFormat('Yellow', 'Yellow')).toEqual([0, 0, 1, 0, 0, 0, 0]) 123 | }) 124 | }) 125 | -------------------------------------------------------------------------------- /tests/parse/parseEnglishDate.test.ts: -------------------------------------------------------------------------------- 1 | import { parseEnglishDateFormat } from '../../src/parse' 2 | 3 | describe('parseEnglishDateFormat', () => { 4 | it('should parse date string in valid format correctly', () => { 5 | expect( 6 | parseEnglishDateFormat('2024-08-02 12:34:56', 'YYYY-MM-DD HH:mm:ss') 7 | ).toEqual([2024, 7, 2, 12, 34, 56, 0]) 8 | }) 9 | 10 | it('should parse date string with milliseconds', () => { 11 | expect( 12 | parseEnglishDateFormat('2024-08-02 12:34:56.789', 'YYYY-MM-DD HH:mm:ss.SSS') 13 | ).toEqual([2024, 7, 2, 12, 34, 56, 789]) 14 | }) 15 | 16 | it('should parse date string with leading zeros in format', () => { 17 | expect( 18 | parseEnglishDateFormat('2024-08-02 09:05:07', 'YYYY-MM-DD HH:mm:ss') 19 | ).toEqual([2024, 7, 2, 9, 5, 7, 0]) 20 | }) 21 | 22 | it('should parse date string with 2digit year and single-digit month and day', () => { 23 | expect(parseEnglishDateFormat('24-8-2 12:34:56', 'YY-M-D HH:mm:ss')).toEqual([ 24 | 2024, 7, 2, 12, 34, 56, 0, 25 | ]) 26 | }) 27 | 28 | it('should parse date string with 12-hour format', () => { 29 | expect( 30 | parseEnglishDateFormat('2024-08-02 05:34:56 PM', 'YYYY-MM-DD hh:mm:ss A') 31 | ).toEqual([2024, 7, 2, 17, 34, 56, 0]) 32 | }) 33 | 34 | it("should parse date string with 12-hour format before 12 o'clock", () => { 35 | expect( 36 | parseEnglishDateFormat('2024-08-02 05:34:56 AM', 'YYYY-MM-DD hh:mm:ss A') 37 | ).toEqual([2024, 7, 2, 5, 34, 56, 0]) 38 | }) 39 | 40 | it('should parse date string with static text in format', () => { 41 | expect( 42 | parseEnglishDateFormat( 43 | 'Year: 2024, Month: 08, Day: 02', 44 | '[Year]: YYYY, [Month]: MM, [Day]: DD' 45 | ) 46 | ).toEqual([2024, 7, 2, 0, 0, 0, 0]) 47 | }) 48 | 49 | it('should throw error for invalid format, missing time components', () => { 50 | expect(() => { 51 | parseEnglishDateFormat('2024-08-02', 'YYYY-MM-DD HH:mm:ss') 52 | }).toThrowError(Error) 53 | }) 54 | 55 | it('should throw error for invalid format, without static text', () => { 56 | expect(() => { 57 | parseEnglishDateFormat('2024-08-02 12:34:56 test', 'YYYY-MM-DD HH:mm:ss') 58 | }).toThrowError(Error) 59 | }) 60 | 61 | it('should parse date string with full month text', () => { 62 | expect(parseEnglishDateFormat('2024, August 23', 'YYYY, MMMM DD')).toEqual([ 63 | 2024, 7, 23, 0, 0, 0, 0, 64 | ]) 65 | }) 66 | 67 | it('should parse date string with full month text with time', () => { 68 | expect( 69 | parseEnglishDateFormat( 70 | '2024, August 23, 10:16:30', 71 | 'YYYY, MMMM DD, HH:mm:ss' 72 | ) 73 | ).toEqual([2024, 7, 23, 10, 16, 30, 0]) 74 | }) 75 | 76 | it('should throw error with full month text and missing literals', () => { 77 | expect(() => 78 | parseEnglishDateFormat('2024/August/23', 'YYYY/MMMM/DD HH:mm:ss') 79 | ).toThrowError(Error) 80 | }) 81 | 82 | it('should parse date string with short month text', () => { 83 | expect(parseEnglishDateFormat('2024, Aug 23', 'YYYY, MMM DD')).toEqual([ 84 | 2024, 7, 23, 0, 0, 0, 0, 85 | ]) 86 | }) 87 | 88 | it('should parse date string with short month text with time', () => { 89 | expect( 90 | parseEnglishDateFormat('2024, Aug 23, 10:16:30', 'YYYY, MMM DD, HH:mm:ss') 91 | ).toEqual([2024, 7, 23, 10, 16, 30, 0]) 92 | }) 93 | 94 | it('should throw error with short month text and missing literals', () => { 95 | expect(() => 96 | parseEnglishDateFormat('2024/Aug/23', 'YYYY/MMM/DD HH:mm:ss') 97 | ).toThrowError(Error) 98 | }) 99 | 100 | it('should parse weekday fullname', () => { 101 | expect(parseEnglishDateFormat('Wednesday', 'dddd')).toEqual([ 102 | 0, 0, 1, 0, 0, 0, 0, 103 | ]) 104 | }) 105 | 106 | it('should parse weekday short name', () => { 107 | expect(parseEnglishDateFormat('Wed', 'ddd')).toEqual([0, 0, 1, 0, 0, 0, 0]) 108 | }) 109 | 110 | it('should parse weekday short 2 letter name', () => { 111 | expect(parseEnglishDateFormat('Wed', 'dd')).toEqual([0, 0, 1, 0, 0, 0, 0]) 112 | }) 113 | 114 | it('should parse weekday number', () => { 115 | expect(parseEnglishDateFormat('3', 'd')).toEqual([0, 0, 1, 0, 0, 0, 0]) 116 | }) 117 | 118 | it('should throw error on random weekday number', () => { 119 | expect(() => parseEnglishDateFormat('7', 'd')).toThrowError(Error) 120 | }) 121 | 122 | it('should throw error on random weekday name', () => { 123 | expect(() => parseEnglishDateFormat('we', 'dd')).toThrowError(Error) 124 | }) 125 | 126 | it('should parse nothing', () => { 127 | expect(parseEnglishDateFormat('Yellow', 'Yellow')).toEqual([ 128 | 0, 0, 1, 0, 0, 0, 0, 129 | ]) 130 | }) 131 | }) 132 | -------------------------------------------------------------------------------- /tests/utils.test.ts: -------------------------------------------------------------------------------- 1 | import { parseFormatTokens, seqToRE } from '../src/utils' 2 | 3 | describe('parseFormatTokens', () => { 4 | it('should parse format "YYYY"', () => { 5 | expect(parseFormatTokens('YYYY')).toEqual(['YYYY']) 6 | }) 7 | 8 | it('should parse format "YYYY-MM-DD"', () => { 9 | expect(parseFormatTokens('YYYY-MM-DD')).toEqual(['YYYY', '-', 'MM', '-', 'DD']) 10 | }) 11 | 12 | it('should parse format "YYYYY"', () => { 13 | expect(parseFormatTokens('YYYYY')).toEqual(['YYYY', 'Y']) 14 | }) 15 | 16 | it('should parse format "YYY"', () => { 17 | expect(parseFormatTokens('YYY')).toEqual(['YY', 'Y']) 18 | }) 19 | 20 | it('should parse format "WETUIPQNBVCXZ"', () => { 21 | expect(parseFormatTokens('WETUIPQNBVCXZ')).toEqual([ 22 | 'W', 23 | 'E', 24 | 'T', 25 | 'U', 26 | 'I', 27 | 'P', 28 | 'Q', 29 | 'N', 30 | 'B', 31 | 'V', 32 | 'C', 33 | 'X', 34 | 'Z', 35 | ]) 36 | }) 37 | 38 | it('should parse format "YYYYWETUIPQNBVCXZ"', () => { 39 | expect(parseFormatTokens('YYYYWETUIPQNBVCXZ')).toEqual([ 40 | 'YYYY', 41 | 'W', 42 | 'E', 43 | 'T', 44 | 'U', 45 | 'I', 46 | 'P', 47 | 'Q', 48 | 'N', 49 | 'B', 50 | 'V', 51 | 'C', 52 | 'X', 53 | 'Z', 54 | ]) 55 | }) 56 | 57 | it('should parse format "YYYYWETUIPQNBVCXZDD"', () => { 58 | expect(parseFormatTokens('YYYYWETUIPQNBVCXZDD')).toEqual([ 59 | 'YYYY', 60 | 'W', 61 | 'E', 62 | 'T', 63 | 'U', 64 | 'I', 65 | 'P', 66 | 'Q', 67 | 'N', 68 | 'B', 69 | 'V', 70 | 'C', 71 | 'X', 72 | 'Z', 73 | 'DD', 74 | ]) 75 | }) 76 | 77 | it('should parse format "YYYY \'ello DD"', () => { 78 | expect(parseFormatTokens("YYYY 'ello DD")).toEqual([ 79 | 'YYYY', 80 | ' ', 81 | "'", 82 | 'e', 83 | 'l', 84 | 'l', 85 | 'o', 86 | ' ', 87 | 'DD', 88 | ]) 89 | }) 90 | 91 | it('should parse format "YYYY-MM-DD HH:mm:ss:SSS"', () => { 92 | expect(parseFormatTokens('YYYY-MM-DD HH:mm:ss:SSS')).toEqual([ 93 | 'YYYY', 94 | '-', 95 | 'MM', 96 | '-', 97 | 'DD', 98 | ' ', 99 | 'HH', 100 | ':', 101 | 'mm', 102 | ':', 103 | 'ss', 104 | ':', 105 | 'SSS', 106 | ]) 107 | }) 108 | 109 | it('should parse format "[[[]]]"', () => { 110 | expect(parseFormatTokens('[[[]]]')).toEqual(['[', '[', ']]']) 111 | }) 112 | 113 | it('should parse format "[[', () => { 114 | expect(parseFormatTokens('[[')).toEqual(['[', '[']) 115 | }) 116 | 117 | it('should parse format "]]"', () => { 118 | expect(parseFormatTokens(']]')).toEqual([']', ']']) 119 | }) 120 | 121 | it('should parse format "[[]]"', () => { 122 | expect(parseFormatTokens('[[]]')).toEqual(['[', ']']) 123 | }) 124 | 125 | it('should parse format "[[]', () => { 126 | expect(parseFormatTokens('[[]')).toEqual(['[', '']) 127 | }) 128 | 129 | it('should parse format "[]]"', () => { 130 | expect(parseFormatTokens('[]]')).toEqual([']']) 131 | }) 132 | 133 | it('should parse format "[[Y]]"', () => { 134 | expect(parseFormatTokens('[[Y]]')).toEqual(['[', 'Y]']) 135 | }) 136 | 137 | it('should parse format "[YYYY"', () => { 138 | expect(parseFormatTokens('[YYYY')).toEqual(['[', 'YYYY']) 139 | }) 140 | 141 | it('should parse format "[Y]"', () => { 142 | expect(parseFormatTokens('[Y]')).toEqual(['Y']) 143 | }) 144 | 145 | it('should parse format "Today is dddd"', () => { 146 | expect(parseFormatTokens('Today is dddd')).toEqual([ 147 | 'T', 148 | 'o', 149 | 'd', 150 | 'a', 151 | 'y', 152 | ' ', 153 | 'i', 154 | 's', 155 | ' ', 156 | 'dddd', 157 | ]) 158 | }) 159 | 160 | it('should parse format "[Today is ]dddd"', () => { 161 | expect(parseFormatTokens('[Today is ]dddd')).toEqual(['Today is ', 'dddd']) 162 | }) 163 | 164 | it('should parse format "YYY[Today is ]dddd"', () => { 165 | expect(parseFormatTokens('YYY[Today is ]dddd')).toEqual([ 166 | 'YY', 167 | 'Y', 168 | 'Today is ', 169 | 'dddd', 170 | ]) 171 | }) 172 | 173 | it("should returns empty doesn't match with FORMAT_TOKEN_REGEX", () => { 174 | expect(parseFormatTokens('')).toEqual([]) 175 | }) 176 | }) 177 | 178 | describe('seqToRE', () => { 179 | it('runs seqToRE', () => { 180 | const myArray = ['a', 'b', 'c'] 181 | let res = seqToRE(myArray) 182 | 183 | expect(res).toEqual(/(a|b|c)/) 184 | }) 185 | 186 | it('handles almost duplicate array strings', () => { 187 | const myArray = ['abc', 'abcdef', 'abcd', 'abcde'] 188 | let res = seqToRE(myArray) 189 | 190 | expect(res).toEqual(/(abcdef|abcde|abcd|abc)/) 191 | }) 192 | 193 | it('handles empty array', () => { 194 | const emptyArray: Array = [] 195 | let res = seqToRE(emptyArray) 196 | 197 | expect(res).toEqual(/(?:)/) 198 | }) 199 | 200 | it('handles empty string in array', () => { 201 | const arrayWithEmptyString = [''] 202 | let res = seqToRE(arrayWithEmptyString) 203 | 204 | expect(res).toEqual(/(?:)/) 205 | }) 206 | }) 207 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "rootDir": "src", 6 | "declaration": true, 7 | "sourceMap": true, 8 | "outDir": "dist", 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noImplicitAny": true, 12 | "skipLibCheck": true, 13 | "moduleResolution": "node" 14 | }, 15 | "ts-node": { 16 | "transpileOnly": true, 17 | "compilerOptions": { 18 | "module": "commonjs" 19 | } 20 | }, 21 | "include": ["src"], 22 | "exclude": ["node_modules", "dist", "tests"] 23 | } 24 | --------------------------------------------------------------------------------