npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@qantesm/nanodate

v0.2.2

Published

World's smallest date library. Zero-locale-payload. Intl-native.

Readme


📊 The Size Difference

| | Moment.js | Day.js | Luxon | 🏆 NanoDate | |---|---|---|---|---| | Core Size | ❌ 72 KB | ⚠️ 2 KB | ❌ 23 KB | ✅ 0.69 KB (Lite) | | + Turkish | + 3 KB | + 1 KB | + 0 KB | + 0 KB | | + Japanese | + 4 KB | + 1 KB | + 0 KB | + 0 KB | | All 400+ Langs | 😱 ~350 KB | 😰 ~100 KB | ⚠️ ~23 KB | 🎉 0.69 KB | | Timezone Data | + 40 KB | + 40 KB | Built-in | ✅ 0 KB (Native) |

How is this possible? NanoDate uses the browser's built-in Intl API instead of bundling locale data. Your browser already knows how to say "January" in 400+ languages! 🌍


⚡ Performance

NanoDate is engineered for extreme performance, consistently outperforming popular libraries in real-world scenarios.

| Category | Winner | NanoDate | vs Day.js | Memory | | :--- | :--- | :--- | :--- | :--- | | Formatting | 🥇 NanoDate | ~9.8M ops/s | 19x faster | 0 B (Static) | | Diffing | 🥇 NanoDate | ~8.9M ops/s | 4.4x faster | 0 B (Static) | | Chained Ops | 🥇 NanoDate | ~5.8M ops/s | 12x faster | Optimized | | Object Creation| Native | ~6.2M ops/s | 1.3x faster | 177 B |

Benchmarks run on Node.js v24, 100,000 iterations. See full benchmarks →


🧪 The V8 Philosophy: How are we so fast?

NanoDate isn't just small; it's optimized for the V8 engine's internal mechanics.

1. Regex-Free Parsing

Most libraries use complex RegEx for ISO parsing, which is slow and memory-intensive. NanoDate uses a pure character-code indexing parser (ultraFastParse) that achieves 5M+ ops/sec by avoiding regex overhead.

2. Hidden Classes & Monomorphism

We ensure all NanoDate contexts have a consistent shape. By avoiding dynamic property additions after initialization, we help V8 keep the objects in "Fast Mode" with optimized hidden classes.

3. Zero-Allocation Patterns

Our .chain() and .batch() helpers reuse internal context objects to minimize Garbage Collection (GC) pressure. In high-frequency operations (like rendering a 10,000-row table), this prevents "jank" caused by memory churn.


🚀 Key Features

  • < 0.7KB Core (Lite bundle, brotlied)
  • Zero Locale Payload - 400+ languages with 0 bytes extra.
  • Intl-Native - Uses the platform, doesn't reinvent it.
  • 100% Immutable - No mutation bugs, ever.
  • Tree-shakable - Pay only for what you use.

📦 Installation

npm install @qantesm/nanodate
import { nano } from '@qantesm/nanodate';

// Standard Usage
nano('2026-01-21', 'tr').format('dddd'); // "Çarşamba"

// 🚀 Performance Mode: Chain (Zero-allocation)
const ts = nano().chain().add(7, 'days').subtract(2, 'hours').value();

// 📅 Calendar View
nano().calendar(); // "Today at 2:30 PM"
nano().subtract(1, 'day').calendar(); // "Yesterday at 2:30 PM"

// 🕒 Durations
nano.duration(5000).humanize(); // "5 seconds"

📦 Installation

npm install @qantesm/nanodate
yarn add @qantesm/nanodate
pnpm add @qantesm/nanodate

Choose Your Bundle

// Full features (~2.5KB gzipped)
import { nano } from '@qantesm/nanodate';

// Minimal core (< 1KB gzipped)
import { nano } from '@qantesm/nanodate/lite';

⚡ Quick Start

import { nano } from '@qantesm/nanodate';

// Current date
nano().format('YYYY-MM-DD');  // "2026-01-21"

// With Turkish locale - NO extra bundle!
nano('2026-01-21', 'tr').format('dddd, MMMM Do YYYY');
// "Çarşamba, Ocak 21. 2026"

// With Japanese locale - STILL no extra bundle!
nano('2026-01-21', 'ja').format('dddd');
// "水曜日"

// Relative time (zero locale payload!)
nano('2026-01-20').fromNow();       // "1 day ago"
nano('2026-01-20', 'tr').fromNow(); // "1 gün önce"
nano('2026-01-20', 'ja').fromNow(); // "1日前"
nano('2026-01-20', 'ar').fromNow(); // "منذ يوم واحد"

// Immutable manipulation
nano()
  .add(7, 'days')
  .startOf('month')
  .format('DD MMMM YYYY');  // "01 Şubat 2026"

// Timezone (zero-cost!)
nano().tz('America/New_York');  // NYC time
nano().tz('Asia/Tokyo');        // Tokyo time

📖 API

Creating Dates

import { nano, utc, fromUnix } from '@qantesm/nanodate';

nano()                      // Now
nano('2026-01-21')          // ISO string
nano(1737452400000)         // Unix timestamp (ms)
nano(new Date())            // Date object
nano('2026-01-21', 'tr')    // With locale

utc()                       // Now in UTC
fromUnix(1737452400)        // Unix timestamp (seconds)

Formatting

// Token-based formatting
nano().format('YYYY-MM-DD');           // "2026-01-21"
nano().format('dddd, MMMM Do YYYY');   // "Wednesday, January 21st 2026"
nano().format('HH:mm:ss');             // "12:36:33"
nano().format('hh:mm A');              // "12:36 PM"

// Preset formats (uses native Intl dateStyle - zero extra bytes!)
nano().format('short');                // "1/21/26"
nano().format('medium');               // "Jan 21, 2026"
nano().format('long');                 // "January 21, 2026"
nano().format('full');                 // "Wednesday, January 21, 2026"
nano().format('full-time');            // Full date with time

// Escape characters with brackets
nano().format('[Today is] dddd');      // "Today is Wednesday"

Format Tokens

| Token | Output | Description | |-------|--------|-------------| | YYYY | 2026 | 4-digit year | | YY | 26 | 2-digit year | | MMMM | January | Full month name | | MMM | Jan | Short month name | | MM | 01 | 2-digit month | | M | 1 | Month number | | DD | 21 | 2-digit day | | D | 21 | Day number | | Do | 21st | Day with ordinal | | dddd | Wednesday | Full weekday | | ddd | Wed | Short weekday | | HH | 09 | 24-hour (2-digit) | | H | 9 | 24-hour | | hh | 09 | 12-hour (2-digit) | | h | 9 | 12-hour | | mm | 05 | Minutes (2-digit) | | ss | 30 | Seconds (2-digit) | | A | AM/PM | Uppercase | | a | am/pm | Lowercase | | Z | +03:00 | UTC offset | | ZZ | +0300 | UTC offset (no colon) |

Relative Time

nano('2026-01-20').fromNow();     // "1 day ago"
nano('2026-01-28').fromNow();     // "in 7 days"
nano('2026-01-21T11:00').fromNow(); // "1 hour ago"

// Works in ANY language without extra bundles!
nano('2026-01-20', 'tr').fromNow(); // "1 gün önce"
nano('2026-01-20', 'de').fromNow(); // "vor 1 Tag"
nano('2026-01-20', 'ja').fromNow(); // "1日前"
nano('2026-01-20', 'ar').fromNow(); // "منذ يوم واحد"
nano('2026-01-20', 'ko').fromNow(); // "1일 전"
nano('2026-01-20', 'ru').fromNow(); // "1 день назад"

Manipulation (Immutable)

// All operations return NEW instances - no mutation bugs!
const today = nano();
const nextWeek = today.add(7, 'days');
const lastMonth = today.subtract(1, 'month');

console.log(today.date());     // 21 (unchanged!)
console.log(nextWeek.date());  // 28

// Chain operations
nano()
  .add(1, 'month')
  .subtract(3, 'days')
  .startOf('week')
  .format('YYYY-MM-DD');

// Start/End of units
nano().startOf('month');   // First day of month, 00:00:00.000
nano().startOf('year');    // Jan 1st, 00:00:00.000
nano().endOf('day');       // 23:59:59.999
nano().endOf('month');     // Last day of month, 23:59:59.999

Comparison

const date1 = nano('2026-01-21');
const date2 = nano('2026-01-28');

date1.isBefore(date2);           // true
date1.isAfter(date2);            // false
date1.isSame(date2, 'month');    // true (same month)
date1.diff(date2, 'days');       // -7
date1.isValid();                 // true

Timezone (Zero-Cost)

// Format in any timezone WITHOUT extra timezone bundles!
nano().tz('America/New_York');    // NYC time
nano().tz('Asia/Tokyo');          // Tokyo time
nano().tz('Europe/London', 'full'); // Full format in London

// Get current timezone
import { getTimezone } from '@qantesm/nanodate';
getTimezone();  // "Europe/Istanbul"

// Get UTC offset
nano().utcOffset();  // 180 (for UTC+3)

🌐 Runtime Support

NanoDate uses the native Intl API which is available in all modern environments.

✅ Fully Supported

| Environment | Version | Intl Support | |-------------|---------|--------------| | Chrome | 71+ | Full | | Firefox | 65+ | Full | | Safari | 14+ | Full | | Edge | 79+ | Full | | Node.js | 18+ | Full (built-in ICU) | | Deno | All | Full | | Bun | All | Full |

⚠️ Edge Cases

Some minimal environments may have limited Intl support:

# Check if full ICU is available
node -e "console.log(new Intl.DateTimeFormat('tr').format(new Date()))"

If you see English instead of Turkish, install full ICU:

# For Node.js < 18
npm install full-icu
node --icu-data-dir=./node_modules/full-icu your-script.js

# For Alpine Docker
apk add icu-data-full

Recommendation: Use Node.js 18+ which includes full ICU by default.

import { checkIntlSupport } from '@qantesm/nanodate';

if (!checkIntlSupport()) {
  console.warn('Limited locale support detected');
}

🔬 Philosophy

"Zero-Locale-Payload"

Traditional date libraries ship megabytes of locale data because they don't trust the browser. In 2026, every modern browser ships with full Intl support including:

  • Intl.DateTimeFormat - 400+ locales for date/time formatting
  • Intl.RelativeTimeFormat - "3 days ago" in any language
  • Built-in timezone database (IANA)

NanoDate trusts the platform. We use what's already there.

Immutable by Design

Every operation returns a new instance. No more bugs from accidentally mutating dates:

// ❌ Moment.js (mutable - dangerous!)
const date = moment();
const tomorrow = date.add(1, 'day');  // date is ALSO modified!
console.log(date.date());  // 22 - unexpected!

// ✅ NanoDate (immutable - safe!)
const date = nano();
const tomorrow = date.add(1, 'day');  // date is UNCHANGED
console.log(date.date());  // 21 - expected!

Tree-Shakable

Only import what you need:

// Only format? ~500 bytes
import { nano } from '@qantesm/nanodate/lite';
nano().format('YYYY-MM-DD');

// Full library with relative time, timezone, etc.? ~2.5KB
import { nano } from '@qantesm/nanodate';

� Real-World Examples

📅 Calendar Application

import { nano } from '@qantesm/nanodate';

// Get all days in current month
const today = nano();
const firstDay = today.startOf('month');
const lastDay = today.endOf('month');

console.log(`Month: ${today.format('MMMM YYYY')}`);
console.log(`Days: ${firstDay.date()} - ${lastDay.date()}`);

// Generate week headers in user's locale
const weekDays = [];
for (let i = 0; i < 7; i++) {
  weekDays.push(nano().startOf('week').add(i, 'days').format('ddd'));
}
console.log(weekDays); // ["Sun", "Mon", "Tue", ...] or localized

🛒 E-Commerce: Order Tracking

import { nano } from '@qantesm/nanodate';

const order = {
  createdAt: '2026-01-18T10:30:00Z',
  estimatedDelivery: '2026-01-25T18:00:00Z'
};

// Show relative time for order status
const created = nano(order.createdAt, 'tr');
const delivery = nano(order.estimatedDelivery, 'tr');

console.log(`Sipariş verildi: ${created.fromNow()}`);
// "Sipariş verildi: 3 gün önce"

console.log(`Tahmini teslimat: ${delivery.fromNow()}`);
// "Tahmini teslimat: 4 gün içinde"

// Format for display
console.log(`Teslimat: ${delivery.format('DD MMMM dddd')}`);
// "Teslimat: 25 Ocak Pazar"

💬 Chat Application: Message Timestamps

import { nano } from '@qantesm/nanodate';

function formatMessageTime(timestamp, userLocale) {
  const msg = nano(timestamp, userLocale);
  const now = nano();
  
  // Today: show time only
  if (msg.isSame(now, 'day')) {
    return msg.format('HH:mm');
  }
  
  // This week: show day name
  if (msg.isSame(now, 'week')) {
    return msg.format('dddd HH:mm');
  }
  
  // Older: show full date
  return msg.format('DD MMM YYYY');
}

// User in Turkey
formatMessageTime('2026-01-21T08:30:00', 'tr'); // "08:30"
formatMessageTime('2026-01-19T14:00:00', 'tr'); // "Pazar 14:00"
formatMessageTime('2026-01-10T10:00:00', 'tr'); // "10 Oca 2026"

📊 Dashboard: Analytics Date Ranges

import { nano } from '@qantesm/nanodate';

function getDateRange(period) {
  const now = nano();
  
  switch (period) {
    case 'today':
      return {
        start: now.startOf('day'),
        end: now.endOf('day')
      };
    case 'this-week':
      return {
        start: now.startOf('week'),
        end: now.endOf('week')
      };
    case 'this-month':
      return {
        start: now.startOf('month'),
        end: now.endOf('month')
      };
    case 'last-30-days':
      return {
        start: now.subtract(30, 'days').startOf('day'),
        end: now.endOf('day')
      };
    case 'this-year':
      return {
        start: now.startOf('year'),
        end: now.endOf('year')
      };
  }
}

const range = getDateRange('last-30-days');
console.log(`${range.start.format('YYYY-MM-DD')} to ${range.end.format('YYYY-MM-DD')}`);
// "2025-12-22 to 2026-01-21"

🌍 Multi-Timezone Meeting Scheduler

import { nano } from '@qantesm/nanodate';

function showMeetingTimes(meetingTimeUTC) {
  const meeting = nano(meetingTimeUTC);
  
  const timezones = [
    { name: 'New York', tz: 'America/New_York' },
    { name: 'London', tz: 'Europe/London' },
    { name: 'Istanbul', tz: 'Europe/Istanbul' },
    { name: 'Tokyo', tz: 'Asia/Tokyo' }
  ];
  
  console.log('📅 Meeting scheduled:');
  timezones.forEach(({ name, tz }) => {
    console.log(`  ${name}: ${meeting.tz(tz)}`);
  });
}

showMeetingTimes('2026-01-25T15:00:00Z');
// 📅 Meeting scheduled:
//   New York: Jan 25, 2026, 10:00 AM
//   London: Jan 25, 2026, 3:00 PM
//   Istanbul: Jan 25, 2026, 6:00 PM
//   Tokyo: Jan 26, 2026, 12:00 AM

🎂 Birthday/Age Calculator

import { nano } from '@qantesm/nanodate';

function getAge(birthdate) {
  const birth = nano(birthdate);
  const today = nano();
  return today.diff(birth, 'years');
}

function getNextBirthday(birthdate, locale) {
  const birth = nano(birthdate);
  const today = nano();
  
  let nextBday = nano()
    .startOf('year')
    .add(birth.month(), 'months')
    .add(birth.date() - 1, 'days');
  
  // If birthday passed this year, use next year
  if (nextBday.isBefore(today)) {
    nextBday = nextBday.add(1, 'year');
  }
  
  return {
    date: nextBday.format('DD MMMM', locale),
    daysUntil: nextBday.diff(today, 'days')
  };
}

console.log(getAge('1990-05-15')); // 35
console.log(getNextBirthday('1990-05-15', 'tr')); 
// { date: "15 Mayıs", daysUntil: 114 }

⏰ Countdown Timer

import { nano } from '@qantesm/nanodate';

function countdown(targetDate, locale) {
  const target = nano(targetDate);
  const now = nano();
  
  if (target.isBefore(now)) {
    return 'Event has passed';
  }
  
  const days = target.diff(now, 'days');
  const hours = target.diff(now, 'hours') % 24;
  const minutes = target.diff(now, 'minutes') % 60;
  
  return {
    days,
    hours,
    minutes,
    formatted: target.format('full', locale),
    relative: target.fromNow()
  };
}

countdown('2026-12-31T23:59:59', 'tr');
// {
//   days: 344,
//   hours: 10,
//   minutes: 23,
//   formatted: "31 Aralık 2026 Perşembe",
//   relative: "11 ay içinde"
// }

�🚀 Perfect for Edge

NanoDate is optimized for serverless edge environments where size matters:

| Platform | Status | Notes | |----------|--------|-------| | Cloudflare Workers | ✅ Perfect | < 1KB is ideal for 1MB limit | | Vercel Edge Functions | ✅ Perfect | Minimal cold start | | Deno Deploy | ✅ Native | Full Intl support | | AWS Lambda@Edge | ✅ Recommended | Fast initialization | | Fastly Compute | ✅ Great | WASM-compatible |


📄 License

MIT © Muhammet Ali Büyük