Skip to content

Instantly share code, notes, and snippets.

@andreschoultz
Last active October 10, 2023 06:09
Show Gist options
  • Save andreschoultz/8142eba11bf7850c541767062498386f to your computer and use it in GitHub Desktop.
Save andreschoultz/8142eba11bf7850c541767062498386f to your computer and use it in GitHub Desktop.
A TypeScript format extension for dates. Quick & easy C# like date formattingđź“…
interface Date {
/**
* Extends the Date object with a `format` method to format dates as strings.
*
* @param {string} format - The format string specifying the desired date/time format.
* @returns {string} The formatted date string.
*
* @example
* ```typescript
* const myDate: Date = new Date();
* console.log(myDate.format("yyyy/MM/dd HH:mm:ss.fff")); // Output: "2023/10/09 15:30:45.123"
* ```
*
* @remarks
* This method supports various format options, such as:
* - `d`, `dd`: Day of the month (1 through 31).
* - `ddd`, `dddd`: Abbreviated and full names of the day (Mon, Monday, etc).
* - `H`, `HH`, `h`, `hh`: 24-hour and 12-hour clock hours.
* - `m`, `mm`: Minutes.
* - `M`, `MM`, `MMM`, `MMMM`: Month in various formats.
* - `s`, `ss`: Seconds.
* - `t`, `tt`: AM/PM.
* - `y`, `yy`, `yyy`, `yyyy`: Year in various formats.
* - `K`: Time zone offset.
* - `z`, `zz`, `zzz`: Time zone offset in various formats.
* - `f`, `ff`, `fff`: Milliseconds and fractions of a second.
*
*
* Date formatting extension inspired by and adapted from the work of OpenAI"s ChatGPT, created by OpenAI.
*
* @see {@link https://www.openai.com/}
* @see {@link https://platform.openai.com/docs/api-reference/introduction}
*
* Original implementation: OpenAI"s ChatGPT
* Curated and adapted for TypeScript: Andre Schoultz
*/
format(format: string): string;
}
Date.prototype.format = function (format: string): string {
const daysOfWeek: string[] = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
const months: string[] = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
return format.replace(/(d{1,4}|M{1,4}|y{1,4}|HH|H|hh|h|mm|ss|t{1,2}|K|z{1,3}|f{1,3})/g, (match: string): string => {
switch (match) {
case "d":
return this.getDate().toString();
case "dd":
return ("0" + this.getDate()).slice(-2);
case "ddd":
return daysOfWeek[this.getDay()].slice(0, 3);
case "dddd":
return daysOfWeek[this.getDay()];
case "H":
return this.getHours().toString();
case "HH":
return ("0" + this.getHours()).slice(-2);
case "h":
return (this.getHours() % 12 || 12).toString();
case "hh":
return ("0" + (this.getHours() % 12 || 12)).slice(-2);
case "m":
return this.getMinutes().toString();
case "mm":
return ("0" + this.getMinutes()).slice(-2);
case "M":
return (this.getMonth() + 1).toString();
case "MM":
return ("0" + (this.getMonth() + 1)).slice(-2);
case "MMM":
return months[this.getMonth()].slice(0, 3);
case "MMMM":
return months[this.getMonth()];
case "s":
return this.getSeconds().toString();
case "ss":
return ("0" + this.getSeconds()).slice(-2);
case "t":
return this.getHours() < 12 ? "A" : "P";
case "tt":
return this.getHours() < 12 ? "AM" : "PM";
case "y":
return (this.getFullYear() % 100).toString();
case "yy":
return ("0" + (this.getFullYear() % 100)).slice(-2);
case "yyy":
return this.getFullYear().toString().padStart(3, "0");
case "yyyy":
return this.getFullYear().toString().padStart(4, "0");
case "K":
const offsetMinutes: number = this.getTimezoneOffset();
const offsetHours: number = Math.abs(offsetMinutes / 60);
const offsetSign: string = offsetMinutes > 0 ? "-" : "+";
return offsetSign + ("0" + offsetHours).slice(-2) + ":" + ("0" + Math.abs(offsetMinutes % 60)).slice(-2);
case "z":
return (this.getTimezoneOffset() / 60).toString();
case "zz":
const timezoneOffset: number = this.getTimezoneOffset() / 60;
return (timezoneOffset > 0 ? "+" : "-") + ("0" + Math.abs(timezoneOffset)).slice(-2);
case "zzz":
const tzOffset: number = this.getTimezoneOffset();
const tzHours: number = Math.abs(tzOffset / 60);
const tzSign: string = tzOffset > 0 ? "-" : "+";
return tzSign + ("0" + tzHours).slice(-2) + ":" + ("0" + Math.abs(tzOffset % 60)).slice(-2);
case "f":
return Math.floor(this.getMilliseconds() / 100).toString();
case "ff":
return ("0" + Math.floor(this.getMilliseconds() / 10)).slice(-2);
case "fff":
return this.getMilliseconds().toString().padEnd(3, "0");
default:
return match;
}
});
};
const runFromatTest = () => {
const testDate = new Date("2015-05-29T05:50:06.7199222");
const expectedResults: any = {
"MM/dd/yyyy": "05/29/2015",
"dddd, dd MMMM yyyy": "Friday, 29 May 2015",
"dddd, dd MMMM yyyy HH:mm": "Friday, 29 May 2015 05:50",
"dddd, dd MMMM yyyy hh:mm tt": "Friday, 29 May 2015 05:50 AM",
"dddd, dd MMMM yyyy H:mm": "Friday, 29 May 2015 5:50",
"dddd, dd MMMM yyyy h:mm tt": "Friday, 29 May 2015 5:50 AM",
"dddd, dd MMMM yyyy HH:mm:ss": "Friday, 29 May 2015 05:50:06",
"MM/dd/yyyy HH:mm": "05/29/2015 05:50",
"MM/dd/yyyy hh:mm tt": "05/29/2015 05:50 AM",
"MM/dd/yyyy H:mm": "05/29/2015 5:50",
"MM/dd/yyyy h:mm tt": "05/29/2015 5:50 AM",
"MM/dd/yyyy HH:mm:ss": "05/29/2015 05:50:06",
"MMMM dd": "May 29",
"yyyy-MM-ddTHH:mm:ss.fffK": "2015-05-29T05:50:06.719+02:00", // Adapt to own timezone when testing
"ddd, dd MMM yyy HH:mm:ss": "Fri, 29 May 2015 05:50:06",
"yyyy-MM-ddTHH:mm:ss": "2015-05-29T05:50:06",
"HH:mm": "05:50",
"hh:mm tt": "05:50 AM",
"H:mm": "5:50",
"h:mm tt": "5:50 AM",
"HH:mm:ss": "05:50:06",
"yyyy MMMM": "2015 May",
};
Object.keys(expectedResults).forEach((format) => {
const result = testDate.format(format);
const expected = expectedResults[format];
console.log(`${format}:`, result);
if (result === expected) {
console.log(" Test Passed");
} else {
console.error(` Test Failed! Expected: ${expected}, Actual: ${result}`);
}
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment