UNPKG

dutyhours

Version:

A tool to calculate total working hours in a given month, taking into account public holidays and configurable working days.

1 lines 12.7 kB
{"version":3,"sources":["../src/index.ts","../bin/cli.ts","../package.json"],"sourcesContent":["import Holidays from 'date-holidays';\n\nexport interface Options {\n /**\n * The country code to determine the public holidays. In ISO 3166-1 alpha-2 format.\n * For example, 'US' for United States, 'PL' for Poland, etc.\n * @type {string}\n */\n country: string;\n\n /**\n * The number of working hours in a single working day.\n * @type {number}\n * @default 8\n *\n */\n hoursPerDay?: number;\n\n /**\n * Whether to include Mondays as working days.\n * @type {boolean}\n * @default true\n */\n withMondays?: boolean;\n\n /**\n * Whether to include Tuesdays as working days.\n * @type {boolean}\n * @default true\n */\n withTuesdays?: boolean;\n\n /**\n * Whether to include Wednesdays as working days.\n * @type {boolean}\n * @default true\n */\n withWednesdays?: boolean;\n\n /**\n * Whether to include Thursdays as working days.\n * @type {boolean}\n * @default true\n */\n withThursdays?: boolean;\n\n /**\n * Whether to include Fridays as working days.\n * @type {boolean}\n * @default true\n */\n withFridays?: boolean;\n\n /**\n * Whether to include Saturdays as working days.\n * @type {boolean}\n * @default false\n */\n withSaturdays?: boolean;\n\n /**\n * Whether to include Sundays as working days.\n * @type {boolean}\n * @default false\n */\n withSundays?: boolean;\n\n /**\n * Whether to exclude Mondays from working days.\n * @type {boolean}\n * @default false\n */\n withoutMondays?: boolean;\n\n /**\n * Whether to exclude Tuesdays from working days.\n * @type {boolean}\n * @default false\n */\n withoutTuesdays?: boolean;\n\n /**\n * Whether to exclude Wednesdays from working days.\n * @type {boolean}\n * @default false\n */\n withoutWednesdays?: boolean;\n\n /**\n * Whether to exclude Thursdays from working days.\n * @type {boolean}\n * @default false\n */\n withoutThursdays?: boolean;\n\n /**\n * Whether to exclude Fridays from working days.\n * @type {boolean}\n * @default false\n */\n withoutFridays?: boolean;\n\n /**\n * Whether to exclude Saturdays from working days.\n * @type {boolean}\n * @default true\n */\n withoutSaturdays?: boolean;\n\n /**\n * Whether to exclude Sundays from working days.\n * @type {boolean}\n * @default true\n */\n withoutSundays?: boolean;\n\n /**\n * The month (indexed from 1 to 12) to calculate working hours for. Defaults to the current month.\n * @type {number}\n */\n month?: number;\n\n /**\n * The year to calculate working hours for. Defaults to the current year.\n * @type {number}\n */\n year?: number;\n}\n\nconst DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] as const;\n\ntype DayName = (typeof DAY_NAMES)[number];\n\nfunction isWorkingDay(dayIndex: number, options: Options): boolean {\n const dayName = DAY_NAMES[dayIndex] as DayName;\n\n if (options[`without${dayName}s` as keyof Options]) return false;\n if (options[`with${dayName}s` as keyof Options]) return true;\n\n // Default to Monday-Friday as working days\n return dayIndex >= 1 && dayIndex <= 5;\n}\n\nfunction getHolidaysForMonth(year: number, month: number, country: string): Set<string> {\n const hd = new Holidays(country);\n const startOfMonth = new Date(year, month - 1, 1);\n const endOfMonth = new Date(year, month, 0);\n\n return new Set(\n hd\n .getHolidays(year)\n .filter(({ date, type }) => {\n const holidayDate = new Date(date);\n return holidayDate >= startOfMonth && holidayDate <= endOfMonth && type !== 'observance';\n })\n .map(({ date }) => new Date(date).toDateString())\n );\n}\n\n/**\n * Calculates the total number of working hours in a given month.\n * @param options Configuration options\n * @returns Total working hours\n */\nfunction calculateWorkingHours(options: Options): number {\n const today = new Date();\n const { country, hoursPerDay = 8, month = today.getMonth() + 1, year = today.getFullYear() } = options;\n\n const holidays = getHolidaysForMonth(year, month, country);\n const endOfMonth = new Date(year, month, 0);\n\n let workingHours = 0;\n\n for (let day = 1; day <= endOfMonth.getDate(); day++) {\n const currentDate = new Date(year, month - 1, day);\n const dayIndex = currentDate.getDay();\n\n if (!holidays.has(currentDate.toDateString()) && isWorkingDay(dayIndex, options)) {\n workingHours += hoursPerDay;\n }\n }\n\n return workingHours;\n}\n\nexport default calculateWorkingHours;\n","#!/usr/bin/env node\nimport calculateWorkingHours from '@@';\nimport { Option, program } from 'commander';\n\nimport packageJson from '../package.json';\n\nprogram\n .version(packageJson.version)\n .description(packageJson.description)\n .argument('<country>', 'The country code to determine the public holidays')\n .option('-h, --hours', 'The number of working hours in a single working day')\n .option(\n '-m, --month <month>',\n 'The month (indexed from 1 to 12) to calculate working hours for. Defaults to the current month'\n )\n .option('-y, --year <year>', 'The year to calculate working hours for. Defaults to the current year')\n .action((country, options) => {\n console.log(calculateWorkingHours({ country, ...options }));\n });\n\n['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'].forEach(day => {\n program.addOption(new Option(`--with${day}s`, `Whether to include ${day}s as working days`));\n program.addOption(new Option(`--without${day}s`, `Whether to exclude ${day}s from working days`));\n});\n\nprogram.parse(process.argv);\n","{\n \"name\": \"dutyhours\",\n \"version\": \"1.0.5\",\n \"description\": \"A tool to calculate total working hours in a given month, taking into account public holidays and configurable working days.\",\n \"keywords\": [\n \"working-hours\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/kamdz/dutyhours/issues\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/kamdz/dutyhours.git\"\n },\n \"license\": \"MIT\",\n \"author\": {\n \"name\": \"Kamil Dzwonkowski\",\n \"email\": \"npm@kamdz.dev\",\n \"url\": \"https://github.com/kamdz\"\n },\n \"type\": \"module\",\n \"exports\": {\n \".\": {\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": \"./dist/cli.js\",\n \"files\": [\n \"dist\",\n \"package.json\",\n \"README.md\",\n \"CHANGELOG.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"cli\": \"tsx bin/cli.ts\",\n \"commit\": \"cz\",\n \"dev\": \"tsx watch src/index.ts\",\n \"dx\": \"npx @kamdz/dx\",\n \"format\": \"prettier --write --ignore-unknown .\",\n \"lint\": \"eslint . --fix\",\n \"lint-staged\": \"lint-staged\",\n \"prepare\": \"husky\",\n \"start\": \"tsx src/index.ts\",\n \"test\": \"jest --coverage --passWithNoTests\",\n \"type-check\": \"tsc --noEmit\"\n },\n \"lint-staged\": {\n \"**/*.{ts,tsx,js,jsx,cjs,mjs,}\": [\n \"eslint --fix\"\n ],\n \"**/*.{ts,tsx,js,jsx,json,md,cjs,mjs,yml,yaml}\": [\n \"prettier --write --ignore-unknown\"\n ]\n },\n \"config\": {\n \"commitizen\": {\n \"path\": \"./node_modules/cz-conventional-changelog\"\n }\n },\n \"release\": {\n \"branches\": [\n \"main\"\n ],\n \"plugins\": [\n \"@semantic-release/commit-analyzer\",\n \"@semantic-release/release-notes-generator\",\n [\n \"@semantic-release/changelog\",\n {\n \"changelogFile\": \"CHANGELOG.md\"\n }\n ],\n \"@semantic-release/npm\",\n [\n \"@semantic-release/git\",\n {\n \"assets\": [\n \"package.json\",\n \"CHANGELOG.md\"\n ],\n \"message\": \"chore(release): ${nextRelease.version} \\n\\n${nextRelease.notes}\"\n }\n ],\n \"@semantic-release/github\"\n ]\n },\n \"devDependencies\": {\n \"@commitlint/cli\": \"^19.6.1\",\n \"@commitlint/config-conventional\": \"^19.6.0\",\n \"@eslint/compat\": \"^1.2.5\",\n \"@eslint/js\": \"^9.19.0\",\n \"@ianvs/prettier-plugin-sort-imports\": \"^4.4.1\",\n \"@semantic-release/changelog\": \"^6.0.3\",\n \"@semantic-release/git\": \"^10.0.1\",\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/jest\": \"^29.5.14\",\n \"@types/node\": \"^22.10.10\",\n \"commitizen\": \"^4.3.1\",\n \"cz-conventional-changelog\": \"^3.3.0\",\n \"eslint\": \"^9.19.0\",\n \"eslint-config-prettier\": \"^10.0.1\",\n \"eslint-plugin-import\": \"^2.31.0\",\n \"eslint-plugin-prettier\": \"^5.2.3\",\n \"globals\": \"^15.14.0\",\n \"husky\": \"^9.1.7\",\n \"jest\": \"^29.7.0\",\n \"lint-staged\": \"^15.4.3\",\n \"prettier\": \"3.4.2\",\n \"semantic-release\": \"^24.2.1\",\n \"ts-jest\": \"^29.2.5\",\n \"tsup\": \"^8.3.6\",\n \"tsx\": \"^4.19.2\",\n \"typescript\": \"^5.7.3\",\n \"typescript-eslint\": \"^8.21.0\"\n },\n \"packageManager\": \"yarn@4.5.1\",\n \"dependencies\": {\n \"commander\": \"^13.1.0\",\n \"date-holidays\": \"^3.23.21\"\n }\n}\n"],"mappings":"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","names":["import_date_holidays","DAY_NAMES","isWorkingDay","dayIndex","options","dayName","getHolidaysForMonth","year","month","country","hd","Holidays","startOfMonth","endOfMonth","date","type","holidayDate","calculateWorkingHours","today","hoursPerDay","holidays","workingHours","day","currentDate","src_default","import_commander","package_default","package_default","country","options","src_default","day"]}