npm package: @seawingai/wingdate
Description: Recurring schedule, ISO, UTC handling with ease
Author: Rafey Husain Syed
Latest version: 1.0.1

# WingDate

[![npm version](https://badge.fury.io/js/@seawingai%2Fwingdate.svg)](https://badge.fury.io/js/@seawingai%2Fwingdate)
[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)

A powerful TypeScript/JavaScript library for handling recurring schedules, ISO dates, and UTC timezone conversions with ease. Built on top of Luxon and RRule for robust date manipulation and recurrence rules.

## Features

- 🕐 **Timezone-aware date handling** with automatic user timezone detection
- 🔄 **Recurring schedules** with RRule integration
- 📅 **ISO 8601 compliance** for reliable date parsing and formatting
- ⚡ **Lightweight and fast** with minimal dependencies
- 🎯 **TypeScript support** with full type definitions
- 🧪 **Comprehensive testing** with Jest

## Installation

```bash
npm install @seawingai/wingdate
# or
pnpm add @seawingai/wingdate
# or
yarn add @seawingai/wingdate
```

## Quick Start

```typescript
import { WingDate, Recurrence } from '@seawingai/wingdate';

// Create a date instance
const date = new WingDate('2024-01-15T10:30:00Z');

// Get current date
const now = WingDate.now();

// Convert to UTC
const utc = WingDate.toUTC('2024-01-15T10:30:00-05:00');

// Format dates
const formatted = WingDate.format('2024-01-15T10:30:00Z', 'America/New_York', 'MMM dd, yyyy');
// Output: "Jan 15, 2024"
```

## Core Usage

### Creating Dates

```typescript
import { WingDate } from '@seawingai/wingdate';

// From ISO string
const date1 = new WingDate('2024-01-15T10:30:00Z');

// From JavaScript Date
const date2 = WingDate.fromJSDate(new Date());

// Current date
const now = WingDate.now();

// With custom timezone
const date3 = new WingDate('2024-01-15T10:30:00Z', 'America/New_York');
```

### Date Comparisons

```typescript
const date = new WingDate('2024-01-15T10:30:00Z');

// Equality
date.eq('2024-01-15T10:30:00Z'); // true
date.neq('2024-01-16T10:30:00Z'); // true

// Greater/Less than
date.gt('2024-01-14T10:30:00Z'); // true
date.lt('2024-01-16T10:30:00Z'); // true
date.gte('2024-01-15T10:30:00Z'); // true
date.lte('2024-01-15T10:30:00Z'); // true
```

### Timezone Conversions

```typescript
// Convert to UTC
const utc = WingDate.toUTC('2024-01-15T10:30:00-05:00');
// Output: "2024-01-15T15:30:00.000Z"

// Convert from UTC to local timezone
const local = WingDate.toISO('2024-01-15T15:30:00Z', 'America/New_York');
// Output: "2024-01-15T10:30:00.000-05:00"

// Format with custom timezone
const formatted = WingDate.format('2024-01-15T15:30:00Z', 'America/New_York', 'yyyy-MM-dd HH:mm ZZZZ');
// Output: "2024-01-15 10:30 EST"
```

## Recurring Schedules

### Basic Recurrence

```typescript
import { Recurrence } from '@seawingai/wingdate';

// Daily recurrence
const daily = new Recurrence({
  frequency: 'daily',
  interval: 1
});

// Weekly recurrence (every Monday and Wednesday)
const weekly = new Recurrence({
  frequency: 'weekly',
  interval: 1,
  byDay: ['MO', 'WE']
});

// Monthly recurrence (every 2 months)
const monthly = new Recurrence({
  frequency: 'monthly',
  interval: 2
});
```

### Working with Recurrences

```typescript
const startDate = new WingDate('2024-01-15T10:30:00Z');

// Daily recurrence
const daily = new Recurrence({ frequency: 'daily' });

// Get all occurrences
const allDates = startDate.all(daily);

// Get occurrences within a month
const monthlyDates = startDate.within(daily, 'month');

// Get occurrences between two dates
const betweenDates = startDate.between(daily, '2024-02-15T10:30:00Z');

// Check if a date is due
const isDue = startDate.due(daily, '2024-01-16T10:30:00Z');
```

### Advanced Recurrence Examples

```typescript
// Weekly meeting (every Monday at 9 AM)
const weeklyMeeting = new Recurrence({
  frequency: 'weekly',
  interval: 1,
  byDay: ['MO']
});

// Bi-weekly event (every 2 weeks)
const biWeekly = new Recurrence({
  frequency: 'weekly',
  interval: 2
});

// Monthly event with end date
const monthlyEvent = new Recurrence({
  frequency: 'monthly',
  interval: 1,
  until: '2024-12-31T23:59:59Z'
});

// Limited occurrences (only 10 times)
const limitedEvent = new Recurrence({
  frequency: 'daily',
  interval: 1,
  count: 10
});
```

## Utility Methods

### Date Formatting

```typescript
// Custom format
const formatted = WingDate.format(
  '2024-01-15T15:30:00Z',
  'America/New_York',
  'EEEE, MMMM dd, yyyy "at" h:mm a'
);
// Output: "Monday, January 15, 2024 at 10:30 AM"

// Different timezones
const tokyo = WingDate.format('2024-01-15T15:30:00Z', 'Asia/Tokyo', 'yyyy-MM-dd HH:mm');
// Output: "2024-01-16 00:30"
```

### Time Comparisons

```typescript
const date1 = new WingDate('2024-01-15T10:30:00Z');
const date2 = new WingDate('2024-01-16T10:30:00Z');

// Check if same time (ignoring date)
date1.sameTime(date2); // true

// Check if overdue
date1.overdue('2024-01-14T10:30:00Z'); // true
```

## API Reference

### WingDate Class

#### Constructor
```typescript
new WingDate(dateISO: string, userTimeZone?: string)
```

#### Static Methods
- `WingDate.now(userTimeZone?: string): WingDate`
- `WingDate.toUTC(dateISO: string, userTimeZone?: string): string`
- `WingDate.toISO(utcISO: string, userTimeZone?: string): string`
- `WingDate.format(utcISO: string, userTimeZone?: string, format?: string): string`
- `WingDate.fromJSDate(date: Date, userTimeZone?: string): WingDate`

#### Instance Methods
- `eq(dateISO: string, userTimeZone?: string): boolean`
- `neq(dateISO: string, userTimeZone?: string): boolean`
- `gt(dateISO: string, userTimeZone?: string): boolean`
- `gte(dateISO: string, userTimeZone?: string): boolean`
- `lt(dateISO: string, userTimeZone?: string): boolean`
- `lte(dateISO: string, userTimeZone?: string): boolean`
- `all(recurrence: Recurrence): WingDate[]`
- `within(recurrence: Recurrence, unit?: DateTimeUnit, includeDates?: boolean): WingDate[]`
- `between(recurrence: Recurrence, endDate: string, includeDates?: boolean): WingDate[]`
- `due(recurrence: Recurrence, date: string | WingDate, userTimeZone?: string): boolean`

### Recurrence Class

#### Constructor
```typescript
new Recurrence(recurrence: IRecurrence)
```

#### Interface
```typescript
interface IRecurrence {
  frequency: 'daily' | 'weekly' | 'monthly' | 'yearly' | 'hourly' | 'minutely' | 'secondly';
  interval?: number;
  byDay?: string[]; // ['MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU']
  count?: number;
  until?: string;
}
```

## Examples

### Calendar Application

```typescript
import { WingDate, Recurrence } from '@seawingai/wingdate';

// Create recurring events
const teamMeeting = new Recurrence({
  frequency: 'weekly',
  interval: 1,
  byDay: ['MO', 'WE', 'FR']
});

const startDate = new WingDate('2024-01-15T09:00:00Z');

// Get all meetings for the month
const meetings = startDate.within(teamMeeting, 'month');

// Check if today has a meeting
const today = WingDate.now();
const hasMeetingToday = startDate.due(teamMeeting, today);
```

### Task Scheduler

```typescript
// Daily task
const dailyTask = new Recurrence({ frequency: 'daily' });

// Check if task is overdue
const taskDate = new WingDate('2024-01-15T17:00:00Z');
const now = WingDate.now();

if (taskDate.overdue(now)) {
  console.log('Task is overdue!');
}
```

## Contributing

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.

## License

This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.

## Support

- 📖 [Documentation](https://seawingai.com/wingdate)
- 🐛 [Report Issues](https://github.com/seawingai/wingdate/issues)
- 💬 [Discussions](https://github.com/seawingai/wingdate/discussions)

---

Made with ❤️ by [SeaWingAI](https://seawingai.com)