npm package: @planktonsoup/is-today-saturday
Description: Check if a given ISO date string is a Saturday in its time zone (ESM, browser & Node.js compatible)
Author: Plankton Soup Software
Latest version: 2.0.1

# @planktonsoup/is-today-saturday

> **Timezone-aware day-of-week checker for ISO 8601 date strings**

A lightweight, zero-dependency JavaScript utility to check if an ISO 8601 date string represents a Saturday (or get any day of the week) **in the timezone specified by the ISO string**. Works in Node.js and browsers.

[![npm version](https://img.shields.io/npm/v/@planktonsoup/is-today-saturday.svg)](https://www.npmjs.com/package/@planktonsoup/is-today-saturday)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

## Why This Package?

JavaScript's `Date.getDay()` uses your **system's local timezone**, not the timezone in the ISO string. This causes bugs when checking days across timezones:

```js
const date = new Date('2025-10-25T00:00:00Z'); // Midnight Saturday UTC
date.getDay(); // Returns 5 (Friday) in MDT because it's still Friday locally! ❌
```

This package **correctly handles timezones** by parsing the offset from the ISO string and checking the day in that specific timezone:

```js
import { isSaturday } from '@planktonsoup/is-today-saturday';
isSaturday('2025-10-25T00:00:00Z'); // true ✅ - checks in UTC, not your local time
```

## Features

✅ **Timezone-aware** - Checks day in the timezone specified by the ISO string, not your system time  
✅ **Zero dependencies** - Tiny footprint (~100 lines), no external runtime dependencies  
✅ **ESM-only** - Modern ES modules for Node.js and browsers  
✅ **Pure functions** - No side effects, deterministic results  
✅ **Type-safe errors** - Clear error messages for invalid input  
✅ **Cross-platform** - Works on Windows, macOS, Linux, and browsers

## Quick Start

## Quick Start

### Installation

```sh
npm install @planktonsoup/is-today-saturday
```

### Basic Usage

```js
import { isSaturday, getDayOfWeek } from '@planktonsoup/is-today-saturday';

// Check if it's Saturday
isSaturday('2025-10-25T12:00:00Z');        // true
isSaturday('2025-10-26T12:00:00Z');        // false (Sunday)

// Get day of week (0=Sunday, 6=Saturday)
getDayOfWeek('2025-10-25T12:00:00Z');      // 6 (Saturday)
getDayOfWeek('2025-10-26T12:00:00Z');      // 0 (Sunday)
```

### Important: Timezone Required

ISO strings **must include a timezone**. This ensures consistent results regardless of where your code runs:

```js
// ❌ Error - timezone missing
isSaturday('2025-10-25T12:00:00'); // Throws: ISO string must include timezone

// ✅ Valid - timezone specified
isSaturday('2025-10-25T12:00:00Z');        // UTC
isSaturday('2025-10-25T12:00:00-06:00');   // Mountain Time (UTC-6)
isSaturday('2025-10-25T12:00:00+09:00');   // Japan (UTC+9)
```

## Usage Examples

### Node.js (ESM)

```js
import { isSaturday, getDayOfWeek } from '@planktonsoup/is-today-saturday';

// Check if it's Saturday in different timezones
console.log(isSaturday('2025-10-25T12:00:00Z'));        // true (Saturday UTC)
console.log(isSaturday('2025-10-25T12:00:00-06:00'));   // true (Saturday Mountain Time)
console.log(isSaturday('2025-10-26T12:00:00Z'));        // false (Sunday)

// Get day of week (0=Sunday, 1=Monday, ..., 6=Saturday)
console.log(getDayOfWeek('2025-10-25T12:00:00Z'));      // 6 (Saturday)
console.log(getDayOfWeek('2025-10-26T12:00:00Z'));      // 0 (Sunday)
console.log(getDayOfWeek('2025-10-27T12:00:00Z'));      // 1 (Monday)

// Build custom day checks
const day = getDayOfWeek('2025-10-25T12:00:00-06:00');
if (day === 0 || day === 6) {
  console.log('Weekend!');
}

// Map day numbers to names
const dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const dayNum = getDayOfWeek('2025-10-25T12:00:00Z');
console.log(dayNames[dayNum]); // 'Saturday'
```

### Browser (ESM)

```html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>isSaturday Example</title>
</head>
<body>
  <script type="module">
    import { isSaturday, getDayOfWeek } from 'https://esm.sh/@planktonsoup/is-today-saturday';
    
    // Check if it's Saturday
    console.log(isSaturday('2025-10-25T12:00:00Z'));        // true
    console.log(isSaturday('2025-10-25T12:00:00-06:00'));   // true
    
    // Get day of week
    console.log(getDayOfWeek('2025-10-25T12:00:00Z'));      // 6
    
    // Display on page
    const day = getDayOfWeek('2025-10-25T12:00:00Z');
    document.body.innerHTML = `Day of week: ${day} (Saturday)`;
  </script>
</body>
</html>
```

**Note:** You can also use a CDN like [esm.sh](https://esm.sh/) or bundle the package with your build tool.

### Common Use Cases

#### Weekend Detection

```js
import { getDayOfWeek } from '@planktonsoup/is-today-saturday';

function isWeekend(isoString) {
  const day = getDayOfWeek(isoString);
  return day === 0 || day === 6; // Sunday or Saturday
}

console.log(isWeekend('2025-10-25T12:00:00Z')); // true (Saturday)
console.log(isWeekend('2025-10-26T12:00:00Z')); // true (Sunday)
console.log(isWeekend('2025-10-27T12:00:00Z')); // false (Monday)
```

#### Business Hours Check

```js
import { getDayOfWeek } from '@planktonsoup/is-today-saturday';

function isBusinessDay(isoString) {
  const day = getDayOfWeek(isoString);
  return day >= 1 && day <= 5; // Monday-Friday
}

console.log(isBusinessDay('2025-10-27T09:00:00Z')); // true (Monday)
console.log(isBusinessDay('2025-10-25T09:00:00Z')); // false (Saturday)
```

#### Timezone-Specific Scheduling

```js
import { isSaturday } from '@planktonsoup/is-today-saturday';

// Check if it's Saturday in Tokyo (UTC+9)
const tokyoDate = '2025-10-25T12:00:00+09:00';
if (isSaturday(tokyoDate)) {
  console.log('Weekend pricing in Tokyo!');
}

// Check if it's Saturday in New York (UTC-4 during EDT)
const nyDate = '2025-10-25T12:00:00-04:00';
if (isSaturday(nyDate)) {
  console.log('Weekend pricing in New York!');
}
```

## API

### `getDayOfWeek(isoString)`

Returns the day of the week (0-6) for the given ISO 8601 date string **in the timezone specified by the string**.

**Parameters:**
- **isoString**: `string` — ISO 8601 date string **with timezone**
  - Required formats: `Z` (UTC), `+HH:MM`, `-HH:MM`, `+HHMM`, or `-HHMM`
  - Examples: `2025-10-25T12:00:00Z`, `2025-10-25T12:00:00-06:00`

**Returns:**
- `number` — Day of week: `0`=Sunday, `1`=Monday, `2`=Tuesday, `3`=Wednesday, `4`=Thursday, `5`=Friday, `6`=Saturday

**Throws:**
- `Error('Invalid ISO date string')` — If the string is not a valid ISO 8601 date
- `Error('ISO string must include timezone (Z, +HH:MM, or -HH:MM)')` — If timezone is missing

**Examples:**

```js
import { getDayOfWeek } from '@planktonsoup/is-today-saturday';

// Get day of week for different days
getDayOfWeek('2025-10-25T12:00:00Z');        // 6 (Saturday)
getDayOfWeek('2025-10-26T12:00:00Z');        // 0 (Sunday)
getDayOfWeek('2025-10-27T12:00:00Z');        // 1 (Monday)

// Use for custom day checks
const day = getDayOfWeek('2025-10-25T12:00:00-06:00');
if (day === 0 || day === 6) {
  console.log('Weekend!');
}

// Map to day names
const dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
console.log(dayNames[getDayOfWeek('2025-10-25T12:00:00Z')]); // 'Saturday'
```

### `isSaturday(isoString)`

Returns `true` if the given ISO 8601 date string represents a Saturday **in the timezone specified by the string**.

**Parameters:**
- **isoString**: `string` — ISO 8601 date string **with timezone**
  - Required formats: `Z` (UTC), `+HH:MM`, `-HH:MM`, `+HHMM`, or `-HHMM`
  - Examples: `2025-10-25T12:00:00Z`, `2025-10-25T12:00:00-06:00`

**Returns:**
- `boolean` — `true` if Saturday (day 6), `false` otherwise

**Throws:**
- `Error('Invalid ISO date string')` — If the string is not a valid ISO 8601 date
- `Error('ISO string must include timezone (Z, +HH:MM, or -HH:MM)')` — If timezone is missing

**Examples:**

```js
import { isSaturday } from '@planktonsoup/is-today-saturday';

// All return true - Saturday in different timezones
isSaturday('2025-10-25T12:00:00Z');        // UTC
isSaturday('2025-10-25T12:00:00-06:00');   // Mountain Time (UTC-6)
isSaturday('2025-10-25T12:00:00+09:00');   // Japan (UTC+9)
isSaturday('2025-10-25T12:00:00+05:30');   // India (UTC+5:30)

// Boundary conditions
isSaturday('2025-10-25T00:00:00Z');        // true - midnight Saturday UTC
isSaturday('2025-10-25T23:59:59.999Z');    // true - end of Saturday UTC
isSaturday('2025-10-26T00:00:00Z');        // false - midnight Sunday UTC

// Different days
isSaturday('2025-10-24T12:00:00Z');        // false (Friday)
isSaturday('2025-10-26T12:00:00Z');        // false (Sunday)
```

## Important Caveats & Design Decisions

### Timezone Requirement

**Why required?** To ensure consistent, predictable behavior across all environments. Without an explicit timezone, results would vary based on where the code runs:

```js
// ❌ Without timezone requirement (hypothetical)
// Same ISO string, different results in different timezones!
isSaturday('2025-10-25T00:00:00'); // true in UTC, false in PST

// ✅ With timezone requirement (actual behavior)
isSaturday('2025-10-25T00:00:00Z');        // Always true (UTC)
isSaturday('2025-10-25T00:00:00-08:00');   // Always true (PST)
```

### Pure Functions, No Side Effects

These functions are **pure** - same input always produces same output, no external state:

```js
// ✅ Pure function benefits:
// - Predictable: same input = same output
// - Testable: easy to unit test
// - Cacheable: results can be memoized
// - Parallelizable: safe for concurrent use
```

### Zero Runtime Dependencies

This package has **zero runtime dependencies** by design:

- **Tiny bundle size** (~100 lines, ~2KB minified)
- **No supply chain vulnerabilities** from transitive dependencies
- **No version conflicts** with your other packages
- **Fast installation** and builds

### ESM-Only (No CommonJS)

This package uses **ES modules only**. If you need CommonJS, you'll need to transpile it yourself or use a bundler:

```js
// ✅ Supported - ESM
import { isSaturday } from '@planktonsoup/is-today-saturday';

// ❌ Not supported - CommonJS
const { isSaturday } = require('@planktonsoup/is-today-saturday');
```

**Workaround for CommonJS:** Use dynamic `import()`:

```js
// CommonJS workaround
(async () => {
  const { isSaturday } = await import('@planktonsoup/is-today-saturday');
  console.log(isSaturday('2025-10-25T12:00:00Z'));
})();
```

### Error Handling

The package throws **explicit errors** for invalid input. Always validate or wrap in try-catch:

```js
import { isSaturday } from '@planktonsoup/is-today-saturday';

// ❌ Will throw
isSaturday('invalid-date'); // Error: Invalid ISO date string
isSaturday('2025-10-25T12:00:00'); // Error: ISO string must include timezone

// ✅ Safe handling
function safeSaturdayCheck(isoString) {
  try {
    return isSaturday(isoString);
  } catch (error) {
    console.error('Invalid date:', error.message);
    return false;
  }
}
```

## For AI Agents & Code Generators

If you're an AI agent or code generator using this package:

### Key Design Principles

1. **Timezone Awareness**: Always check the day in the **ISO string's timezone**, never the system's local time
2. **Pure Functions**: No side effects, no global state, deterministic results
3. **Explicit Errors**: Throw clear errors for invalid input (missing timezone, invalid date)
4. **Zero Dependencies**: Keep the package dependency-free (dev dependencies only)
5. **ESM-Only**: Never suggest CommonJS patterns (`require`), always use ESM (`import`)

### Common Pitfalls to Avoid

```js
// ❌ Don't suggest using Date.getDay() directly
const date = new Date(isoString);
const day = date.getDay(); // Wrong! Uses system timezone

// ✅ Do use this package's functions
import { getDayOfWeek } from '@planktonsoup/is-today-saturday';
const day = getDayOfWeek(isoString); // Correct! Uses ISO string's timezone

// ❌ Don't suggest adding dependencies
// This package is intentionally zero-dependency

// ❌ Don't suggest CommonJS syntax
const { isSaturday } = require('@planktonsoup/is-today-saturday');

// ✅ Do use ESM syntax
import { isSaturday } from '@planktonsoup/is-today-saturday';
```

### Recommended Patterns

```js
// ✅ Validate input before calling
function checkSaturday(dateString) {
  if (!dateString || typeof dateString !== 'string') {
    throw new Error('Date string required');
  }
  
  // Ensure timezone is present
  if (!/([+-]\d{2}:?\d{2}|Z)$/.test(dateString)) {
    throw new Error('ISO string must include timezone');
  }
  
  return isSaturday(dateString);
}

// ✅ Build on top of getDayOfWeek for custom checks
function isWeekday(isoString) {
  const day = getDayOfWeek(isoString);
  return day >= 1 && day <= 5;
}

// ✅ Handle errors gracefully
function safeGetDayOfWeek(isoString, fallback = -1) {
  try {
    return getDayOfWeek(isoString);
  } catch {
    return fallback;
  }
}
```

## Migration from v1.x to v2.0

> **⚠️ Breaking Changes in v2.0.0**

### What Changed?

**v1.x had a critical bug:** It used JavaScript's `Date.getDay()` which checks the day in your **system's local timezone**, not the timezone in the ISO string. This meant:

- Same ISO string could return different results on different machines
- Results were unpredictable and environment-dependent
- Timezone information in the ISO string was ignored

**v2.0 fixes this:** Now correctly checks the day in the **timezone specified by the ISO string**, ensuring consistent results everywhere.

### How to Migrate

#### 1. Add Timezone to All ISO Strings

```js
// ❌ v1.x - worked but results were unreliable
isSaturday('2025-10-25T12:00:00');

// ✅ v2.0 - explicit timezone required
isSaturday('2025-10-25T12:00:00Z');        // UTC
isSaturday('2025-10-25T12:00:00-06:00');   // Your timezone
```

#### 2. Update Test Expectations

If you have tests that check this library's behavior, the expected values may need updating because v2.0 returns **correct** timezone-aware results:

```js
// Example: If you were testing in PST (UTC-8) timezone
// v1.x would have returned Friday for midnight UTC on Saturday
// v2.0 correctly returns Saturday

// ❌ v1.x test (wrong expected value)
expect(isSaturday('2025-10-25T00:00:00Z')).toBe(false); // Wrong!

// ✅ v2.0 test (correct expected value)
expect(isSaturday('2025-10-25T00:00:00Z')).toBe(true); // Correct!
```

#### 3. Handle New Errors

v2.0 throws an error if timezone is missing:

```js
// Add timezone or add error handling
try {
  isSaturday(dateString);
} catch (error) {
  if (error.message.includes('must include timezone')) {
    // Add timezone or handle the error
  }
}
```

## Contributing

This package is intentionally minimal and focused. Contributions are welcome for:

- **Bug fixes** - Timezone calculation errors, edge cases
- **Documentation** - Clarity improvements, additional examples
- **Tests** - Additional test cases, especially for edge cases

**Not accepting:**
- New features that add dependencies
- CommonJS support (ESM-only by design)
- Features that add significant complexity

### Development Setup

1. Clone the repository:
   ```sh
   git clone https://github.com/PlanktonSoupSoftware/is-today-saturday.git
   cd is-today-saturday/modules
   ```

2. Install dependencies:
   ```sh
   npm install
   ```

3. Create a `.env` file:
   ```sh
   NODE_OPTIONS=--experimental-vm-modules
   ```

4. Run tests:
   ```sh
   npm test
   ```

5. Run examples:
   ```sh
   npm run example
   npm run example:browser
   ```

### Testing Guidelines

- Use `npm test` (never run `jest` directly - ESM requires special setup)
- All tests must pass before submitting PR
- Add tests for new functionality or bug fixes
- Test timezone edge cases (boundary conditions, various offsets)

See [.github/copilot-instructions.md](.github/copilot-instructions.md) for detailed development guidelines.

## License

MIT