A TypeScript Date is the JavaScript Date object, which stores one moment in time as the number of milliseconds since 1 January 1970 UTC, and TypeScript adds a Date type that the compiler checks. We get the current date and time with new Date() or the current timestamp with Date.now(), and we read or change the year, month, day and time with getter and setter methods. TypeScript needs no import or special setting for Date, because the Date type is part of the standard library that every project loads.
We use Date whenever an app records or shows a moment, such as the creation time of an order or the due date of an invoice.
The following example covers the most common daily date tasks, with the result of each line as a comment.
// 1. Current date and time
const now = new Date(); // e.g. Sat Oct 03 2026 14:30:00 GMT+0530
const millis = Date.now(); // e.g. 1790969391214
const today = now.toLocaleDateString("en-CA"); // e.g. "2026-10-03", local date
// 2. A specific date (month is 0-based)
const date = new Date(2026, 9, 3); // 3 October 2026, 00:00 local time
const utc = new Date("2026-10-03T00:00:00Z"); // 3 October 2026, 00:00 UTC
// 3. Read parts
const year = date.getFullYear(); // year = 2026
const month = date.getMonth(); // month = 9 (October)
const day = date.getDate(); // day = 3
const weekday = date.getDay(); // weekday = 6 (Saturday)
// 4. Add days
const later = new Date(date);
later.setDate(later.getDate() + 30); // later = 2 November 2026
// 5. Compare
const same = date.getTime() === new Date(2026, 9, 3).getTime(); // same = true
const before = date < later; // before = true
// 6. Format
const us = date.toLocaleDateString("en-US"); // us = "10/3/2026"
const gb = date.toLocaleDateString("en-GB"); // gb = "03/10/2026"
const iso = date.toISOString(); // iso = "2026-10-02T18:30:00.000Z" in India (UTC+05:30)
Notice that the values that depend on the time zone are for India Standard Time (UTC+05:30), so toISOString() shows midnight on 3 October as 18:30 on the previous day.
Next, we create specific dates, add days or months, compare and format dates, and handle the time zone and JSON pitfalls that cause most date bugs. The last section covers the status of the new Temporal API.
1. The Date Type in TypeScript
The Date type is declared in the TypeScript library file lib.es5.d.ts, which every lib setting includes. Using Date has never required an ES6 target, and with TypeScript 7 every target is ES2015 or newer anyway. The compiler infers the type from new Date(), so an annotation is optional.
let created = new Date(); // type Date (inferred)
let updated: Date = new Date(); // type Date (explicit)
let deleted: Date | null = null; // a date that may not exist yet
TypeScript checks every method call against that type. Calling a method that does not exist, such as created.getYears(), or passing a Date where a string is expected, fails at compile time. The type does not check the value, though, so an invalid date is still of type Date, as section 2 shows.
2. Creating Date Objects
The Date constructor accepts four kinds of arguments.
- No argument gives the current moment.
- A number is read as milliseconds since 1 January 1970 UTC.
- A string is parsed as a date.
- Separate numbers give the individual parts of a date.
The parts form treats the month as an index from 0 to 11, so 9 means October. The 0-based month is the most common source of off-by-one-month bugs. For example, a booking form that passes the month number 10 from a drop-down to new Date(2026, 10, 3) books 3 November instead of 3 October.
// 1. Milliseconds since 1 January 1970 UTC
const fromMillis = new Date(0); // 1970-01-01T00:00:00.000Z
// 2. ISO string with time zone: same instant everywhere
const fromIso = new Date("2026-10-03T09:00:00Z");
// 3. Year, month (0-based), day, hours, minutes in local time
const fromParts = new Date(2026, 9, 3, 14, 30);
// 4. UTC parts
const fromUtcParts = new Date(Date.UTC(2026, 9, 3, 14, 30));
// 5. Date-only string: parsed as UTC
const dateOnly = new Date("2026-10-03"); // 05:30 on 3 October in India
// 6. Date-time string without zone: parsed as local time
const localTime = new Date("2026-10-03T00:00"); // 00:00 on 3 October in India
// 7. Invalid input
const invalid = new Date("hello");
const isInvalid = Number.isNaN(invalid.getTime()); // isInvalid = true
Examples 5 and 6 look almost the same but give different moments. The ECMAScript date string rules read a date-only ISO string as UTC midnight and a date-time string without an offset as local time. In India, the first one is 05:30 local time. In a time zone west of UTC, such as New York, the same date-only string falls on the previous evening, so getDate() returns 2 instead of 3. To avoid the shift, we pass strings with an explicit Z or offset, or build local dates from parts.
The constructor never throws for bad input. It returns an “Invalid Date” whose getTime() is NaN, so we check user input with Number.isNaN(date.getTime()) before using it. Strings in other formats, such as “December 17, 2021 04:28:00”, may parse in one engine and fail in another; only the ISO format is guaranteed.
3. Getting the Current Date and Time
Calling new Date() without arguments creates a Date for the current moment, and Date.now() returns the same moment as a number of milliseconds. The number is the better choice for timestamps that we store in a database column of type number or use to measure durations, because no object is created.
const now = new Date();
// 1. Today as YYYY-MM-DD in local time
const today = now.toLocaleDateString("en-CA"); // e.g. "2026-10-03"
// 2. Today as YYYY-MM-DD in UTC
const todayUtc = now.toISOString().slice(0, 10); // e.g. "2026-10-03"
// 3. Current time as HH:mm
const time = now.toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" }); // e.g. "14:30"
// 4. Measure elapsed time
const start = Date.now();
const elapsed = Date.now() - start; // e.g. 0 (milliseconds)
The first two lines differ, because toISOString() always returns the UTC date, whereas the “en-CA” locale format returns the local date in the YYYY-MM-DD form. When we ran the example at 00:59 India time, the local line printed “2026-10-03” and the UTC line printed “2026-10-02”. For “today” as the user sees it, we use the local version. For example, a to-do app that lists the tasks due today must use the local date, or a user in India sees the previous day’s list between midnight and 05:30.
4. Reading Date and Time Parts
Each part of a date has its own getter method. The local getters return values in the time zone of the computer that runs the code, and every getter has a getUTC…() twin that returns the value in UTC.
| Method | Returns | Range |
|---|---|---|
| getFullYear() | Year | For example 2026 |
| getMonth() | Month index | 0 (January) to 11 (December) |
| getDate() | Day of the month | 1 to 31 |
| getDay() | Day of the week | 0 (Sunday) to 6 (Saturday) |
| getHours(), getMinutes(), getSeconds() | Time parts | 0-23, 0-59, 0-59 |
| getMilliseconds() | Milliseconds | 0 to 999 |
| getTime() | Milliseconds since 1 January 1970 UTC | Any number |
| getTimezoneOffset() | Difference from UTC in minutes | -330 in India |
The old getYear() method returns the year minus 1900 (126 for 2026) and is deprecated. TypeScript does not declare it at all, so date.getYear() fails with “error TS2339: Property ‘getYear’ does not exist on type ‘Date'”; we use getFullYear(). The sign of getTimezoneOffset() is the opposite of the usual notation, so for India, which is UTC+05:30, the method returns -330.
const date = new Date(2026, 9, 3, 14, 30, 15);
// 1. Local parts
const hours = date.getHours(); // hours = 14
const minutes = date.getMinutes(); // minutes = 30
const seconds = date.getSeconds(); // seconds = 15
// 2. UTC parts (India is UTC+05:30)
const utcHours = date.getUTCHours(); // utcHours = 9
const utcMinutes = date.getUTCMinutes(); // utcMinutes = 0
// 3. Offset from UTC in minutes
const offset = date.getTimezoneOffset(); // offset = -330
5. Adding and Subtracting Days, Months and Years
A Date has no addDays() method, so we read a part, add to it, and write it back with the matching setter, such as setDate(), setMonth(), setFullYear() or setHours(). For example, a library app sets the return date of a loan to 30 days after the checkout date. The setters change the object in place, so we copy the date first with new Date(original) when the original must stay unchanged.
const start = new Date(2026, 9, 3);
// 1. Add and subtract days, months and years
const plusDays = new Date(start);
plusDays.setDate(plusDays.getDate() + 30); // 2 November 2026
const minusDays = new Date(start);
minusDays.setDate(minusDays.getDate() - 7); // 26 September 2026
const nextYear = new Date(start);
nextYear.setFullYear(nextYear.getFullYear() + 1); // 3 October 2027
// 2. Month end: 31 January + 1 month overflows
const jan31 = new Date(2026, 0, 31);
jan31.setMonth(jan31.getMonth() + 1); // 3 March 2026, not 28 February
// 3. Days between two dates
const end = new Date(2026, 11, 25);
const msPerDay = 24 * 60 * 60 * 1000;
const daysLeft = Math.round((end.getTime() - start.getTime()) / msPerDay); // daysLeft = 83
The setters accept values outside the normal range and roll the extra over into the next unit. The rollover is why adding 30 days to 3 October moves into November without any special code. The same rule produces the month-end problem in the second example, because 31 January plus one month asks for 31 February, which rolls over to 3 March. Code that adds months to end-of-month dates must clamp the day itself, for example by checking whether getDate() changed and calling setDate(0), which moves to the last day of the previous month.
For the difference in days, we subtract the timestamps and divide by the milliseconds in a day. Math.round() matters in countries with daylight saving time, because a day in which the clocks change has 23 or 25 hours, and plain division would give a fraction.
6. Comparing Two Dates
The === and == operators compare two Date objects by reference, so two objects for the same moment are not equal. We compare the numbers from getTime() instead. The < and > operators work on Date objects without getTime(), because JavaScript converts them to numbers first. For example, a hotel booking form compares the two dates to reject a check-out date that is not after the check-in date.
const a = new Date(2026, 9, 3);
const b = new Date(2026, 9, 3);
const c = new Date(2026, 9, 10);
const sameObject = a === b; // sameObject = false, two objects
const sameTime = a.getTime() === b.getTime(); // sameTime = true
const earlier = a < c; // earlier = true
const latest = new Date(Math.max(a.getTime(), c.getTime())); // latest = 10 October 2026
// Sort dates, oldest first
const sorted = [c, a].toSorted((x, y) => x.getTime() - y.getTime());
The ES2023 method toSorted() returns a sorted copy and leaves the original array unchanged. TypeScript reports a – b on two Date objects as an error (“The left-hand side of an arithmetic operation must be of type ‘any’, ‘number’, ‘bigint’ or an enum type”), which is why the compare function calls getTime(). To check whether two dates fall on the same calendar day, we compare the “en-CA” strings from section 3, or each local part from getFullYear() down to getDate().
7. Formatting a Date
For display, the Intl.DateTimeFormat API formats dates for any locale and time zone, and toLocaleDateString() is a shortcut for it. For storage and APIs, toISOString() gives the standard UTC format that every system can parse. For example, an online shop shows the order date in the customer’s locale but sends the toISOString() value to its API.
const date = new Date(2026, 9, 3, 14, 30);
// 1. Built-in formats
const iso = date.toISOString(); // iso = "2026-10-03T09:00:00.000Z"
const short = date.toDateString(); // short = "Sat Oct 03 2026"
// 2. Locale formats with options
const long = date.toLocaleDateString("en-US", {
weekday: "long", year: "numeric", month: "long", day: "numeric",
}); // long = "Saturday, October 3, 2026"
const german = date.toLocaleDateString("de-DE"); // german = "3.10.2026"
// 3. Another time zone
const newYork = new Intl.DateTimeFormat("en-US", {
dateStyle: "medium", timeStyle: "short", timeZone: "America/New_York",
}).format(date); // newYork = "Oct 3, 2026, 5:00 AM"
// 4. Custom format dd/MM/yyyy
const dd = String(date.getDate()).padStart(2, "0");
const mm = String(date.getMonth() + 1).padStart(2, "0");
const custom = dd + "/" + mm + "/" + date.getFullYear(); // custom = "03/10/2026"
The timeZone option is the only built-in way to show a date in a zone other than the computer’s own; a Date object itself has no time zone, only a moment. TypeScript checks the options object, so a typo such as weekday: “longg” is a compile error, and the message even suggests the fix, “Type ‘”longg”‘ is not assignable to type ‘”long” | “narrow” | “short” | undefined’. Did you mean ‘”long”‘?”
For a fixed pattern that no locale provides, we build the string from the parts and pad them with padStart(), as in the fourth example; the + 1 converts the 0-based month to the usual 1 to 12.
8. Dates in JSON and API Data
JSON has no date type. JSON.stringify() converts a Date to its ISO string, and JSON.parse() leaves that string as a string. TypeScript cannot see the conversion at runtime, so after JSON.parse(…) as Order, the compiler treats createdAt as a Date, and the first call to getDate() on it throws a TypeError.
interface Order { id: number; createdAt: Date }
const order: Order = { id: 1, createdAt: new Date(2026, 9, 3) };
// 1. JSON turns a Date into a string
const json = JSON.stringify(order); // json = {"id":1,"createdAt":"2026-10-02T18:30:00.000Z"}
// 2. Parsing does not turn it back
const parsed = JSON.parse(json) as Order;
const isDate = parsed.createdAt instanceof Date; // isDate = false, it is a string
// 3. Convert explicitly
const restored: Order = { ...parsed, createdAt: new Date(parsed.createdAt) };
const day = restored.createdAt.getDate(); // day = 3
We convert date fields explicitly after parsing, or we declare the incoming field as a string and convert it at the boundary of the application. The JSON value also shows the time zone effect from section 2, because midnight on 3 October in India is 18:30 on 2 October in UTC. When only the calendar date matters (a birthday, a due date), we store it as a “2026-10-03” string instead of a full timestamp.
9. The Temporal API
The problems with Date (0-based months, objects that change in place, no time zone support, parsing rules that depend on the string format) are the reason JavaScript is getting a new date API called Temporal. It has separate immutable types for a calendar date (Temporal.PlainDate), a time of day, an exact instant and a date-time in a named time zone, and methods such as add({ months: 1 }) that clamp the day at month end.
On the day of writing, Temporal is standardized but not yet available in every runtime.
- TC39 moved the Temporal proposal to Stage 4 in 2026, so it will be part of a future ECMAScript edition; the TC39 list of finished proposals expects it in ES2027.
- MDN marks Temporal as “Limited availability”, which means it is not yet available in all major browsers.
- Node.js 22 does not provide a global Temporal object by default (typeof Temporal is “undefined”).
- TypeScript 7.0 includes the type declarations in the library file lib.esnext.temporal.d.ts, loaded with “lib”: [“esnext”]. The types only describe the API; on Node.js 22 the code also needs a polyfill such as @js-temporal/polyfill.
Until Temporal is available in the runtimes we target, Date stays the standard choice, with the rules from this article. For heavy time zone work, libraries such as date-fns or Luxon are an option today.
10. Example Project With Fixed Time Zone
The Date examples hold every snippet from this article, one file per section, built with TypeScript 7.0.2 for Node.js 22. Since date output depends on the computer’s time zone, index.ts sets process.env.TZ to “Asia/Kolkata” before running the snippets, so the values match the comments on any computer.
npm install
npm start
The lines that use the current time print different values on every run. The others match the article, for example the formatting section.
=== Formatting ===
iso = 2026-10-03T09:00:00.000Z | short = Sat Oct 03 2026
long = Saturday, October 3, 2026 | german = 3.10.2026
newYork = Oct 3, 2026, 5:00 AM | custom = 03/10/2026
11. Conclusion
A TypeScript Date is the JavaScript Date with compile-time type checks. The calls new Date() and Date.now() give the current moment, the getters and setters read and change parts in local time or UTC, getTime() is the reliable way to compare, and Intl.DateTimeFormat or toLocaleDateString() format dates for users.
Most bugs come from the 0-based month, date-only strings parsed as UTC, setters that change the original object, and dates that turn into strings in JSON. Temporal fixes these problems at the API level, but until runtimes ship it by default, the Date object with these rules is the tool to use.
12. References
MDN documents the Date and Intl APIs in detail, and the TC39 repository tracks the Temporal proposal.
- MDN: Date
- MDN: Date time string format
- MDN: Intl.DateTimeFormat
- MDN: Temporal
- TC39: Temporal proposal
- TypeScript Handbook: Everyday Types
Happy Learning !!