Skip to content

Commit

Permalink
Merge pull request #2 from nascjoao/feat-0.3.0
Browse files Browse the repository at this point in the history
Release 0.3.0
  • Loading branch information
nascjoao authored Aug 20, 2024
2 parents c7f8d40 + a0ddc2a commit 04f5dc6
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 67 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tikjs",
"version": "0.2.3",
"version": "0.3.0",
"description": "Fast lightweight library for formatting time in JavaScript",
"main": "dist/index.js",
"module": "dist/index.es.js",
Expand All @@ -27,7 +27,7 @@
"size-limit": [
{
"path": "dist",
"limit": "1.5 kB"
"limit": "1.99 kB"
}
],
"keywords": [
Expand Down
79 changes: 46 additions & 33 deletions src/TikJSTime/TikJSTime.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,14 @@
/**
* The average year length in days.
*
* This is the average length of a year in days, taking into account leap years.
*
* A common year has 365 days, but a leap year has 366 days. We add an extra day every 4 years
* to account for the extra 0.25 days per year. However, century years are not leap years unless
* they are divisible by 400. For example, 2000 is a leap year, but 2100 is not.
*
* To do this calculation, we add 1/4 of a day every year, but subtract 1/100 of a day every year.
* Also add 1/400 of a day every year.
*/
const AVERAGE_YEAR = 365 + 1 / 4 - 1 / 100 + 1 / 400;
const AVERAGE_MONTH = AVERAGE_YEAR / 12;
const HOURS_IN_A_DAY = 24;
const MILLISECONDS_IN_A_SECOND = 1000;
const SECONDS_IN_A_MINUTE = 60;
const SECONDS_IN_AN_HOUR = 60 * 60;
const SECONDS_IN_A_DAY = HOURS_IN_A_DAY * SECONDS_IN_AN_HOUR;
const SECONDS_IN_A_MONTH = AVERAGE_MONTH * SECONDS_IN_A_DAY;
const SECONDS_IN_A_YEAR = AVERAGE_YEAR * SECONDS_IN_A_DAY;
import {
MILLISECONDS_IN_A_SECOND,
SECONDS_IN_A_DAY,
SECONDS_IN_A_MINUTE,
SECONDS_IN_A_MONTH,
SECONDS_IN_A_YEAR,
SECONDS_IN_AN_HOUR,
} from "../utils/timeEquivalences";
import parseTimeToSeconds from "../utils/parseTimeToSeconds";

export type TikJSInput = string | number;
export type TikJSInput = string | number | Date;

export class TikJSTime {
public years = 0;
Expand All @@ -32,6 +20,8 @@ export class TikJSTime {
public milliseconds = 0;
public static dates = {
/**
* @deprecated Pass the dates as arguments to `tikjs()` instead.
* ---
* Get the duration between two or more dates. The order
* of the dates can be ascending or descending.
* @param dates - The dates to compare.
Expand Down Expand Up @@ -63,14 +53,22 @@ export class TikJSTime {
},
};

constructor(time: TikJSInput) {
const seconds = Number(time);
if (seconds === 0) return;
if (isNaN(seconds)) {
throw new Error(
`The time "${time}" is not a valid number or string that can be converted to a number.`,
constructor(time: TikJSInput);
constructor(date1: Date, date2: Date);
constructor(timeOrDate: TikJSInput, date2?: Date) {
if (timeOrDate == 0) return;

let seconds = 0;

if (timeOrDate instanceof Date && date2 instanceof Date) {
const millisecondsBetweenDates = Math.abs(
timeOrDate.getTime() - date2.getTime(),
);
seconds = millisecondsBetweenDates / MILLISECONDS_IN_A_SECOND;
} else if (!(timeOrDate instanceof Date)) {
seconds = parseTimeToSeconds(timeOrDate);
}

this.years = seconds / SECONDS_IN_A_YEAR;
this.months = seconds / SECONDS_IN_A_MONTH;
this.days = seconds / SECONDS_IN_A_DAY;
Expand All @@ -80,15 +78,30 @@ export class TikJSTime {
this.milliseconds = seconds * MILLISECONDS_IN_A_SECOND;
}

/**
* Format the time in a human-readable way.
* You can use the following blocks:
* - `y` or `yy`: years
* - `M` or `MM`: months
* - `d` or `dd`: days
* - `h` or `hh`: hours
* - `m` or `mm`: minutes
* - `s` or `ss`: seconds
* - `S` or `SS`: milliseconds
* - `[...]`: any text inside the brackets will be displayed as is
* @param format - The format to display the time.
* @returns The formatted time.
* @example
* ```javascript
* const time = tikjs(60);
* console.log(time.format("Ti[m]e: m:ss")); // Time: 1:00
* ```
*/
format(format: string) {
const blocksPattern = /(yy?|MM?|dd?|hh?|mm?|ss?|SS?|\[[^\]]+\])/g;
const thereAreNoBlocks = format.match(blocksPattern) === null;

if (thereAreNoBlocks) {
throw new Error(
`The time pattern "${format}" must contain at least one of the following blocks: "h", "hh", "m", "mm", "s" or "ss".`,
);
}
if (thereAreNoBlocks) return format;

const wholeYears = Math.floor(this.years);
const wholeMonths = Math.floor(this.months) % 12;
Expand Down
14 changes: 0 additions & 14 deletions src/TikJSTime/tests/format.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,6 @@ describe("TikJSTime — format", () => {
expect(formattedTime).toBe("00:10:00");
});

it("should throw an error if the format string is empty", () => {
const time = new TikJSTime(600);
expect(() => time.format("")).toThrow(
'The time pattern "" must contain at least one of the following blocks: "h", "hh", "m", "mm", "s" or "ss".',
);
});

it("should throw an error if the format string has no blocks", () => {
const time = new TikJSTime(600);
expect(() => time.format("abc")).toThrow(
'The time pattern "abc" must contain at least one of the following blocks: "h", "hh", "m", "mm", "s" or "ss".',
);
});

it("should escape blocks with square brackets", () => {
const time = new TikJSTime(601);
const formattedTime = time.format("Ti[m]e: mm:ss");
Expand Down
68 changes: 50 additions & 18 deletions src/tikjs/tikjs.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,66 @@
import { type TikJSInput, TikJSTime } from "../TikJSTime";

/**
* @param time - The time to be converted. It must be a number or string representing seconds.
* @returns A new TikJSTime instance. It represents the time in years, months, days,
* hours, minutes, seconds and milliseconds. Also it has a method to format the time.
* To format the time, you can use the following blocks:
* - `y` or `yy`: years
* - `M` or `MM`: months
* - `d` or `dd`: days
* - `h` or `hh`: hours
* - `m` or `mm`: minutes
* - `s` or `ss`: seconds
* - `S` or `SS`: milliseconds
* - `[...]`: any text inside the brackets will be displayed as is
* @throws If the time pattern does not contain any of the following
* blocks: "h", "hh", "m", "mm", "s" or "ss".
* **Tik.js** is a library to work with time in JavaScript. It allows you to easily
* parse time to get durations and format them.
*
* @param time - The time to work with. It can be a number or string.
* If it's a number, it will be considered as a duration in seconds.
* If it's a string, you can specify the unit of time by adding a suffix.
* For example, "1d" for 1 day.
*
* Unit of time suffixes:
* - `s` for seconds
* - `m` for minutes
* - `h` for hours
* - `d` for days
* - `M` for months
* - `y` for years
*
* @example
* ```javascript
* const time = tikjs(3600); // 1 hour
* console.log(time.hours); // 1
* console.log(time.minutes); // 60
* console.log(time.seconds); // 3600
* console.log(time.format("h:mm:ss")); // 1:00:00
* ```
* @example
* ```javascript
* import tikjs from "tikjs";
* const time = tikjs('1h'); // 1 hour
* console.log(time.hours); // 1
* console.log(time.minutes); // 60
* console.log(time.seconds); // 3600
* console.log(time.format("h:mm:ss")); // 1:00:00
* ```
*
* Also, you can get the duration between two dates:
*
* const time = tikjs(60);
* @param date1 - The first date.
* @param date2 - The second date.
*
* console.log(time.format("Ti[m]e: m:ss")); // Time: 1:00
* @example
* ```javascript
* const date1 = new Date('2021-01-01');
* const date2 = new Date('2021-01-02');
* const time = tikjs(date1, date2);
* console.log(time.days); // 1
* console.log(time.format("d [day]")) // 1 day
* ```
*
* @returns A TikJSTime object.
*/
function tikjs(): typeof TikJSTime;
function tikjs(time: TikJSInput): TikJSTime;
function tikjs(time?: TikJSInput): TikJSTime | typeof TikJSTime {
function tikjs(date1: Date, date2: Date): TikJSTime;
function tikjs(
time?: TikJSInput | Date,
date2?: Date,
): TikJSTime | typeof TikJSTime {
if (time === undefined) {
return TikJSTime;
} else if (time instanceof Date && date2 instanceof Date) {
return new TikJSTime(time, date2);
}
return new TikJSTime(time);
}
Expand Down
63 changes: 63 additions & 0 deletions src/utils/parseTimeToSeconds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {
MILLISECONDS_IN_A_SECOND,
SECONDS_IN_A_DAY,
SECONDS_IN_A_MINUTE,
SECONDS_IN_A_MONTH,
SECONDS_IN_A_YEAR,
SECONDS_IN_AN_HOUR,
} from "../utils/timeEquivalences";

export default function parseTimeToSeconds(time: string | number): number {
const timeCollection = [];
let seconds = 0;

if (typeof time === "string") {
const regex = /(\d+\.?\d*)\s*([yMdhmsS])?/g;
let match;
const matches = [];

while ((match = regex.exec(time)) !== null) {
matches.push(match);
}

for (const match of matches) {
timeCollection.push([match[1], match[2] || "s"]);
}
}

if (timeCollection.length === 0) {
timeCollection.push([time, "s"]);
}

for (const [_time, unit] of timeCollection) {
switch (unit) {
case "y":
seconds += Number(_time) * SECONDS_IN_A_YEAR;
break;
case "M":
seconds += Number(_time) * SECONDS_IN_A_MONTH;
break;
case "d":
seconds += Number(_time) * SECONDS_IN_A_DAY;
break;
case "h":
seconds += Number(_time) * SECONDS_IN_AN_HOUR;
break;
case "m":
seconds += Number(_time) * SECONDS_IN_A_MINUTE;
break;
case "s":
seconds += Number(_time);
break;
case "S":
seconds += Number(_time) / MILLISECONDS_IN_A_SECOND;
break;
default:
throw new Error(
`Valid units: "y", "M", "d", "h", "m", "s" or "S".`,
);
}
}

return seconds;
}
21 changes: 21 additions & 0 deletions src/utils/timeEquivalences.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* The average year length in days.
*
* This is the average length of a year in days, taking into account leap years.
*
* A common year has 365 days, but a leap year has 366 days. We add an extra day every 4 years
* to account for the extra 0.25 days per year. However, century years are not leap years unless
* they are divisible by 400. For example, 2000 is a leap year, but 2100 is not.
*
* To do this calculation, we add 1/4 of a day every year, but subtract 1/100 of a day every year.
* Also add 1/400 of a day every year.
*/
export const AVERAGE_YEAR = 365 + 1 / 4 - 1 / 100 + 1 / 400;
export const AVERAGE_MONTH = AVERAGE_YEAR / 12;
export const HOURS_IN_A_DAY = 24;
export const MILLISECONDS_IN_A_SECOND = 1000;
export const SECONDS_IN_A_MINUTE = 60;
export const SECONDS_IN_AN_HOUR = 60 * 60;
export const SECONDS_IN_A_DAY = HOURS_IN_A_DAY * SECONDS_IN_AN_HOUR;
export const SECONDS_IN_A_MONTH = AVERAGE_MONTH * SECONDS_IN_A_DAY;
export const SECONDS_IN_A_YEAR = AVERAGE_YEAR * SECONDS_IN_A_DAY;

0 comments on commit 04f5dc6

Please sign in to comment.