PHP's date in TypeScript

Rosetta Stone: golang/Format

How to use

Install via yarn add locutus and import: import { date } from 'locutus/php/datetime/date'.

Or with CommonJS: const { date } = require('locutus/php/datetime/date')

Use a bundler that supports tree-shaking so you only ship the functions you actually use. Vite, webpack, Rollup, and Parcel all handle this. For server-side use this is less of a concern.

Examples

These examples are extracted from test cases that automatically verify our functions against their native counterparts.

#codeexpected result
1date('H:m:s \\m \\i\\s \\m\\o\\n\\t\\h', 1062402400)'07:09:40 m is month'
2date('F j, Y, g:i a', 1062462400)'September 2, 2003, 12:26 am'
3date('Y W o', 1062462400)'2003 36 2003'
4var $x = date('Y m d', (new Date()).getTime() / 1000) $x = $x + '' var $result = $x.length // 2009 01 0910
5date('W', 1104534000)'52'
6date('B t', 1104534000)'999 31'
7date('W U', 1293750000.82); // 2010-12-31'52 1293750000'
8date('W', 1293836400); // 2011-01-01'52'
9date('W Y-m-d', 1293974054); // 2011-01-02'52 2011-01-02'

Notes

  • Uses global: locutus to store the default timezone Although the function potentially allows timezone info (see notes), it currently does not set per a timezone specified by date_default_timezone_set(). Implementers might use $locutus.currentTimezoneOffset and $locutus.currentTimezoneDST set by that function in order to adjust the dates in this function (or our other date functions!) accordingly

Here's what our current TypeScript equivalent to PHP's date looks like.

type DateFormatToken =
| 'd'
| 'D'
| 'j'
| 'l'
| 'N'
| 'S'
| 'w'
| 'z'
| 'W'
| 'F'
| 'm'
| 'M'
| 'n'
| 't'
| 'L'
| 'o'
| 'Y'
| 'y'
| 'a'
| 'A'
| 'B'
| 'g'
| 'G'
| 'h'
| 'H'
| 'i'
| 's'
| 'u'
| 'e'
| 'I'
| 'O'
| 'P'
| 'T'
| 'Z'
| 'c'
| 'r'
| 'U'

type DateFormatterMap = { [K in DateFormatToken]: () => string | number }

export function date(format: string, timestamp?: number | Date | string): string {
// discuss at: https://locutus.io/php/date/
// original by: Carlos R. L. Rodrigues (https://www.jsfromhell.com)
// original by: gettimeofday
// parts by: Peter-Paul Koch (https://www.quirksmode.org/js/beat.html)
// improved by: Kevin van Zonneveld (https://kvz.io)
// improved by: MeEtc (https://yass.meetcweb.com)
// improved by: Brad Touesnard
// improved by: Tim Wiel
// improved by: Bryan Elliott
// improved by: David Randall
// improved by: Theriault (https://github.com/Theriault)
// improved by: Theriault (https://github.com/Theriault)
// improved by: Brett Zamir (https://brett-zamir.me)
// improved by: Theriault (https://github.com/Theriault)
// improved by: Thomas Beaucourt (https://www.webapp.fr)
// improved by: JT
// improved by: Theriault (https://github.com/Theriault)
// improved by: Rafał Kukawski (https://blog.kukawski.pl)
// improved by: Theriault (https://github.com/Theriault)
// input by: Brett Zamir (https://brett-zamir.me)
// input by: majak
// input by: Alex
// input by: Martin
// input by: Alex Wilson
// input by: Haravikk
// bugfixed by: Kevin van Zonneveld (https://kvz.io)
// bugfixed by: majak
// bugfixed by: Kevin van Zonneveld (https://kvz.io)
// bugfixed by: Brett Zamir (https://brett-zamir.me)
// bugfixed by: omid (https://locutus.io/php/380:380#comment_137122)
// bugfixed by: Chris (https://www.devotis.nl/)
// note 1: Uses global: locutus to store the default timezone
// note 1: Although the function potentially allows timezone info
// note 1: (see notes), it currently does not set
// note 1: per a timezone specified by date_default_timezone_set(). Implementers might use
// note 1: $locutus.currentTimezoneOffset and
// note 1: $locutus.currentTimezoneDST set by that function
// note 1: in order to adjust the dates in this function
// note 1: (or our other date functions!) accordingly
// example 1: date('H:m:s \\m \\i\\s \\m\\o\\n\\t\\h', 1062402400)
// returns 1: '07:09:40 m is month'
// example 2: date('F j, Y, g:i a', 1062462400)
// returns 2: 'September 2, 2003, 12:26 am'
// example 3: date('Y W o', 1062462400)
// returns 3: '2003 36 2003'
// example 4: var $x = date('Y m d', (new Date()).getTime() / 1000)
// example 4: $x = $x + ''
// example 4: var $result = $x.length // 2009 01 09
// returns 4: 10
// example 5: date('W', 1104534000)
// returns 5: '52'
// example 6: date('B t', 1104534000)
// returns 6: '999 31'
// example 7: date('W U', 1293750000.82); // 2010-12-31
// returns 7: '52 1293750000'
// example 8: date('W', 1293836400); // 2011-01-01
// returns 8: '52'
// example 9: date('W Y-m-d', 1293974054); // 2011-01-02
// returns 9: '52 2011-01-02'

let jsdate = new Date()
let f!: DateFormatterMap
// Keep this here (works, but for code commented-out below for file size reasons)
// var tal= [];
const txtWords = [
'Sun',
'Mon',
'Tues',
'Wednes',
'Thurs',
'Fri',
'Satur',
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
]
// trailing backslash -> (dropped)
// a backslash followed by any character (including backslash) -> the character
// empty string -> empty string
const formatChr = /\\?(.?)/gi
const hasFormatterToken = (token: string): token is DateFormatToken => Object.hasOwn(f, token)
const formatChrCb = function (t: string, s: string): string {
return hasFormatterToken(t) ? String(f[t]()) : s
}
const _pad = function (n: string | number, c: number): string {
let str = String(n)
while (str.length < c) {
str = '0' + str
}
return str
}
f = {
// Day
d: function () {
// Day of month w/leading 0; 01..31
return _pad(f.j(), 2)
},
D: function () {
// Shorthand day name; Mon...Sun
return String(f.l()).slice(0, 3)
},
j: function () {
// Day of month; 1..31
return jsdate.getDate()
},
l: function () {
// Full day name; Monday...Sunday
return (txtWords[Number(f.w())] ?? '') + 'day'
},
N: function () {
// ISO-8601 day of week; 1[Mon]..7[Sun]
return Number(f.w()) || 7
},
S: function () {
// Ordinal suffix for day of month; st, nd, rd, th
const j = Number(f.j())
let i = j % 10
if (i <= 3 && Number.parseInt(String((j % 100) / 10), 10) === 1) {
i = 0
}
return ['st', 'nd', 'rd'][i - 1] || 'th'
},
w: function () {
// Day of week; 0[Sun]..6[Sat]
return jsdate.getDay()
},
z: function () {
// Day of year; 0..365
const a = new Date(Number(f.Y()), Number(f.n()) - 1, Number(f.j()))
const b = new Date(Number(f.Y()), 0, 1)
return Math.round((a.getTime() - b.getTime()) / 864e5)
},

// Week
W: function () {
// ISO-8601 week number
const a = new Date(Number(f.Y()), Number(f.n()) - 1, Number(f.j()) - Number(f.N()) + 3)
const b = new Date(a.getFullYear(), 0, 4)
return _pad(1 + Math.round((a.getTime() - b.getTime()) / 864e5 / 7), 2)
},

// Month
F: function () {
// Full month name; January...December
return txtWords[6 + Number(f.n())] ?? ''
},
m: function () {
// Month w/leading 0; 01...12
return _pad(f.n(), 2)
},
M: function () {
// Shorthand month name; Jan...Dec
return String(f.F()).slice(0, 3)
},
n: function () {
// Month; 1...12
return jsdate.getMonth() + 1
},
t: function () {
// Days in month; 28...31
return new Date(Number(f.Y()), Number(f.n()), 0).getDate()
},

// Year
L: function () {
// Is leap year?; 0 or 1
const j = Number(f.Y())
return (j % 4 === 0 && j % 100 !== 0) || j % 400 === 0 ? 1 : 0
},
o: function () {
// ISO-8601 year
const n = Number(f.n())
const W = Number(f.W())
const Y = Number(f.Y())
return Y + (n === 12 && W < 9 ? 1 : n === 1 && W > 9 ? -1 : 0)
},
Y: function () {
// Full year; e.g. 1980...2010
return jsdate.getFullYear()
},
y: function () {
// Last two digits of year; 00...99
return String(f.Y()).slice(-2)
},

// Time
a: function () {
// am or pm
return jsdate.getHours() > 11 ? 'pm' : 'am'
},
A: function () {
// AM or PM
return String(f.a()).toUpperCase()
},
B: function () {
// Swatch Internet time; 000..999
const H = jsdate.getUTCHours() * 36e2
// Hours
const i = jsdate.getUTCMinutes() * 60
// Minutes
// Seconds
const s = jsdate.getUTCSeconds()
return _pad(Math.floor((H + i + s + 36e2) / 86.4) % 1e3, 3)
},
g: function () {
// 12-Hours; 1..12
return Number(f.G()) % 12 || 12
},
G: function () {
// 24-Hours; 0..23
return jsdate.getHours()
},
h: function () {
// 12-Hours w/leading 0; 01..12
return _pad(f.g(), 2)
},
H: function () {
// 24-Hours w/leading 0; 00..23
return _pad(f.G(), 2)
},
i: function () {
// Minutes w/leading 0; 00..59
return _pad(jsdate.getMinutes(), 2)
},
s: function () {
// Seconds w/leading 0; 00..59
return _pad(jsdate.getSeconds(), 2)
},
u: function () {
// Microseconds; 000000-999000
return _pad(jsdate.getMilliseconds() * 1000, 6)
},

// Timezone
e: function () {
// Timezone identifier; e.g. Atlantic/Azores, ...
// The following works, but requires inclusion of the very large
// timezone_abbreviations_list() function.
/* return that.date_default_timezone_get();
*/
const msg = 'Not supported (see source code of date() for timezone on how to add support)'
throw new Error(msg)
},
I: function () {
// DST observed?; 0 or 1
// Compares Jan 1 minus Jan 1 UTC to Jul 1 minus Jul 1 UTC.
// If they are not equal, then DST is observed.
const a = new Date(Number(f.Y()), 0)
// Jan 1
const c = Date.UTC(Number(f.Y()), 0)
// Jan 1 UTC
const b = new Date(Number(f.Y()), 6)
// Jul 1
// Jul 1 UTC
const d = Date.UTC(Number(f.Y()), 6)
return a.getTime() - c !== b.getTime() - d ? 1 : 0
},
O: function () {
// Difference to GMT in hour format; e.g. +0200
const tzo = jsdate.getTimezoneOffset()
const a = Math.abs(tzo)
return (tzo > 0 ? '-' : '+') + _pad(Math.floor(a / 60) * 100 + (a % 60), 4)
},
P: function () {
// Difference to GMT w/colon; e.g. +02:00
const O = String(f.O())
return O.slice(0, 3) + ':' + O.slice(3, 5)
},
T: function () {
// The following works, but requires inclusion of the very
// large timezone_abbreviations_list() function.
/* var abbr, i, os, _default;
if (!tal.length) {
tal = that.timezone_abbreviations_list();
}
if ($locutus && $locutus.default_timezone) {
_default = $locutus.default_timezone;
for (abbr in tal) {
for (i = 0; i < tal[abbr].length; i++) {
if (tal[abbr][i].timezone_id === _default) {
return abbr.toUpperCase();
}
}
}
}
for (abbr in tal) {
for (i = 0; i < tal[abbr].length; i++) {
os = -jsdate.getTimezoneOffset() * 60;
if (tal[abbr][i].offset === os) {
return abbr.toUpperCase();
}
}
}
*/
return 'UTC'
},
Z: function () {
// Timezone offset in seconds (-43200...50400)
return -jsdate.getTimezoneOffset() * 60
},

// Full Date/Time
c: function () {
// ISO-8601 date.
return 'Y-m-d\\TH:i:sP'.replace(formatChr, formatChrCb)
},
r: function () {
// RFC 2822
return 'D, d M Y H:i:s O'.replace(formatChr, formatChrCb)
},
U: function () {
// Seconds since UNIX epoch
return (jsdate.getTime() / 1000) | 0
},
}

const _date = function (formatStr: string, timestampValue?: number | Date | string): string {
jsdate =
timestampValue === undefined
? new Date() // Not provided
: timestampValue instanceof Date
? new Date(timestampValue) // JS Date()
: new Date(Number(timestampValue) * 1000) // UNIX timestamp (auto-convert to int)
return formatStr.replace(formatChr, formatChrCb)
}

return _date(format, timestamp)
}

Improve this function

Locutus is a community effort following The McDonald's Theory: we ship first iterations, hoping others will improve them. If you see something that could be better, we'd love your contribution.

View on GitHub · Edit on GitHub · View Raw


« More PHP datetime functions


Star