@lbd-sh/date-tz 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +137 -88
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,147 +1,196 @@
1
- # DateTz Class Documentation
1
+ # Date TZ
2
2
 
3
- ## Overview
3
+ Powerful timezone-aware date utilities for JavaScript and TypeScript. `DateTz` keeps timestamps in sync with IANA timezones, handles daylight-saving changes transparently, and exposes a tiny, dependency-free API that stays close to the platform `Date` object while remaining predictable.
4
4
 
5
- The `DateTz` class represents a date and time in a specific timezone. It provides utilities for formatting, parsing, comparing, and manipulating date and time values with full timezone support.
5
+ ## Features
6
6
 
7
- ---
7
+ - Full TypeScript support with `DateTz`, `IDateTz`, and the bundled `timezones` catalog.
8
+ - Minute-precision timestamps normalised to UTC while exposing friendly getters (`year`, `month`, `day`, ...).
9
+ - Formatting and parsing with familiar tokens (`YYYY`, `MM`, `DD`, `HH`, `hh`, `aa`, `tz`, and more).
10
+ - Arithmetic helpers (`add`, `set`) that respect leap years, month lengths, and DST.
11
+ - Instant timezone conversion with `convertToTimezone` and `cloneToTimezone`, backed by automatic DST detection (`Intl.DateTimeFormat`).
12
+ - Works in Node.js and modern browsers without polyfills.
8
13
 
9
- ## Constructor
14
+ ## Installation
10
15
 
11
- ```ts
12
- new DateTz(value: IDateTz)
13
- new DateTz(value: number, tz?: string)
16
+ ```bash
17
+ npm install @lbd-sh/date-tz
18
+ # or
19
+ yarn add @lbd-sh/date-tz
14
20
  ```
15
21
 
16
- - Accepts either an `IDateTz` object or a Unix timestamp with an optional timezone.
17
- - Throws an error if the provided timezone is invalid.
22
+ ## Quick Start
18
23
 
19
- ---
24
+ ```ts
25
+ import { DateTz } from '@lbd-sh/date-tz';
20
26
 
21
- ## Properties
27
+ // Create a Rome-based date for 2025-03-01 09:15
28
+ const meeting = new DateTz(Date.UTC(2025, 2, 1, 8, 15), 'Europe/Rome');
22
29
 
23
- ### Instance Properties
30
+ meeting.toString(); // "2025-03-01 09:15:00"
31
+ meeting.toString('DD MMM YYYY HH:mm'); // "01 Mar 2025 09:15"
24
32
 
25
- - `timestamp: number` Milliseconds since Unix epoch (UTC).
26
- - `timezone: string` — The timezone identifier (e.g., `"UTC"`, `"Europe/Rome"`).
33
+ // Move the meeting forward and switch to New York time
34
+ meeting.add(1, 'day').add(2, 'hour');
35
+ const nyc = meeting.cloneToTimezone('America/New_York');
27
36
 
28
- ### Static Properties
37
+ nyc.toString('YYYY-MM-DD HH:mm tz'); // "2025-03-02 05:15 America/New_York"
38
+ nyc.isDst; // true or false depending on the date
39
+ ```
29
40
 
30
- - `DateTz.defaultFormat: string` — Default string format pattern: `'YYYY-MM-DD HH:mm:ss'`.
41
+ ## Usage
31
42
 
32
- ---
43
+ ### Creating Dates
33
44
 
34
- ## Getters
45
+ ```ts
46
+ import { DateTz, IDateTz } from '@lbd-sh/date-tz';
35
47
 
36
- - `timezoneOffset: number` — Returns the timezone offset in minutes.
37
- - `year: number` — Returns the full year.
38
- - `month: number` Returns the month (0–11).
39
- - `day: number` — Returns the day of the month (1–31).
40
- - `hour: number` — Returns the hour (0–23).
41
- - `minute: number` — Returns the minute (0–59).
42
- - `dayOfWeek: number` — Returns the day of the week (0–6).
48
+ new DateTz(Date.now(), 'UTC');
49
+ new DateTz(1719753300000, 'Europe/Rome');
50
+ new DateTz({ timestamp: Date.now(), timezone: 'Asia/Tokyo' } satisfies IDateTz);
43
51
 
44
- ---
52
+ DateTz.now('America/Los_Angeles');
53
+ ```
45
54
 
46
- ## Methods
55
+ Notes:
47
56
 
48
- ### `compare(other: IDateTz): number`
57
+ - Timestamps are stored in milliseconds since the Unix epoch and are truncated to the nearest minute (`seconds` and `milliseconds` are dropped) for deterministic arithmetic.
58
+ - Timezone identifiers must exist in the bundled `timezones` map; an error is thrown otherwise.
49
59
 
50
- Compares this instance with another `DateTz`. Throws if timezones differ.
60
+ ### Formatting
51
61
 
52
- ### `isComparable(other: IDateTz): boolean`
62
+ `DateTz.toString` accepts an optional pattern and locale. Unspecified tokens fall back to the default `DateTz.defaultFormat` (`YYYY-MM-DD HH:mm:ss`).
53
63
 
54
- Returns `true` if the two instances share the same timezone.
64
+ ```ts
65
+ const invoice = new DateTz(Date.UTC(2025, 5, 12, 12, 0), 'Europe/Paris');
55
66
 
56
- ### `toString(pattern?: string): string`
67
+ invoice.toString(); // "2025-06-12 14:00:00"
68
+ invoice.toString('DD/MM/YYYY HH:mm tz'); // "12/06/2025 14:00 Europe/Paris"
69
+ invoice.toString('LM DD, YYYY hh:mm aa', 'it'); // "Giugno 12, 2025 02:00 pm"
70
+ ```
57
71
 
58
- Returns the string representation using the provided format.
72
+ Available tokens:
59
73
 
60
- #### Format Tokens
74
+ | Token | Meaning | Example |
75
+ | ----- | ------- | ------- |
76
+ | `YYYY`, `yyyy` | Full year | `2025` |
77
+ | `YY`, `yy` | Year, two digits | `25` |
78
+ | `MM` | Month (01–12) | `06` |
79
+ | `LM` | Locale month name (capitalised) | `Giugno` |
80
+ | `DD` | Day of month (01–31) | `12` |
81
+ | `HH` | Hours (00–23) | `14` |
82
+ | `hh` | Hours (01–12) | `02` |
83
+ | `mm` | Minutes (00–59) | `00` |
84
+ | `ss` | Seconds (00–59) | `00` |
85
+ | `aa` | `am`/`pm` marker | `pm` |
86
+ | `AA` | `AM`/`PM` marker | `PM` |
87
+ | `tz` | Timezone identifier | `Europe/Paris` |
61
88
 
62
- | Token | Meaning |
63
- | ---------- | --------------- |
64
- | YYYY, yyyy | Full year |
65
- | YY, yy | Last 2 digits |
66
- | MM | Month (01–12) |
67
- | DD | Day (01–31) |
68
- | HH | Hour (00–23) |
69
- | hh | Hour (01–12) |
70
- | mm | Minute (00–59) |
71
- | ss | Second (00–59) |
72
- | aa, AA | AM/PM marker |
73
- | tz | Timezone string |
89
+ ### Parsing strings
74
90
 
75
- ### `add(value: number, unit: 'minute' | 'hour' | 'day' | 'month' | 'year'): this`
91
+ `DateTz.parse` mirrors `toString`: pass the source string, its pattern, and an optional timezone (default `UTC`).
76
92
 
77
- Adds the given time to the instance.
93
+ ```ts
94
+ import { DateTz } from '@lbd-sh/date-tz';
78
95
 
79
- ### `set(value: number, unit: 'year' | 'month' | 'day' | 'hour' | 'minute'): this`
96
+ const parsed = DateTz.parse(
97
+ '2025-06-12 02:00 PM',
98
+ 'YYYY-MM-DD hh:mm AA',
99
+ 'America/New_York'
100
+ );
80
101
 
81
- Sets a specific part of the date/time.
102
+ parsed.timestamp; // Milliseconds in UTC (minute precision)
103
+ parsed.timezone; // "America/New_York"
104
+ parsed.isDst; // true/false depending on the moment
105
+ ```
82
106
 
83
- ### `convertToTimezone(tz: string): this`
107
+ > 12-hour patterns require both `hh` and the `AA`/`aa` markers when parsing. If you only need 24-hour formats, prefer `HH`.
84
108
 
85
- Changes the timezone of the instance in place.
109
+ ### Arithmetic
86
110
 
87
- ### `cloneToTimezone(tz: string): DateTz`
111
+ Mutating helpers operate in-place and normalise overflows:
88
112
 
89
- Returns a new instance in the specified timezone.
113
+ ```ts
114
+ const endOfQuarter = new DateTz(Date.UTC(2025, 2, 31, 23, 0), 'UTC');
90
115
 
91
- ---
116
+ endOfQuarter.add(1, 'day'); // 2025-04-01 23:00
117
+ endOfQuarter.set(6, 'month'); // 2025-06-01 23:00
118
+ endOfQuarter.set(2026, 'year'); // 2026-06-01 23:00
119
+ ```
92
120
 
93
- ## Static Methods
121
+ All arithmetic respects leap years, month lengths, and daylight-saving changes via the offset cache.
94
122
 
95
- ### `DateTz.parse(dateString: string, pattern?: string, tz?: string): DateTz`
123
+ ### Comparing
96
124
 
97
- Parses a string to a `DateTz` instance.
125
+ ```ts
126
+ const rome = DateTz.now('Europe/Rome');
127
+ const madrid = DateTz.now('Europe/Madrid');
98
128
 
99
- ### `DateTz.now(tz?: string): DateTz`
129
+ rome.isComparable(madrid); // false (different timezones)
100
130
 
101
- Returns the current date/time as a `DateTz` instance.
131
+ const laterInRome = new DateTz(rome.timestamp + 60_000, 'Europe/Rome');
132
+ rome.compare(laterInRome); // negative number
133
+ ```
102
134
 
103
- ---
135
+ `compare` throws when timezones differ to avoid accidental cross-timezone comparisons. Use `isComparable` first, or convert one date.
104
136
 
105
- ## Utility Methods (Private)
137
+ ### Timezone conversion
106
138
 
107
- - `stripSMs(timestamp: number): number` — Removes seconds and milliseconds.
108
- - `isLeapYear(year: number): boolean` Determines if the year is a leap year.
109
- - `daysInYear(year: number): number` — Returns days in a year.
139
+ ```ts
140
+ const departure = new DateTz(Date.UTC(2025, 4, 15, 6, 45), 'Europe/Rome');
110
141
 
111
- ---
142
+ departure.isDst; // true/false depending on the date
112
143
 
113
- ## Example
144
+ // Modify in place
145
+ departure.convertToTimezone('America/New_York');
114
146
 
115
- ```ts
116
- const dt = new DateTz(1719146400000, 'Europe/Rome');
117
- console.log(dt.toString());
147
+ // Clone to keep the original instance
148
+ const arrival = departure.cloneToTimezone('Asia/Tokyo');
149
+ ```
118
150
 
119
- dt.add(1, 'day');
120
- console.log(dt.day);
151
+ Timezone changes refresh the internal offset cache and leverage `Intl.DateTimeFormat` when available to detect real-world DST shifts.
121
152
 
122
- const parsed = DateTz.parse("2025-06-23 14:00:00", "YYYY-MM-DD HH:mm:ss", "Europe/Rome");
123
- console.log(parsed.toString());
153
+ ### Accessing components
154
+
155
+ ```ts
156
+ const dt = DateTz.now('UTC');
157
+
158
+ dt.year; // e.g. 2025
159
+ dt.month; // 0-based (0 = January)
160
+ dt.day; // 1-31
161
+ dt.hour; // 0-23
162
+ dt.minute; // 0-59
163
+ dt.dayOfWeek; // 0 (Sunday) to 6 (Saturday)
164
+ dt.timezone; // Timezone id provided at creation
165
+ dt.timezoneOffset; // { sdt, dst } seconds from UTC
124
166
  ```
125
167
 
126
- ---
168
+ ## Type Definitions
169
+
170
+ The package ships with comprehensive typings:
127
171
 
128
- ## Error Handling
172
+ - `DateTz` implements `IDateTz`.
173
+ - `IDateTz` describes objects that can seed the constructor.
174
+ - `timezones` is a `Record<string, { sdt: number; dst: number }>` that exposes offsets in seconds.
129
175
 
130
- - Throws on invalid timezone.
131
- - Throws if trying to compare across timezones.
132
- - Throws if parsing a 12-hour format without AM/PM marker.
176
+ Import what you need:
133
177
 
134
- ---
178
+ ```ts
179
+ import { DateTz, IDateTz, timezones } from '@lbd-sh/date-tz';
180
+ ```
135
181
 
136
- ## Requirements
182
+ ## Timezone catalogue
137
183
 
138
- Requires:
139
- - `timezones` object mapping timezone identifiers to UTC offsets.
140
- - `daysPerMonth`, `MS_PER_DAY`, `MS_PER_HOUR`, `MS_PER_MINUTE`, `epochYear` constants.
184
+ - Contains 500+ IANA identifiers with both standard (`sdt`) and daylight (`dst`) offsets in seconds.
185
+ - When `dst === sdt`, the zone does not observe daylight saving time.
186
+ - You can inspect or extend the map in `timezones.ts` before bundling into your application.
141
187
 
142
- ---
188
+ ## Publishing & Packaging
143
189
 
144
- ## Summary
190
+ - Build with `npm run build` (TypeScript emits to `dist/` with declarations and source maps).
191
+ - `package.json` maps `main` and `types` to the compiled output, so consumers do not need TypeScript.
192
+ - The GitHub Action (`.github/workflows/production.yaml`) compiles, versions, and publishes to npm as `@lbd-sh/date-tz`.
145
193
 
146
- `DateTz` is ideal for handling precise and consistent date/time values across multiple timezones with customizable formatting, parsing, and manipulation options.
194
+ ## License
147
195
 
196
+ ISC © lbd-sh
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@lbd-sh/date-tz",
3
3
  "displayName": "Date TZ",
4
4
  "engineStrict": false,
5
- "version": "1.0.1",
5
+ "version": "1.0.2",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "scripts": {