Date & Time #

Dates and times are one of those topics that look simple but are full of traps — timezones, daylight saving time, different formats across countries, and an internal representation that often confuses. JavaScript’s built-in Date object has long been criticized for its inconsistent design: months start at 0 not 1, methods mutate the object, and timezone handling is limited. Even so, Date remains a foundation worth understanding because it’s used throughout the Node.js ecosystem. This article covers Date in depth, Intl.DateTimeFormat for correct per-locale formatting, and safe time handling patterns in production applications.

The Basic Date Object #

// creating a Date

// now
const sekarang = new Date();
console.log(sekarang); // 2024-01-15T10:30:00.000Z

// from a Unix timestamp (milliseconds since Jan 1 1970 UTC)
const dariTimestamp = new Date(1705312200000);

// from an ISO 8601 string — the safest format for parsing
const dariISO = new Date("2024-01-15T10:30:00.000Z");

// from other strings — AVOID, results differ across browsers/Node.js
const dariString = new Date("January 15, 2024"); // ✗ inconsistent across environments

// from components — CAUTION: months start at 0!
const dariKomponen = new Date(2024, 0, 15, 10, 30, 0); // 15 Jan 2024, 10:30:00
//                                  ↑ 0 = January!

// ANTI-PATTERN: forgetting that months start at 0
const salah = new Date(2024, 1, 15); // ✗ this is February, not January!

// CORRECT: use constants for clarity, or use an ISO string
const benar = new Date("2024-01-15"); // ✓ ISO strings are unambiguous

// Date.now() — the current timestamp in milliseconds (faster than new Date())
const timestamp = Date.now();

// Date.UTC() — create a UTC timestamp from components (months still 0-indexed)
const timestampUTC = Date.UTC(2024, 0, 15, 10, 30, 0);

Reading Date Components #

Date has two sets of methods: ones working in the local timezone (getFullYear, getMonth, etc.) and ones working in UTC (getUTCFullYear, getUTCMonth, etc.).

const d = new Date("2024-01-15T10:30:45.123Z");

// components in the LOCAL timezone (results differ depending on server/client timezone)
console.log(d.getFullYear());     // 2024 (or maybe different if UTC+X)
console.log(d.getMonth());        // 0 (January — remember: 0-indexed!)
console.log(d.getDate());         // 15 (day of the month)
console.log(d.getDay());          // 1 (day of the week: 0=Sunday, 1=Monday)
console.log(d.getHours());        // depends on the local timezone
console.log(d.getMinutes());      // 30
console.log(d.getSeconds());      // 45
console.log(d.getMilliseconds()); // 123
console.log(d.getTime());         // timestamp in milliseconds (always UTC)
console.log(d.getTimezoneOffset()); // timezone offset in minutes (negative for UTC+)

// components in UTC — consistent across all timezones
console.log(d.getUTCFullYear());  // 2024
console.log(d.getUTCMonth());     // 0
console.log(d.getUTCDate());      // 15
console.log(d.getUTCHours());     // 10 — always 10, regardless of the local timezone
console.log(d.getUTCMinutes());   // 30

// day and month names — use Intl, not manual arrays
const namaHari = ["Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jumat", "Sabtu"];
const namaBulan = [
  "Januari", "Februari", "Maret", "April", "Mei", "Juni",
  "Juli", "Agustus", "September", "Oktober", "November", "Desember"
];

// ANTI-PATTERN: manual name arrays (not international)
console.log(namaHari[d.getDay()]); // ✗ only works for one language

// CORRECT: use Intl.DateTimeFormat
const formatter = new Intl.DateTimeFormat("id-ID", { weekday: "long" });
console.log(formatter.format(d)); // "Senin" — automatic per locale

Writing Date Components #

The Date object is mutable — set* methods modify the object directly, rather than creating a new one. This is a common source of bugs.

const d = new Date("2024-01-15T10:30:00Z");

// ANTI-PATTERN: directly modifying a shared object
function tambahSatuHariSalah(tanggal: Date): Date {
  tanggal.setDate(tanggal.getDate() + 1); // ✗ modifies the original object!
  return tanggal;
}

const tgl = new Date("2024-01-15");
const besok = tambahSatuHariSalah(tgl);
console.log(tgl.toISOString());   // "2024-01-16..." — tgl changed too!
console.log(besok.toISOString()); // "2024-01-16..."

// CORRECT: always make a copy before modifying
function tambahHari(tanggal: Date, jumlah: number): Date {
  const salinan = new Date(tanggal.getTime()); // make a copy via the timestamp
  salinan.setDate(salinan.getDate() + jumlah);
  return salinan;
}

const tgl2 = new Date("2024-01-15");
const besok2 = tambahHari(tgl2, 1);
console.log(tgl2.toISOString());   // "2024-01-15..." — unchanged ✓
console.log(besok2.toISOString()); // "2024-01-16..."

// available set methods
const d2 = new Date();
d2.setFullYear(2025);
d2.setMonth(5);        // June (0-indexed)
d2.setDate(20);
d2.setHours(14);
d2.setMinutes(30);
d2.setSeconds(0);
d2.setMilliseconds(0);

// set UTC
d2.setUTCFullYear(2025);
d2.setUTCMonth(5);
d2.setUTCHours(7); // 07:00 UTC = 14:00 WIB (UTC+7)

Date Formatting #

toString and toISOString #

const d = new Date("2024-01-15T10:30:00.000Z");

// toISOString — ISO 8601 format, always UTC, the standard format for APIs
console.log(d.toISOString());
// "2024-01-15T10:30:00.000Z"

// toLocaleDateString — date format according to the locale
console.log(d.toLocaleDateString("id-ID"));
// "15/1/2024" or "15 Januari 2024" depending on the implementation

// toLocaleTimeString — time format according to the locale
console.log(d.toLocaleTimeString("id-ID"));

// toLocaleString — date and time according to the locale
console.log(d.toLocaleString("id-ID"));

// toUTCString — RFC 7231 format (for HTTP headers)
console.log(d.toUTCString());
// "Mon, 15 Jan 2024 10:30:00 GMT"

// ANTI-PATTERN: formatting dates with manual string concatenation
function formatTanggalSalah(d: Date): string {
  return d.getDate() + "/" + (d.getMonth() + 1) + "/" + d.getFullYear(); // ✗
  // problems: no zero-padding, not timezone-aware
}

// CORRECT: use Intl.DateTimeFormat
function formatTanggal(d: Date, locale: string = "id-ID"): string {
  return new Intl.DateTimeFormat(locale, {
    day: "2-digit",
    month: "2-digit",
    year: "numeric",
  }).format(d);
}

console.log(formatTanggal(d)); // "15/01/2024"

Intl.DateTimeFormat — Professional Formatting #

Intl.DateTimeFormat is the right way to format dates — it automatically follows the conventions of each locale and timezone.

const d = new Date("2024-01-15T10:30:00.000Z");

// full format for Indonesia
const formatIndonesia = new Intl.DateTimeFormat("id-ID", {
  weekday: "long",   // "Senin"
  day: "numeric",    // "15"
  month: "long",     // "Januari"
  year: "numeric",   // "2024"
  hour: "2-digit",   // "17" (in WIB = UTC+7)
  minute: "2-digit", // "30"
  timeZone: "Asia/Jakarta",
});

console.log(formatIndonesia.format(d));
// "Senin, 15 Januari 2024 pukul 17.30"

// short format
const formatSingkat = new Intl.DateTimeFormat("id-ID", {
  day: "2-digit",
  month: "short",
  year: "numeric",
  timeZone: "Asia/Jakarta",
});

console.log(formatSingkat.format(d)); // "15 Jan 2024"

// time only
const formatWaktu = new Intl.DateTimeFormat("id-ID", {
  hour: "2-digit",
  minute: "2-digit",
  second: "2-digit",
  timeZoneName: "short",
  timeZone: "Asia/Jakarta",
});

console.log(formatWaktu.format(d)); // "17.30.00 WIB"

// relative format — "3 hari yang lalu", "dalam 2 jam"
const formatRelatif = new Intl.RelativeTimeFormat("id-ID", {
  numeric: "auto", // "kemarin" instead of "1 hari yang lalu"
});

console.log(formatRelatif.format(-1, "day"));    // "kemarin"
console.log(formatRelatif.format(-3, "day"));    // "3 hari yang lalu"
console.log(formatRelatif.format(2, "hour"));    // "dalam 2 jam"
console.log(formatRelatif.format(-30, "minute")); // "30 menit yang lalu"

// helper: calculate and format relative time
function waktuRelatif(tanggal: Date, locale: string = "id-ID"): string {
  const formatter = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
  const selisihDetik = Math.round((tanggal.getTime() - Date.now()) / 1000);

  const batas = [
    { unit: "year" as const, detik: 365 * 24 * 3600 },
    { unit: "month" as const, detik: 30 * 24 * 3600 },
    { unit: "week" as const, detik: 7 * 24 * 3600 },
    { unit: "day" as const, detik: 24 * 3600 },
    { unit: "hour" as const, detik: 3600 },
    { unit: "minute" as const, detik: 60 },
    { unit: "second" as const, detik: 1 },
  ];

  for (const { unit, detik } of batas) {
    const nilai = Math.round(selisihDetik / detik);
    if (Math.abs(nilai) >= 1) {
      return formatter.format(nilai, unit);
    }
  }

  return "baru saja";
}

const tigaHariLalu = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000);
console.log(waktuRelatif(tigaHariLalu)); // "3 hari yang lalu"

Custom Formats #

For very specific formats (e.g. for file names or databases), Intl.DateTimeFormat might be too flexible. Use formatToParts() for full control:

function formatKustom(d: Date, timezone: string = "Asia/Jakarta"): {
  tanggal: string;  // "2024-01-15"
  waktu: string;    // "17:30:00"
  dateTime: string; // "2024-01-15 17:30:00"
  namaFile: string; // "20240115_173000"
} {
  const parts = new Intl.DateTimeFormat("en-CA", {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
    hour12: false,
    timeZone: timezone,
  }).formatToParts(d);

  const get = (type: string) => parts.find((p) => p.type === type)?.value ?? "";

  const tanggal = `${get("year")}-${get("month")}-${get("day")}`;
  const waktu = `${get("hour")}:${get("minute")}:${get("second")}`;

  return {
    tanggal,
    waktu,
    dateTime: `${tanggal} ${waktu}`,
    namaFile: `${get("year")}${get("month")}${get("day")}_${get("hour")}${get("minute")}${get("second")}`,
  };
}

const d = new Date("2024-01-15T10:30:00.000Z");
console.log(formatKustom(d));
// { tanggal: "2024-01-15", waktu: "17:30:00", dateTime: "2024-01-15 17:30:00", namaFile: "20240115_173000" }

Date Arithmetic #

// always make a copy before modifying
function salinanDate(d: Date): Date {
  return new Date(d.getTime());
}

// add/subtract days
function tambahHari(d: Date, jumlah: number): Date {
  const hasil = salinanDate(d);
  hasil.setDate(hasil.getDate() + jumlah);
  return hasil;
}

// add/subtract months — setMonth handles overflow automatically
function tambahBulan(d: Date, jumlah: number): Date {
  const hasil = salinanDate(d);
  hasil.setMonth(hasil.getMonth() + jumlah);
  return hasil;
}

// CAUTION: tambahBulan can produce unexpected dates
const tgl31Jan = new Date("2024-01-31");
console.log(tambahBulan(tgl31Jan, 1).toISOString());
// "2024-03-02" — Feb has no 31st, overflow into March!

// for this case, clamp to the end of the month
function tambahBulanAman(d: Date, jumlah: number): Date {
  const hasil = salinanDate(d);
  const hariAsli = d.getDate();
  hasil.setMonth(hasil.getMonth() + jumlah);

  // if the day overflowed, set it to the last day of the target month
  if (hasil.getDate() !== hariAsli) {
    hasil.setDate(0); // setDate(0) = the last day of the previous month
  }

  return hasil;
}

console.log(tambahBulanAman(tgl31Jan, 1).toISOString());
// "2024-02-29" — the last day of February 2024 (a leap year)

// add/subtract years
function tambahTahun(d: Date, jumlah: number): Date {
  const hasil = salinanDate(d);
  hasil.setFullYear(hasil.getFullYear() + jumlah);
  return hasil;
}

// difference between two dates
function selisihHari(a: Date, b: Date): number {
  const ms = Math.abs(b.getTime() - a.getTime());
  return Math.floor(ms / (1000 * 60 * 60 * 24));
}

function selisihBulan(a: Date, b: Date): number {
  return (
    (b.getFullYear() - a.getFullYear()) * 12 +
    (b.getMonth() - a.getMonth())
  );
}

function selisihTahun(a: Date, b: Date): number {
  return b.getFullYear() - a.getFullYear();
}

// example
const lahir = new Date("1995-03-20");
const sekarang = new Date("2024-01-15");

console.log(`Umur: ${selisihTahun(lahir, sekarang)} tahun`); // 28
console.log(`Selisih: ${selisihHari(lahir, sekarang)} hari`); // 10527

// start and end of periods
function awalHari(d: Date, timezone?: string): Date {
  if (timezone) {
    // use Intl to get the date in a specific timezone
    const parts = new Intl.DateTimeFormat("en-CA", {
      year: "numeric", month: "2-digit", day: "2-digit",
      timeZone: timezone,
    }).formatToParts(d);
    const get = (type: string) => parts.find((p) => p.type === type)?.value ?? "";
    return new Date(`${get("year")}-${get("month")}-${get("day")}T00:00:00`);
  }
  const hasil = salinanDate(d);
  hasil.setHours(0, 0, 0, 0);
  return hasil;
}

function akhirHari(d: Date): Date {
  const hasil = salinanDate(d);
  hasil.setHours(23, 59, 59, 999);
  return hasil;
}

function awalBulan(d: Date): Date {
  const hasil = salinanDate(d);
  hasil.setDate(1);
  hasil.setHours(0, 0, 0, 0);
  return hasil;
}

function akhirBulan(d: Date): Date {
  const hasil = salinanDate(d);
  hasil.setMonth(hasil.getMonth() + 1, 0); // setDate(0) = the last day of this month
  hasil.setHours(23, 59, 59, 999);
  return hasil;
}

Timezones #

Timezones are the most common source of Date bugs. The entire Date object stores time in UTC internally — the local timezone is only used when displaying or reading components.

flowchart LR
    A["Input string\n'2024-01-15T10:30:00Z'"] -- parse --> B["Internal\nUTC timestamp\n1705312200000ms"]
    B -- "getHours()\nLocal timezone" --> C["17 (WIB, UTC+7)\n10 (UTC)\n05 (New York, UTC-5)"]
    B -- "toISOString()" --> D["'2024-01-15T10:30:00.000Z'\nAlways UTC"]
// the most common timezone problem: parsing strings without a timezone
const tanpaTZ = new Date("2024-01-15");
// In Node.js, a date string without a time is parsed as UTC midnight!
console.log(tanpaTZ.toISOString()); // "2024-01-15T00:00:00.000Z"
// But if displayed in WIB (UTC+7):
// getHours() = 7 — a day ahead for users in UTC-8!

// a string with a time but no timezone is parsed as LOCAL time
const denganWaktu = new Date("2024-01-15T00:00:00");
// Depends on the server timezone — inconsistent!

// CORRECT: always include the timezone in parsed strings
const konsisten = new Date("2024-01-15T00:00:00Z");           // UTC
const wib = new Date("2024-01-15T00:00:00+07:00");            // WIB
const withTimezone = new Date("2024-01-15T07:00:00.000Z");    // UTC, same as WIB midnight

// get the current date in a specific timezone
function tanggalSaatIniDi(timezone: string): string {
  return new Intl.DateTimeFormat("en-CA", {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    timeZone: timezone,
  }).format(new Date());
}

console.log(tanggalSaatIniDi("Asia/Jakarta"));      // "2024-01-15"
console.log(tanggalSaatIniDi("America/New_York"));  // maybe "2024-01-14" in the evening

// converting time between timezones
function konversiTimezone(d: Date, dariTZ: string, keTZ: string): string {
  // you can't really "convert" a Date to another timezone —
  // a Date is always UTC. Only its display formatting differs.
  return new Intl.DateTimeFormat("en-CA", {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
    hour12: false,
    timeZone: keTZ,
  }).format(d);
}

const sekarang = new Date("2024-01-15T10:30:00Z");
console.log(konversiTimezone(sekarang, "UTC", "Asia/Jakarta"));
// "2024-01-15, 17:30:00" (WIB = UTC+7)

console.log(konversiTimezone(sekarang, "UTC", "America/New_York"));
// "2024-01-15, 05:30:00" (EST = UTC-5)
Always store and transfer time in UTC format (ISO 8601 with the Z suffix) in databases and APIs. Converting to a local timezone only happens at the presentation layer — when displaying to users. This prevents the very common bug where times shift when data moves between servers with different timezones.

Safe Date Parsing #

new Date(string) behaves inconsistently for formats other than ISO 8601. For robust parsing, always validate the result.

// safe parsing — validate after parsing
function parseTanggal(input: string): Date | null {
  const d = new Date(input);

  // Date("invalid") produces "Invalid Date"
  // isNaN on its timestamp detects this
  if (isNaN(d.getTime())) return null;

  return d;
}

// parsing the DD/MM/YYYY format (common in Indonesia)
function parseTanggalID(input: string): Date | null {
  const match = input.match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
  if (!match) return null;

  const [, hari, bulan, tahun] = match;

  // create in UTC so the timezone doesn't affect it
  const d = new Date(Date.UTC(
    parseInt(tahun),
    parseInt(bulan) - 1,  // convert to 0-indexed
    parseInt(hari)
  ));

  // validate that the date is valid (e.g. 31/02/2024 doesn't exist)
  if (
    d.getUTCDate() !== parseInt(hari) ||
    d.getUTCMonth() !== parseInt(bulan) - 1 ||
    d.getUTCFullYear() !== parseInt(tahun)
  ) {
    return null; // date overflow — invalid
  }

  return d;
}

console.log(parseTanggalID("15/01/2024")); // a Date object
console.log(parseTanggalID("31/02/2024")); // null — Feb 31 doesn't exist
console.log(parseTanggalID("abc"));        // null — wrong format

// date range validation
function isRentangValid(mulai: Date, akhir: Date): boolean {
  return mulai.getTime() <= akhir.getTime();
}

function isTanggalDiMasaDepan(d: Date): boolean {
  return d.getTime() > Date.now();
}

function isUmurValid(tanggalLahir: Date, minUmur: number = 17): boolean {
  const umur = selisihTahun(tanggalLahir, new Date());
  return umur >= minUmur;
}

function selisihTahun(a: Date, b: Date): number {
  return b.getFullYear() - a.getFullYear();
}

Common Patterns in Applications #

Timestamps for Databases #

// store as an ISO string (recommended for portability)
function sekarangISO(): string {
  return new Date().toISOString();
  // "2024-01-15T10:30:00.123Z"
}

// store as a Unix timestamp (an integer, more compact)
function sekarangTimestamp(): number {
  return Date.now(); // milliseconds
}

function sekarangTimestampDetik(): number {
  return Math.floor(Date.now() / 1000); // seconds (for JWT exp, etc.)
}

// convert between formats
function isoKeTimestamp(iso: string): number {
  return new Date(iso).getTime();
}

function timestampKeISO(ms: number): string {
  return new Date(ms).toISOString();
}

Range Pickers and Periods #

interface Periode {
  mulai: Date;
  akhir: Date;
}

function periodeHariIni(timezone: string = "Asia/Jakarta"): Periode {
  const sekarang = new Date();

  // get today's date in the specified timezone
  const tanggalStr = tanggalSaatIniDi(timezone);
  const mulai = new Date(`${tanggalStr}T00:00:00+07:00`);
  const akhir = new Date(`${tanggalStr}T23:59:59.999+07:00`);

  return { mulai, akhir };
}

function periodeMinggIni(): Periode {
  const sekarang = new Date();
  const hariIni = sekarang.getDay(); // 0=Sunday, 1=Monday...
  const selisihKeSenin = hariIni === 0 ? -6 : 1 - hariIni;

  const mulai = tambahHari(awalHari(sekarang), selisihKeSenin);
  const akhir = tambahHari(mulai, 6);
  akhir.setHours(23, 59, 59, 999);

  return { mulai, akhir };
}

function periodeBulanIni(): Periode {
  const sekarang = new Date();
  return {
    mulai: awalBulan(sekarang),
    akhir: akhirBulan(sekarang),
  };
}

function periode30HariTerakhir(): Periode {
  const akhir = new Date();
  const mulai = tambahHari(akhir, -30);
  mulai.setHours(0, 0, 0, 0);
  return { mulai, akhir };
}

function awalHari(d: Date): Date {
  const hasil = new Date(d.getTime());
  hasil.setHours(0, 0, 0, 0);
  return hasil;
}

function tambahHari(d: Date, jumlah: number): Date {
  const hasil = new Date(d.getTime());
  hasil.setDate(hasil.getDate() + jumlah);
  return hasil;
}

function awalBulan(d: Date): Date {
  const hasil = new Date(d.getTime());
  hasil.setDate(1);
  hasil.setHours(0, 0, 0, 0);
  return hasil;
}

function akhirBulan(d: Date): Date {
  const hasil = new Date(d.getTime());
  hasil.setMonth(hasil.getMonth() + 1, 0);
  hasil.setHours(23, 59, 59, 999);
  return hasil;
}

function tanggalSaatIniDi(timezone: string): string {
  return new Intl.DateTimeFormat("en-CA", {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    timeZone: timezone,
  }).format(new Date());
}

Caching Formatters #

Creating a new Intl.DateTimeFormat instance every time a format is called is fairly expensive. Cache frequently used instances:

// ANTI-PATTERN: creating a new formatter on every call
function formatTanggalBoros(d: Date): string {
  return new Intl.DateTimeFormat("id-ID", {  // ✗ a new allocation every time
    day: "2-digit",
    month: "long",
    year: "numeric",
  }).format(d);
}

// CORRECT: cache the formatter
const formatterCache = new Map<string, Intl.DateTimeFormat>();

function getFormatter(locale: string, options: Intl.DateTimeFormatOptions): Intl.DateTimeFormat {
  const key = `${locale}:${JSON.stringify(options)}`;

  if (!formatterCache.has(key)) {
    formatterCache.set(key, new Intl.DateTimeFormat(locale, options));
  }

  return formatterCache.get(key)!;
}

// frequently used formatters — define once
const fmt = {
  tanggal: getFormatter("id-ID", { day: "2-digit", month: "long", year: "numeric", timeZone: "Asia/Jakarta" }),
  waktu: getFormatter("id-ID", { hour: "2-digit", minute: "2-digit", timeZone: "Asia/Jakarta" }),
  lengkap: getFormatter("id-ID", { day: "2-digit", month: "short", year: "numeric", hour: "2-digit", minute: "2-digit", timeZone: "Asia/Jakarta" }),
};

console.log(fmt.tanggal.format(new Date())); // "15 Januari 2024"
console.log(fmt.waktu.format(new Date()));   // "17.30"

Summary #

  • Months in Date start at 0 — January = 0, December = 11. This is the most common source of bugs; always use ISO 8601 strings to create unambiguous Dates.
  • Date is mutable — always make a copy with new Date(d.getTime()) before modifying; don’t mutate a Date received as a parameter.
  • Store and transfer time in UTC — use toISOString() for databases and APIs; convert to a local timezone only at the presentation layer with Intl.DateTimeFormat.
  • Use Intl.DateTimeFormat instead of manual formatting — it handles locale, timezone, and display conventions automatically; far more accurate than string concatenation or manual month name arrays.
  • Cache frequently used Intl.DateTimeFormat instances — creating a new instance per call is fairly expensive; store them in a Map or module variable.
  • Intl.RelativeTimeFormat for relative time — “3 hari yang lalu”, “dalam 2 jam” — more accurate and international than manual implementations.
  • Validate parsing resultsnew Date("invalid-string") returns “Invalid Date” instead of throwing; always check isNaN(d.getTime()) after parsing.
  • tambahBulan can overflow — Jan 31 + 1 month = Mar 2, not Feb 28/29. Use a clamp to the target month’s last day if this behavior isn’t desired.
  • Date.now() is faster than new Date().getTime() for timestamps — use it for critical performance like benchmarking or logging.

← Previous: Timers
About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact