@bereasoftware/time-guard 1.0.1
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.
- package/LICENSE +9 -0
- package/README.en.md +1248 -0
- package/README.md +1315 -0
- package/dist/time-guard.cjs +1 -0
- package/dist/time-guard.es.js +4340 -0
- package/dist/time-guard.iife.js +1 -0
- package/dist/time-guard.umd.js +1 -0
- package/dist/types/index.d.ts +1112 -0
- package/package.json +115 -0
package/README.en.md
ADDED
|
@@ -0,0 +1,1248 @@
|
|
|
1
|
+
# TimeGuard 🕐
|
|
2
|
+
|
|
3
|
+
A modern, production-grade date/time manipulation library built with **TypeScript**, **Temporal API**, and **SOLID principles**. TimeGuard leverages modern JavaScript standards and best practices.
|
|
4
|
+
|
|
5
|
+
[](#testing)
|
|
6
|
+
[](#supported-locales)
|
|
7
|
+
[](#calendar-systems)
|
|
8
|
+
[](https://www.npmjs.com/package/@bereasoftware/time-guard)
|
|
9
|
+
[](https://www.npmjs.com/package/@bereasoftware/time-guard)
|
|
10
|
+
[](https://www.npmjs.com/package/@bereasoftware/time-guard)
|
|
11
|
+
[](https://github.com/Berea-Soft/time-guard/actions/workflows/ci.yml)
|
|
12
|
+
[](https://www.npmjs.com/package/@bereasoftware/time-guard)
|
|
13
|
+
[](https://www.typescriptlang.org/)
|
|
14
|
+
[](https://github.com/Berea-Soft/email-validator/blob/main/LICENSE)
|
|
15
|
+
[](https://github.com/Berea-Soft/time-guard/commits/main)
|
|
16
|
+
[](https://github.com/Berea-Soft/time-guard)
|
|
17
|
+
[](https://github.com/Berea-Soft/time-guard)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 🎯 Features
|
|
22
|
+
|
|
23
|
+
- ✨ **Modern JavaScript** - Built on Temporal API (TC39 standard)
|
|
24
|
+
- 🏛️ **SOLID Principles** - Clean, maintainable, extensible architecture
|
|
25
|
+
- 🌍 **40+ Locales** - Comprehensive internationalization support
|
|
26
|
+
- 📦 **TypeScript** - Full type safety with strict mode enabled
|
|
27
|
+
- 🧪 **530+ Tests** - Complete BDD/TDD test coverage
|
|
28
|
+
- 🎨 **Multiple Formats** - ISO, RFC2822, RFC3339, UTC, and custom patterns
|
|
29
|
+
- ⚡ **Tree-Shakeable** - Modular structure for optimal bundle size
|
|
30
|
+
- 📚 **Well-Documented** - Extensive guides, examples, and API reference
|
|
31
|
+
- 🔌 **Plugin System** - Extend with optional plugins (relative time, duration, advanced formatting)
|
|
32
|
+
- 📅 **Multiple Calendars** - Gregorian, Islamic, Hebrew, Chinese, Japanese, Buddhist, and more
|
|
33
|
+
- ⏱️ **Nanosecond Precision** - Full Temporal API nanosecond support
|
|
34
|
+
- 🔄 **Duration API** - `until()`, `round()` methods for advanced calculations
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 📋 Table of Contents
|
|
39
|
+
|
|
40
|
+
- [Quick Start](#quick-start)
|
|
41
|
+
- [Installation](#installation)
|
|
42
|
+
- [Core Concepts](#core-concepts)
|
|
43
|
+
- [Component Accessors](#component-accessors)
|
|
44
|
+
- [Advanced Calculations](#advanced-calculations)
|
|
45
|
+
- [Calendar Systems](#calendar-systems)
|
|
46
|
+
- [Plugins](#plugins)
|
|
47
|
+
- [Documentation](#documentation)
|
|
48
|
+
- [Supported Locales](#supported-locales)
|
|
49
|
+
- [API Overview](#api-overview)
|
|
50
|
+
- [Testing](#testing)
|
|
51
|
+
- [Architecture](#architecture)
|
|
52
|
+
- [Contributing](#contributing)
|
|
53
|
+
- [License](#license)
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 🚀 Quick Start
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { TimeGuard } from "time-guard";
|
|
61
|
+
|
|
62
|
+
// Create a date
|
|
63
|
+
const now = TimeGuard.now();
|
|
64
|
+
const date = TimeGuard.from("2024-03-13");
|
|
65
|
+
|
|
66
|
+
// Manipulate dates
|
|
67
|
+
const tomorrow = date.add(1, "day");
|
|
68
|
+
const nextMonth = date.add(1, "month");
|
|
69
|
+
|
|
70
|
+
// Format with locales
|
|
71
|
+
const spanish = date.locale("es").format("dddd, DD MMMM YYYY");
|
|
72
|
+
// Output: miércoles, 13 marzo 2024
|
|
73
|
+
|
|
74
|
+
const japanese = date.locale("ja").format("YYYY年M月D日");
|
|
75
|
+
// Output: 2024年3月13日
|
|
76
|
+
|
|
77
|
+
// Get date components
|
|
78
|
+
console.log(date.year()); // 2024
|
|
79
|
+
console.log(date.month()); // 3
|
|
80
|
+
console.log(date.day()); // 13
|
|
81
|
+
console.log(date.dayOfWeek()); // 3 (Wednesday)
|
|
82
|
+
|
|
83
|
+
// Compare dates
|
|
84
|
+
console.log(date.isBefore(tomorrow)); // true
|
|
85
|
+
console.log(date.isSame(date.clone())); // true
|
|
86
|
+
console.log(date.isAfter(new Date("2020-01-01"))); // true
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 📦 Installation
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm install time-guard
|
|
95
|
+
# or
|
|
96
|
+
yarn add time-guard
|
|
97
|
+
# or
|
|
98
|
+
pnpm add time-guard
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Requirements
|
|
102
|
+
|
|
103
|
+
- **Node.js** 16+ (Temporal API support)
|
|
104
|
+
- **TypeScript** 5.0+ (optional but recommended)
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## 🏗️ Core Concepts
|
|
109
|
+
|
|
110
|
+
### 1. Immutability
|
|
111
|
+
|
|
112
|
+
All TimeGuard instances are immutable. Every operation returns a new instance:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
const date = TimeGuard.from("2024-03-13");
|
|
116
|
+
const modified = date.add(1, "day");
|
|
117
|
+
|
|
118
|
+
console.log(date.day()); // 13 (unchanged)
|
|
119
|
+
console.log(modified.day()); // 14 (new instance)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 2. Timezone Support
|
|
123
|
+
|
|
124
|
+
Handle timezones with full Temporal API support:
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const date = TimeGuard.from("2024-03-13 10:30:00");
|
|
128
|
+
|
|
129
|
+
// Set timezone
|
|
130
|
+
const inNYC = date.timezone("America/New_York");
|
|
131
|
+
const inTokyo = date.timezone("Asia/Tokyo");
|
|
132
|
+
|
|
133
|
+
console.log(inNYC.format("YYYY-MM-DD HH:mm:ss Z"));
|
|
134
|
+
console.log(inTokyo.format("YYYY-MM-DD HH:mm:ss Z"));
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 3. Localization
|
|
138
|
+
|
|
139
|
+
Support for 40+ languages and locales:
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
const date = TimeGuard.from("2024-03-13");
|
|
143
|
+
|
|
144
|
+
date.locale("en").format("MMMM DD, YYYY"); // March 13, 2024
|
|
145
|
+
date.locale("es").format("DD MMMM YYYY"); // 13 marzo 2024
|
|
146
|
+
date.locale("fr").format("DD MMMM YYYY"); // 13 mars 2024
|
|
147
|
+
date.locale("de").format("DD. MMMM YYYY"); // 13. März 2024
|
|
148
|
+
date.locale("ja").format("YYYY年M月D日"); // 2024年3月13日
|
|
149
|
+
date.locale("zh-cn").format("YYYY年M月D日"); // 2024年3月13日
|
|
150
|
+
date.locale("ar").format("DD MMMM YYYY"); // 13 مارس 2024
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 4. Format Strategies
|
|
154
|
+
|
|
155
|
+
Multiple preset formats and custom patterns:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
const date = TimeGuard.from("2024-03-13 14:30:45");
|
|
159
|
+
|
|
160
|
+
// Presets
|
|
161
|
+
date.format("iso"); // 2024-03-13T14:30:45
|
|
162
|
+
date.format("date"); // 2024-03-13
|
|
163
|
+
date.format("time"); // 14:30:45
|
|
164
|
+
date.format("datetime"); // 2024-03-13 14:30:45
|
|
165
|
+
date.format("rfc2822"); // Wed, 13 Mar 2024 14:30:45 GMT
|
|
166
|
+
date.format("rfc3339"); // 2024-03-13T14:30:45Z
|
|
167
|
+
date.format("utc"); // 2024-03-13T14:30:45.000Z
|
|
168
|
+
|
|
169
|
+
// Custom patterns
|
|
170
|
+
date.format("YYYY-MM-DD HH:mm:ss");
|
|
171
|
+
date.format("dddd, MMMM DD, YYYY");
|
|
172
|
+
date.format("MM/DD/YYYY");
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 🎯 Component Accessors
|
|
178
|
+
|
|
179
|
+
Quick access to individual date components:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
const date = TimeGuard.from("2024-03-13 14:30:45.123");
|
|
183
|
+
|
|
184
|
+
// Individual components
|
|
185
|
+
console.log(date.year()); // 2024
|
|
186
|
+
console.log(date.month()); // 3
|
|
187
|
+
console.log(date.day()); // 13
|
|
188
|
+
console.log(date.hour()); // 14
|
|
189
|
+
console.log(date.minute()); // 30
|
|
190
|
+
console.log(date.second()); // 45
|
|
191
|
+
console.log(date.millisecond()); // 123
|
|
192
|
+
|
|
193
|
+
// Week information
|
|
194
|
+
console.log(date.dayOfWeek()); // 3 (Wed: 1=Sun, 7=Sat)
|
|
195
|
+
console.log(date.dayOfYear()); // 73
|
|
196
|
+
console.log(date.weekOfYear()); // 11
|
|
197
|
+
|
|
198
|
+
// Month/Year information
|
|
199
|
+
console.log(date.daysInMonth()); // 31
|
|
200
|
+
console.log(date.daysInYear()); // 366 (leap year)
|
|
201
|
+
console.log(date.inLeapYear()); // true
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## ⏱️ Advanced Calculations
|
|
207
|
+
|
|
208
|
+
### Duration: Calculate time between dates
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
const start = TimeGuard.from("2024-01-15");
|
|
212
|
+
const end = TimeGuard.from("2024-03-20");
|
|
213
|
+
|
|
214
|
+
const duration = start.until(end);
|
|
215
|
+
|
|
216
|
+
console.log(duration);
|
|
217
|
+
// {
|
|
218
|
+
// years: 0,
|
|
219
|
+
// months: 2,
|
|
220
|
+
// days: 5,
|
|
221
|
+
// hours: 0,
|
|
222
|
+
// minutes: 0,
|
|
223
|
+
// seconds: 0,
|
|
224
|
+
// milliseconds: 0
|
|
225
|
+
// }
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Round: Precision control
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const date = TimeGuard.from("2024-03-13 14:35:47.654");
|
|
232
|
+
|
|
233
|
+
// Round to different units
|
|
234
|
+
date.round({ smallestUnit: "second" }); // 2024-03-13 14:35:48
|
|
235
|
+
date.round({ smallestUnit: "minute" }); // 2024-03-13 14:36:00
|
|
236
|
+
date.round({ smallestUnit: "hour" }); // 2024-03-13 15:00:00
|
|
237
|
+
date.round({ smallestUnit: "day" }); // 2024-03-14 00:00:00
|
|
238
|
+
|
|
239
|
+
// Rounding modes: 'ceil', 'floor', 'trunc', 'half' (default)
|
|
240
|
+
date.round({
|
|
241
|
+
smallestUnit: "minute",
|
|
242
|
+
roundingMode: "ceil",
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## 📅 Calendar Systems
|
|
249
|
+
|
|
250
|
+
TimeGuard includes support for multiple calendar systems, extendable via the calendar manager:
|
|
251
|
+
|
|
252
|
+
### Supported Calendars
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { TimeGuard, CalendarManager } from "time-guard";
|
|
256
|
+
import {
|
|
257
|
+
IslamicCalendar,
|
|
258
|
+
HebrewCalendar,
|
|
259
|
+
ChineseCalendar,
|
|
260
|
+
JapaneseCalendar,
|
|
261
|
+
BuddhistCalendar,
|
|
262
|
+
} from "time-guard/calendars";
|
|
263
|
+
|
|
264
|
+
// Get calendar manager
|
|
265
|
+
const calendarMgr = CalendarManager.getInstance();
|
|
266
|
+
|
|
267
|
+
// List available calendars
|
|
268
|
+
console.log(calendarMgr.list());
|
|
269
|
+
// ['gregory', 'islamic', 'hebrew', 'chinese', 'japanese', 'buddhist']
|
|
270
|
+
|
|
271
|
+
// Register custom calendar
|
|
272
|
+
const islamic = new IslamicCalendar();
|
|
273
|
+
calendarMgr.register(islamic);
|
|
274
|
+
|
|
275
|
+
// Get calendar info
|
|
276
|
+
const gregorian = calendarMgr.get("gregory");
|
|
277
|
+
console.log(gregorian.getMonthName(3)); // "March"
|
|
278
|
+
console.log(gregorian.getMonthName(3, true)); // "Mar"
|
|
279
|
+
console.log(gregorian.getWeekdayName(1)); // "Sunday"
|
|
280
|
+
console.log(gregorian.isLeapYear(2024)); // true
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## 🔌 Plugins
|
|
286
|
+
|
|
287
|
+
TimeGuard includes an optional plugin system for extended functionality:
|
|
288
|
+
|
|
289
|
+
### Available Plugins
|
|
290
|
+
|
|
291
|
+
1. **Relative Time Plugin** - Human-readable time differences
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
import { TimeGuard, PluginManager } from "time-guard";
|
|
295
|
+
import relativeTimePlugin from "time-guard/plugins/relative-time";
|
|
296
|
+
|
|
297
|
+
PluginManager.use(relativeTimePlugin, TimeGuard);
|
|
298
|
+
|
|
299
|
+
TimeGuard.from("2024-01-01").fromNow(); // "2 months ago"
|
|
300
|
+
TimeGuard.from("2024-04-01").toNow(); // "in 19 days"
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
2. **Duration Plugin** - ISO 8601 duration support
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
import { Duration } from "time-guard/plugins/duration";
|
|
307
|
+
|
|
308
|
+
const duration = Duration.fromISO("P2Y3M4D");
|
|
309
|
+
duration.humanize(); // "2 years, 3 months, 4 days"
|
|
310
|
+
duration.asDays(); // 1159
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
3. **Advanced Format Plugin** - Extended format tokens
|
|
314
|
+
|
|
315
|
+
```typescript
|
|
316
|
+
import advancedFormatPlugin from "time-guard/plugins/advanced-format";
|
|
317
|
+
|
|
318
|
+
PluginManager.use(advancedFormatPlugin, TimeGuard);
|
|
319
|
+
|
|
320
|
+
date.format("Do MMMM YYYY"); // "13th March 2024"
|
|
321
|
+
date.format("Q [Q] YYYY"); // "1 Q 2024"
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
**📖 Full Details:** See [PLUGINS.md](PLUGINS.md) for complete plugin documentation.
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## 📚 Documentation
|
|
329
|
+
|
|
330
|
+
### Main Documentation Files
|
|
331
|
+
|
|
332
|
+
| Document | Purpose |
|
|
333
|
+
| ------------------------------------- | ------------------------------------------------------------------------- |
|
|
334
|
+
| [📖 ARCHITECTURE.md](ARCHITECTURE.md) | Deep dive into design patterns, SOLID principles, and system architecture |
|
|
335
|
+
| [💡 EXAMPLES.md](EXAMPLES.md) | Real-world usage examples and common scenarios |
|
|
336
|
+
| [🌍 LOCALES.md](LOCALES.md) | Complete guide to localization and supported languages |
|
|
337
|
+
| [🔌 PLUGINS.md](PLUGINS.md) | Plugin system documentation and usage guide |
|
|
338
|
+
| [📖 API Reference](#api-overview) | Quick API reference (below) |
|
|
339
|
+
|
|
340
|
+
### Quick Navigation
|
|
341
|
+
|
|
342
|
+
- **Getting Started** → Start with [Quick Start](#quick-start) above
|
|
343
|
+
- **Advanced Usage** → See [EXAMPLES.md](EXAMPLES.md)
|
|
344
|
+
- **Localization** → See [LOCALES.md](LOCALES.md)
|
|
345
|
+
- **Architecture** → See [ARCHITECTURE.md](ARCHITECTURE.md)
|
|
346
|
+
|
|
347
|
+
## 🌍 Supported Locales - Complete Guide
|
|
348
|
+
|
|
349
|
+
TimeGuard provides **40+ languages and regional variants** with full internationalization support. Locales are organized by language family for easy discovery.
|
|
350
|
+
|
|
351
|
+
### Locale Code Format
|
|
352
|
+
|
|
353
|
+
Locale codes follow the standard `[language]-[region]` pattern:
|
|
354
|
+
|
|
355
|
+
- `en` - Default form (used if region variant not specified)
|
|
356
|
+
- `en-gb` - Specific region variant (Great Britain)
|
|
357
|
+
- `es-mx` - Spanish variant for Mexico
|
|
358
|
+
- `zh-cn` - Simplified Chinese
|
|
359
|
+
|
|
360
|
+
### Available Locales by Family
|
|
361
|
+
|
|
362
|
+
#### 🇬🇧 English (4 variants)
|
|
363
|
+
|
|
364
|
+
- `en` - English (US)
|
|
365
|
+
- `en-au` - English (Australia)
|
|
366
|
+
- `en-gb` - English (Great Britain)
|
|
367
|
+
- `en-ca` - English (Canada)
|
|
368
|
+
|
|
369
|
+
### Spanish (3 variants)
|
|
370
|
+
|
|
371
|
+
- `es` - Spanish (Spain)
|
|
372
|
+
- `es-mx` - Spanish (Mexico)
|
|
373
|
+
- `es-us` - Spanish (US)
|
|
374
|
+
|
|
375
|
+
### Romance Languages (5)
|
|
376
|
+
|
|
377
|
+
- `fr` - French
|
|
378
|
+
- `it` - Italian
|
|
379
|
+
- `pt` - Portuguese (Portugal)
|
|
380
|
+
- `pt-br` - Portuguese (Brazil)
|
|
381
|
+
- `ro` - Romanian
|
|
382
|
+
|
|
383
|
+
### Slavic Languages (4)
|
|
384
|
+
|
|
385
|
+
- `ru` - Russian
|
|
386
|
+
- `pl` - Polish
|
|
387
|
+
- `cs` - Czech
|
|
388
|
+
- `sk` - Slovak
|
|
389
|
+
|
|
390
|
+
### Nordic Languages (4)
|
|
391
|
+
|
|
392
|
+
- `sv` - Swedish
|
|
393
|
+
- `nb` - Norwegian (Bokmål)
|
|
394
|
+
- `da` - Danish
|
|
395
|
+
- `fi` - Finnish
|
|
396
|
+
|
|
397
|
+
### Asian Languages (7)
|
|
398
|
+
|
|
399
|
+
- `ja` - Japanese
|
|
400
|
+
- `zh-cn` - Chinese (Simplified)
|
|
401
|
+
- `zh-tw` - Chinese (Traditional)
|
|
402
|
+
- `ko` - Korean
|
|
403
|
+
- `th` - Thai
|
|
404
|
+
- `vi` - Vietnamese
|
|
405
|
+
- `id` - Indonesian
|
|
406
|
+
|
|
407
|
+
### European Languages (7)
|
|
408
|
+
|
|
409
|
+
- `de` - German
|
|
410
|
+
- `nl` - Dutch
|
|
411
|
+
- `el` - Greek
|
|
412
|
+
- `hu` - Hungarian
|
|
413
|
+
- `eu` - Basque
|
|
414
|
+
- `ca` - Catalan
|
|
415
|
+
- `tr` - Turkish
|
|
416
|
+
|
|
417
|
+
### Middle Eastern & South Asian (3)
|
|
418
|
+
|
|
419
|
+
- `ar` - Arabic
|
|
420
|
+
- `he` - Hebrew
|
|
421
|
+
- `hi` - Hindi
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
### Locale Usage Guide
|
|
426
|
+
|
|
427
|
+
#### Setting Locales
|
|
428
|
+
|
|
429
|
+
```typescript
|
|
430
|
+
import { TimeGuard } from "time-guard";
|
|
431
|
+
|
|
432
|
+
const date = TimeGuard.from("2024-03-13 14:30:00");
|
|
433
|
+
|
|
434
|
+
// Get current locale
|
|
435
|
+
const currentLocale = date.locale(); // "en"
|
|
436
|
+
|
|
437
|
+
// Change locale (returns new instance)
|
|
438
|
+
const spanish = date.locale("es");
|
|
439
|
+
const french = date.locale("fr");
|
|
440
|
+
const japanese = date.locale("ja");
|
|
441
|
+
const arabic = date.locale("ar");
|
|
442
|
+
|
|
443
|
+
// Chain operations
|
|
444
|
+
date.locale("es").format("dddd, DD MMMM YYYY"); // miércoles, 13 marzo 2024
|
|
445
|
+
|
|
446
|
+
// Or use constructor config
|
|
447
|
+
TimeGuard.from("2024-03-13", { locale: "de" });
|
|
448
|
+
TimeGuard.now({ locale: "ja" });
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
#### Formatting in Different Locales
|
|
452
|
+
|
|
453
|
+
```typescript
|
|
454
|
+
const date = TimeGuard.from("2024-03-13");
|
|
455
|
+
|
|
456
|
+
// English variants
|
|
457
|
+
date.locale("en").format("MMMM DD, YYYY"); // March 13, 2024
|
|
458
|
+
date.locale("en-gb").format("DD MMMM YYYY"); // 13 March 2024
|
|
459
|
+
date.locale("en-au").format("DD/MM/YYYY"); // 13/03/2024
|
|
460
|
+
date.locale("en-ca").format("YYYY-MM-DD"); // 2024-03-13
|
|
461
|
+
|
|
462
|
+
// Spanish variants
|
|
463
|
+
date.locale("es").format("DD MMMM YYYY"); // 13 marzo 2024
|
|
464
|
+
date.locale("es-mx").format("DD/MM/YYYY"); // 13/03/2024
|
|
465
|
+
date.locale("es-us").format("MMMM D"); // marzo 13
|
|
466
|
+
|
|
467
|
+
// Romance languages
|
|
468
|
+
date.locale("fr").format("dddd D MMMM YYYY"); // mercredi 13 mars 2024
|
|
469
|
+
date.locale("it").format("dddd, D MMMM YYYY"); // mercoledì, 13 marzo 2024
|
|
470
|
+
date.locale("pt").format("dddd, D MMMM YYYY"); // quarta-feira, 13 de março de 2024
|
|
471
|
+
date.locale("pt-br").format("DD/MM/YYYY"); // 13/03/2024
|
|
472
|
+
date.locale("ro").format("DD MMMM YYYY"); // 13 martie 2024
|
|
473
|
+
|
|
474
|
+
// Slavic languages
|
|
475
|
+
date.locale("ru").format("DD MMMM YYYY"); // 13 марта 2024
|
|
476
|
+
date.locale("pl").format("DD MMMM YYYY"); // 13 marca 2024
|
|
477
|
+
date.locale("cs").format("DD. MMMM YYYY"); // 13. března 2024
|
|
478
|
+
date.locale("sk").format("DD. MMMM YYYY"); // 13. marca 2024
|
|
479
|
+
|
|
480
|
+
// Nordic languages
|
|
481
|
+
date.locale("sv").format("DD MMMM YYYY"); // 13 mars 2024
|
|
482
|
+
date.locale("nb").format("DD. MMMM YYYY"); // 13. mars 2024
|
|
483
|
+
date.locale("da").format("DD. MMMM YYYY"); // 13. marts 2024
|
|
484
|
+
date.locale("fi").format("DD. MMMM YYYY"); // 13. maaliskuuta 2024
|
|
485
|
+
|
|
486
|
+
// Asian languages
|
|
487
|
+
date.locale("ja").format("YYYY年M月D日"); // 2024年3月13日
|
|
488
|
+
date.locale("zh-cn").format("YYYY年M月D日"); // 2024年3月13日
|
|
489
|
+
date.locale("zh-tw").format("YYYY年M月D日"); // 2024年3月13日
|
|
490
|
+
date.locale("ko").format("YYYY년 M월 D일"); // 2024년 3월 13일
|
|
491
|
+
date.locale("th").format("DD MMMM YYYY"); // 13 มีนาคม 2567 (BE)
|
|
492
|
+
date.locale("vi").format("DD/MM/YYYY"); // 13/03/2024
|
|
493
|
+
date.locale("id").format("DD MMMM YYYY"); // 13 Maret 2024
|
|
494
|
+
|
|
495
|
+
// European languages
|
|
496
|
+
date.locale("de").format("DD. MMMM YYYY"); // 13. März 2024
|
|
497
|
+
date.locale("nl").format("DD MMMM YYYY"); // 13 maart 2024
|
|
498
|
+
date.locale("el").format("DD MMMM YYYY"); // 13 Μαρτίου 2024
|
|
499
|
+
date.locale("hu").format("YYYY. MMMM DD."); // 2024. március 13.
|
|
500
|
+
date.locale("eu").format("YYYY[ko] MMMM[ren] DD"); // 2024ko martsaren 13
|
|
501
|
+
date.locale("ca").format("DD MMMM YYYY"); // 13 de març de 2024
|
|
502
|
+
date.locale("tr").format("DD MMMM YYYY"); // 13 Mart 2024
|
|
503
|
+
|
|
504
|
+
// Middle Eastern & South Asian
|
|
505
|
+
date.locale("ar").format("DD MMMM YYYY"); // 13 مارس 2024
|
|
506
|
+
date.locale("he").format("DD.MM.YYYY"); // 13.03.2024
|
|
507
|
+
date.locale("hi").format("DD MMMM YYYY"); // 13 मार्च 2024
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
#### Day and Month Names
|
|
511
|
+
|
|
512
|
+
```typescript
|
|
513
|
+
// Get localized day names
|
|
514
|
+
date.locale("es").format("dddd"); // miércoles
|
|
515
|
+
date.locale("es").format("ddd"); // mié
|
|
516
|
+
date.locale("fr").format("dddd"); // mercredi
|
|
517
|
+
date.locale("de").format("dddd"); // Mittwoch
|
|
518
|
+
date.locale("ja").format("dddd"); // 水曜日
|
|
519
|
+
|
|
520
|
+
// Get localized month names
|
|
521
|
+
date.locale("es").format("MMMM"); // marzo
|
|
522
|
+
date.locale("es").format("MMM"); // mar
|
|
523
|
+
date.locale("fr").format("MMMM"); // mars
|
|
524
|
+
date.locale("de").format("MMMM"); // März
|
|
525
|
+
date.locale("ru").format("MMMM"); // марта
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
#### Multi-Locale Applications
|
|
529
|
+
|
|
530
|
+
```typescript
|
|
531
|
+
// Switch language at runtime (user preference)
|
|
532
|
+
let currentLocale = "en";
|
|
533
|
+
|
|
534
|
+
function formatUserDate(
|
|
535
|
+
date: TimeGuard,
|
|
536
|
+
locale: string = currentLocale,
|
|
537
|
+
): string {
|
|
538
|
+
return date.locale(locale).format("dddd, MMMM D, YYYY [at] HH:mm");
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
const date = TimeGuard.now();
|
|
542
|
+
|
|
543
|
+
// English user
|
|
544
|
+
console.log(formatUserDate(date, "en")); // Wednesday, March 13, 2024 at 14:30
|
|
545
|
+
|
|
546
|
+
// Spanish user
|
|
547
|
+
currentLocale = "es";
|
|
548
|
+
console.log(formatUserDate(date, "es")); // miércoles, 13 de marzo de 2024 a las 14:30
|
|
549
|
+
|
|
550
|
+
// French user
|
|
551
|
+
console.log(formatUserDate(date, "fr")); // mercredi, 13 mars 2024 à 14:30
|
|
552
|
+
|
|
553
|
+
// Japanese user
|
|
554
|
+
console.log(formatUserDate(date, "ja")); // 水曜日、2024年3月13日 14:30
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
#### Getting Available Locales Programmatically
|
|
558
|
+
|
|
559
|
+
```typescript
|
|
560
|
+
// Get all available locales
|
|
561
|
+
const locales = TimeGuard.getAvailableLocales();
|
|
562
|
+
// Returns: ['en', 'en-au', 'en-gb', 'en-ca', 'es', 'es-mx', 'es-us', ...]
|
|
563
|
+
|
|
564
|
+
// Filter by prefix
|
|
565
|
+
const englishLocales = locales.filter((l) => l.startsWith("en"));
|
|
566
|
+
const spanishLocales = locales.filter((l) => l.startsWith("es"));
|
|
567
|
+
const asianLocales = locales.filter((l) =>
|
|
568
|
+
["ja", "zh-cn", "zh-tw", "ko"].includes(l),
|
|
569
|
+
);
|
|
570
|
+
|
|
571
|
+
// Create locale selector UI
|
|
572
|
+
function createLocaleSelector() {
|
|
573
|
+
const locales = TimeGuard.getAvailableLocales();
|
|
574
|
+
return locales.map((locale) => ({
|
|
575
|
+
code: locale,
|
|
576
|
+
label: new Intl.DisplayNames("en", { type: "language" }).of(locale),
|
|
577
|
+
}));
|
|
578
|
+
}
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
**📖 Full Details:** See [LOCALES.md](LOCALES.md) for locale-specific usage and characteristics.
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## 🔌 Plugins - Complete Guide
|
|
586
|
+
|
|
587
|
+
TimeGuard includes a powerful plugin system for extending functionality. Plugins follow SOLID principles and are fully optional.
|
|
588
|
+
|
|
589
|
+
### Plugin Manager
|
|
590
|
+
|
|
591
|
+
```typescript
|
|
592
|
+
import { TimeGuard, PluginManager } from "time-guard";
|
|
593
|
+
|
|
594
|
+
// Use a plugin
|
|
595
|
+
PluginManager.use(myPlugin, TimeGuard);
|
|
596
|
+
|
|
597
|
+
// Check if plugin is installed
|
|
598
|
+
PluginManager.isInstalled(pluginName);
|
|
599
|
+
|
|
600
|
+
// List installed plugins
|
|
601
|
+
PluginManager.listInstalled();
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
### 1️⃣ Relative Time Plugin
|
|
605
|
+
|
|
606
|
+
Adds human-readable time differences like "2 hours ago" or "in 3 days".
|
|
607
|
+
|
|
608
|
+
```typescript
|
|
609
|
+
import { TimeGuard, PluginManager } from "time-guard";
|
|
610
|
+
import relativeTimePlugin from "time-guard/plugins/relative-time";
|
|
611
|
+
|
|
612
|
+
// Install plugin once
|
|
613
|
+
PluginManager.use(relativeTimePlugin, TimeGuard);
|
|
614
|
+
|
|
615
|
+
// Now use relative time methods
|
|
616
|
+
const date = TimeGuard.from("2024-01-15");
|
|
617
|
+
|
|
618
|
+
// Relative to now
|
|
619
|
+
date.fromNow(); // "2 months ago"
|
|
620
|
+
date.toNow(); // "in 2 months"
|
|
621
|
+
|
|
622
|
+
// Without suffix
|
|
623
|
+
date.fromNow(true); // "2 months"
|
|
624
|
+
date.toNow(true); // "2 months"
|
|
625
|
+
|
|
626
|
+
// Relative to another date
|
|
627
|
+
const other = TimeGuard.from("2024-02-15");
|
|
628
|
+
date.from(other); // "a month ago"
|
|
629
|
+
date.to(other); // "in a month"
|
|
630
|
+
|
|
631
|
+
// Humanize duration
|
|
632
|
+
date.humanize(other); // "a month"
|
|
633
|
+
date.humanize(other, true); // "a month" (exact mode)
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
**Supported Relative Time Formats:**
|
|
637
|
+
|
|
638
|
+
```
|
|
639
|
+
"a few seconds ago" // Very recent
|
|
640
|
+
"a minute ago" / "2 minutes ago"
|
|
641
|
+
"an hour ago" / "3 hours ago"
|
|
642
|
+
"a day ago" / "5 days ago"
|
|
643
|
+
"a month ago" / "2 months ago"
|
|
644
|
+
"a year ago" / "3 years ago"
|
|
645
|
+
"in a few seconds" // Future
|
|
646
|
+
"in a minute" / "in 2 minutes"
|
|
647
|
+
"in an hour" / "in 3 hours"
|
|
648
|
+
"in a day" / "in 5 days"
|
|
649
|
+
"in a month" / "in 2 months"
|
|
650
|
+
"in a year" / "in 3 years"
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
### 2️⃣ Duration Plugin
|
|
656
|
+
|
|
657
|
+
ISO 8601 duration support with advanced calculations.
|
|
658
|
+
|
|
659
|
+
```typescript
|
|
660
|
+
import { TimeGuard } from "time-guard";
|
|
661
|
+
import { Duration, durationPlugin } from "time-guard/plugins/duration";
|
|
662
|
+
import { PluginManager } from "time-guard";
|
|
663
|
+
|
|
664
|
+
// Install plugin
|
|
665
|
+
PluginManager.use(durationPlugin, TimeGuard);
|
|
666
|
+
|
|
667
|
+
// ===== Create Durations =====
|
|
668
|
+
|
|
669
|
+
// From object
|
|
670
|
+
const duration1 = new Duration({
|
|
671
|
+
years: 2,
|
|
672
|
+
months: 3,
|
|
673
|
+
days: 4,
|
|
674
|
+
hours: 12,
|
|
675
|
+
minutes: 30,
|
|
676
|
+
});
|
|
677
|
+
|
|
678
|
+
// From ISO 8601 string
|
|
679
|
+
const duration2 = Duration.fromISO("P3Y6M4DT12H30M5S");
|
|
680
|
+
// P = Period marker
|
|
681
|
+
// 3Y = 3 years
|
|
682
|
+
// 6M = 6 months
|
|
683
|
+
// 4D = 4 days
|
|
684
|
+
// T = Time marker
|
|
685
|
+
// 12H = 12 hours
|
|
686
|
+
// 30M = 30 minutes
|
|
687
|
+
// 5S = 5 seconds
|
|
688
|
+
|
|
689
|
+
// From TimeGuard dates
|
|
690
|
+
const start = TimeGuard.from("2024-01-15");
|
|
691
|
+
const end = TimeGuard.from("2024-05-20");
|
|
692
|
+
const between = Duration.between(start, end);
|
|
693
|
+
// { years: 0, months: 4, days: 5, ... }
|
|
694
|
+
|
|
695
|
+
// ===== Duration Operations =====
|
|
696
|
+
|
|
697
|
+
// Get ISO string
|
|
698
|
+
duration1.toISO(); // "P2Y3M4DT12H30M"
|
|
699
|
+
|
|
700
|
+
// Get total in different units
|
|
701
|
+
duration1.asDays(); // Total days
|
|
702
|
+
duration1.asHours(); // Total hours
|
|
703
|
+
duration1.asSeconds(); // Total seconds
|
|
704
|
+
duration1.asMilliseconds(); // Total milliseconds
|
|
705
|
+
|
|
706
|
+
// Humanize
|
|
707
|
+
duration1.humanize(); // "2 years, 3 months, 4 days, 12 hours, 30 minutes"
|
|
708
|
+
duration1.humanize("es"); // Spanish: "2 años, 3 meses..."
|
|
709
|
+
duration1.humanize("fr"); // French: "2 ans, 3 mois..."
|
|
710
|
+
|
|
711
|
+
// Get components
|
|
712
|
+
duration1.years;
|
|
713
|
+
duration1.months;
|
|
714
|
+
duration1.days;
|
|
715
|
+
duration1.hours;
|
|
716
|
+
duration1.minutes;
|
|
717
|
+
duration1.seconds;
|
|
718
|
+
duration1.milliseconds;
|
|
719
|
+
|
|
720
|
+
// Clone
|
|
721
|
+
const copy = duration1.clone();
|
|
722
|
+
|
|
723
|
+
// Arithmetic
|
|
724
|
+
duration1.add(new Duration({ days: 5 }));
|
|
725
|
+
duration1.subtract(new Duration({ hours: 2 }));
|
|
726
|
+
duration1.multiply(2); // Double the duration
|
|
727
|
+
duration1.negate(); // Reverse direction
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
**ISO 8601 Duration Examples:**
|
|
731
|
+
|
|
732
|
+
```typescript
|
|
733
|
+
Duration.fromISO("P1Y"); // 1 year
|
|
734
|
+
Duration.fromISO("P3M"); // 3 months
|
|
735
|
+
Duration.fromISO("P1W"); // 1 week (7 days)
|
|
736
|
+
Duration.fromISO("P1D"); // 1 day
|
|
737
|
+
Duration.fromISO("PT1H"); // 1 hour
|
|
738
|
+
Duration.fromISO("PT30M"); // 30 minutes
|
|
739
|
+
Duration.fromISO("PT45S"); // 45 seconds
|
|
740
|
+
Duration.fromISO("P1Y2M3DT4H5M6S"); // Complex: 1 year, 2 months, ...
|
|
741
|
+
Duration.fromISO("-P1D"); // Negative: -1 day
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
---
|
|
745
|
+
|
|
746
|
+
### 3️⃣ Advanced Format Plugin
|
|
747
|
+
|
|
748
|
+
Extended format tokens for specialized formatting needs.
|
|
749
|
+
|
|
750
|
+
```typescript
|
|
751
|
+
import { TimeGuard, PluginManager } from "time-guard";
|
|
752
|
+
import advancedFormatPlugin from "time-guard/plugins/advanced-format";
|
|
753
|
+
|
|
754
|
+
// Install plugin
|
|
755
|
+
PluginManager.use(advancedFormatPlugin, TimeGuard);
|
|
756
|
+
|
|
757
|
+
const date = TimeGuard.from("2024-03-13 14:30:00");
|
|
758
|
+
|
|
759
|
+
// Advanced tokens become available
|
|
760
|
+
date.format("Do MMMM YYYY"); // "13th March 2024"
|
|
761
|
+
date.format("Q [Q] YYYY"); // "1 Q 2024"
|
|
762
|
+
date.format("[Week] w, YYYY"); // "Week 11, 2024"
|
|
763
|
+
date.format("W [of] ww"); // "11 of 11"
|
|
764
|
+
date.format("gggg-[W]ww"); // "2024-W11" (ISO week)
|
|
765
|
+
date.format("GGGG-[W]WW"); // 2024-W11 (alternative)
|
|
766
|
+
|
|
767
|
+
// Timezone abbreviation
|
|
768
|
+
date.format("HH:mm zzz"); // "14:30 UTC"
|
|
769
|
+
|
|
770
|
+
// 24-hour (k = 1-24 instead of 0-23)
|
|
771
|
+
date.format("k:mm"); // "14:30"
|
|
772
|
+
|
|
773
|
+
// Unix timestamps
|
|
774
|
+
date.format("X"); // Unix seconds
|
|
775
|
+
date.format("x"); // Unix milliseconds
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
**Advanced Format Tokens:**
|
|
779
|
+
|
|
780
|
+
```
|
|
781
|
+
Q // Quarter (1, 2, 3, 4)
|
|
782
|
+
Do // Ordinal day (1st, 2nd, 3rd, etc.)
|
|
783
|
+
w // Week of year (no padding)
|
|
784
|
+
ww // Week of year (zero-padded)
|
|
785
|
+
W // ISO week number
|
|
786
|
+
gggg // ISO week year
|
|
787
|
+
GGGG // Alternative ISO week year
|
|
788
|
+
k / kk // 24-hour format (1-24)
|
|
789
|
+
X // Unix seconds
|
|
790
|
+
x // Unix milliseconds
|
|
791
|
+
zzz // Timezone abbreviation (UTC, EST, etc.)
|
|
792
|
+
```
|
|
793
|
+
|
|
794
|
+
---
|
|
795
|
+
|
|
796
|
+
### Plugin Architecture
|
|
797
|
+
|
|
798
|
+
All plugins implement `ITimeGuardPlugin`:
|
|
799
|
+
|
|
800
|
+
```typescript
|
|
801
|
+
interface ITimeGuardPlugin {
|
|
802
|
+
name: string;
|
|
803
|
+
version: string;
|
|
804
|
+
install(TimeGuardClass: typeof TimeGuard): void;
|
|
805
|
+
}
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
### Creating Custom Plugins
|
|
809
|
+
|
|
810
|
+
```typescript
|
|
811
|
+
import { TimeGuard } from "time-guard";
|
|
812
|
+
import type { ITimeGuardPlugin } from "time-guard/types";
|
|
813
|
+
|
|
814
|
+
class MyCustomPlugin implements ITimeGuardPlugin {
|
|
815
|
+
name = "my-plugin";
|
|
816
|
+
version = "1.0.0";
|
|
817
|
+
|
|
818
|
+
install(TimeGuardClass: typeof TimeGuard): void {
|
|
819
|
+
// Add method to TimeGuard prototype
|
|
820
|
+
(TimeGuardClass.prototype as any).myMethod = function () {
|
|
821
|
+
return "Hello from my plugin!";
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// Use it
|
|
827
|
+
const plugin = new MyCustomPlugin();
|
|
828
|
+
PluginManager.use(plugin, TimeGuard);
|
|
829
|
+
|
|
830
|
+
// Now available
|
|
831
|
+
const date = TimeGuard.now();
|
|
832
|
+
date.myMethod(); // "Hello from my plugin!"
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
**📖 Full Plugin Details:** See [PLUGINS.md](PLUGINS.md) for extended documentation.
|
|
836
|
+
|
|
837
|
+
---
|
|
838
|
+
|
|
839
|
+
## 🎯 Complete API Reference
|
|
840
|
+
|
|
841
|
+
### Factory Methods
|
|
842
|
+
|
|
843
|
+
```typescript
|
|
844
|
+
// Create current date/time
|
|
845
|
+
TimeGuard.now();
|
|
846
|
+
TimeGuard.now({ locale: "es", timezone: "America/Mexico_City" });
|
|
847
|
+
|
|
848
|
+
// Create from various inputs
|
|
849
|
+
TimeGuard.from("2024-03-13");
|
|
850
|
+
TimeGuard.from("2024-03-13T14:30:00");
|
|
851
|
+
TimeGuard.from(new Date());
|
|
852
|
+
TimeGuard.from(1234567890000); // milliseconds
|
|
853
|
+
TimeGuard.from(1234567890, { timezone: "UTC" }); // seconds
|
|
854
|
+
TimeGuard.from("2024-03-13", { locale: "es" });
|
|
855
|
+
|
|
856
|
+
// Create from Temporal object
|
|
857
|
+
TimeGuard.fromTemporal(temporalPlainDateTime, config);
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
### 🔄 Conversion Methods
|
|
861
|
+
|
|
862
|
+
```typescript
|
|
863
|
+
const date = TimeGuard.from("2024-03-13 14:30:45");
|
|
864
|
+
|
|
865
|
+
date.toDate(); // Convert to JavaScript Date
|
|
866
|
+
date.toTemporal(); // Get underlying Temporal object
|
|
867
|
+
date.toISOString(); // ISO 8601: "2024-03-13T14:30:45Z"
|
|
868
|
+
date.toJSON(); // JSON serialization (ISO string)
|
|
869
|
+
date.toString(); // Human readable: "2024-03-13 14:30:45"
|
|
870
|
+
|
|
871
|
+
date.valueOf(); // Milliseconds since epoch
|
|
872
|
+
date.unix(); // Seconds since epoch
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
### ➕ Manipulation Methods
|
|
876
|
+
|
|
877
|
+
```typescript
|
|
878
|
+
const date = TimeGuard.from("2024-03-13 14:30:00");
|
|
879
|
+
|
|
880
|
+
// Add time - accepts partial record of units
|
|
881
|
+
date.add({ days: 5 });
|
|
882
|
+
date.add({ months: 1, days: 5 });
|
|
883
|
+
date.add({ years: 1, hours: 2, minutes: 30 });
|
|
884
|
+
|
|
885
|
+
// Subtract time - same syntax as add
|
|
886
|
+
date.subtract({ days: 5 });
|
|
887
|
+
date.subtract({ months: 1 });
|
|
888
|
+
|
|
889
|
+
// Set specific component(s)
|
|
890
|
+
date.set({ day: 15 }); // Keep other components
|
|
891
|
+
date.set({ hour: 10, minute: 0 });
|
|
892
|
+
date.set({ year: 2025, month: 1, day: 1 });
|
|
893
|
+
|
|
894
|
+
// Start/End of period
|
|
895
|
+
date.startOf("year"); // 2024-01-01 00:00:00
|
|
896
|
+
date.startOf("month"); // 2024-03-01 00:00:00
|
|
897
|
+
date.startOf("day"); // 2024-03-13 00:00:00
|
|
898
|
+
date.startOf("hour"); // 2024-03-13 14:00:00
|
|
899
|
+
date.endOf("year"); // 2024-12-31 23:59:59
|
|
900
|
+
date.endOf("month"); // 2024-03-31 23:59:59
|
|
901
|
+
|
|
902
|
+
date.clone(); // Create independent copy
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
### 🔍 Component Accessors (Getters)
|
|
906
|
+
|
|
907
|
+
```typescript
|
|
908
|
+
const date = TimeGuard.from("2024-03-13 14:30:45.123");
|
|
909
|
+
|
|
910
|
+
// Date components
|
|
911
|
+
date.year(); // 2024
|
|
912
|
+
date.month(); // 3 (January = 1, December = 12)
|
|
913
|
+
date.day(); // 13
|
|
914
|
+
date.quarter(); // 1 (Q1, Q2, Q3, or Q4)
|
|
915
|
+
|
|
916
|
+
// Time components
|
|
917
|
+
date.hour(); // 14
|
|
918
|
+
date.minute(); // 30
|
|
919
|
+
date.second(); // 45
|
|
920
|
+
date.millisecond(); // 123
|
|
921
|
+
|
|
922
|
+
// Week/Day information
|
|
923
|
+
date.dayOfWeek(); // 3 (1=Sunday, 7=Saturday)
|
|
924
|
+
date.dayOfYear(); // 73
|
|
925
|
+
date.weekOfYear(); // 11
|
|
926
|
+
|
|
927
|
+
// Month/Year information
|
|
928
|
+
date.daysInMonth(); // 31
|
|
929
|
+
date.daysInYear(); // 366 (leap year)
|
|
930
|
+
date.inLeapYear(); // true
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
### ⚖️ Comparison Methods
|
|
934
|
+
|
|
935
|
+
```typescript
|
|
936
|
+
const date1 = TimeGuard.from("2024-03-13");
|
|
937
|
+
const date2 = TimeGuard.from("2024-03-20");
|
|
938
|
+
|
|
939
|
+
// Direct comparison
|
|
940
|
+
date1.isBefore(date2); // true
|
|
941
|
+
date1.isAfter(date2); // false
|
|
942
|
+
date1.isSame(date1); // true
|
|
943
|
+
|
|
944
|
+
// Unit-specific comparison
|
|
945
|
+
date1.isSame(date2, "month"); // true (same month)
|
|
946
|
+
date1.isSame(date2, "year"); // true (same year)
|
|
947
|
+
date1.isSame(date2, "day"); // false (different day)
|
|
948
|
+
|
|
949
|
+
// Range checking
|
|
950
|
+
date1.isBetween(date1, date2); // true
|
|
951
|
+
date1.isBetween(date1, date2, undefined, "[]"); // inclusive both ends
|
|
952
|
+
date1.isBetween(date1, date2, undefined, "()"); // exclusive both ends
|
|
953
|
+
date1.isBetween(date1, date2, "month", "[]"); // granular range
|
|
954
|
+
|
|
955
|
+
// Calculate difference
|
|
956
|
+
date1.diff(date2, "days"); // -7
|
|
957
|
+
date1.diff(date2, "millisecond"); // difference in ms
|
|
958
|
+
date1.diff(date2, "months"); // -0
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
### 📊 Advanced Calculations
|
|
962
|
+
|
|
963
|
+
```typescript
|
|
964
|
+
const date = TimeGuard.from("2024-01-15");
|
|
965
|
+
const future = TimeGuard.from("2024-05-20");
|
|
966
|
+
|
|
967
|
+
// Duration: Get complete breakdown
|
|
968
|
+
const duration = date.until(future);
|
|
969
|
+
// { years: 0, months: 4, days: 5, hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }
|
|
970
|
+
|
|
971
|
+
// Rounding: Precision control
|
|
972
|
+
date.round({ smallestUnit: "millisecond" }); // Default, no change
|
|
973
|
+
date.round({ smallestUnit: "second" }); // Removes milliseconds
|
|
974
|
+
date.round({ smallestUnit: "minute" }); // 2024-03-13 14:30:00
|
|
975
|
+
date.round({ smallestUnit: "hour" }); // 2024-03-13 14:00:00
|
|
976
|
+
date.round({ smallestUnit: "day" }); // 2024-03-13 00:00:00
|
|
977
|
+
|
|
978
|
+
// Rounding modes
|
|
979
|
+
date.round({
|
|
980
|
+
smallestUnit: "minute",
|
|
981
|
+
roundingMode: "halfExpand", // Default: round to nearest
|
|
982
|
+
});
|
|
983
|
+
|
|
984
|
+
date.round({
|
|
985
|
+
smallestUnit: "minute",
|
|
986
|
+
roundingMode: "ceil", // Always round up
|
|
987
|
+
});
|
|
988
|
+
```
|
|
989
|
+
|
|
990
|
+
### 🌍 Locale & Timezone
|
|
991
|
+
|
|
992
|
+
```typescript
|
|
993
|
+
const date = TimeGuard.from("2024-03-13 14:30:00");
|
|
994
|
+
|
|
995
|
+
// Get/Set locale
|
|
996
|
+
date.locale(); // Returns current locale: 'en'
|
|
997
|
+
date.locale("es"); // Set locale, returns new instance
|
|
998
|
+
|
|
999
|
+
// Format in different locales
|
|
1000
|
+
date.format("YYYY-MM-DD"); // 2024-03-13
|
|
1001
|
+
date.locale("es").format("DD MMMM YYYY"); // 13 marzo 2024
|
|
1002
|
+
date.locale("es-mx").format("DD/MM/YYYY"); // 13/03/2024
|
|
1003
|
+
date.locale("fr").format("dddd, DD MMMM YYYY"); // mercredi, 13 mars 2024
|
|
1004
|
+
date.locale("de").format("DD. MMMM YYYY"); // 13. März 2024
|
|
1005
|
+
date.locale("ja").format("YYYY年M月D日"); // 2024年3月13日
|
|
1006
|
+
date.locale("zh-cn").format("YYYY年M月D日"); // 2024年3月13日
|
|
1007
|
+
date.locale("ar").format("DD MMMM YYYY"); // 13 مارس 2024
|
|
1008
|
+
|
|
1009
|
+
// Get/Set timezone
|
|
1010
|
+
date.timezone(); // Returns current timezone: 'UTC'
|
|
1011
|
+
const inNYC = date.timezone("America/New_York");
|
|
1012
|
+
const inTokyo = date.timezone("Asia/Tokyo");
|
|
1013
|
+
const inDubai = date.timezone("Asia/Dubai");
|
|
1014
|
+
|
|
1015
|
+
// Format with timezone info
|
|
1016
|
+
inNYC.format("YYYY-MM-DD HH:mm:ss Z"); // 2024-03-13 10:30:00 -04:00
|
|
1017
|
+
inTokyo.format("YYYY-MM-DD HH:mm:ss Z"); // 2024-03-13 23:30:00 +09:00
|
|
1018
|
+
|
|
1019
|
+
// Get all available locales
|
|
1020
|
+
TimeGuard.getAvailableLocales(); // Array of 40+ locale codes
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
### 🎨 Format Patterns
|
|
1024
|
+
|
|
1025
|
+
#### Format Presets
|
|
1026
|
+
|
|
1027
|
+
```typescript
|
|
1028
|
+
const date = TimeGuard.from("2024-03-13 14:30:45.123");
|
|
1029
|
+
|
|
1030
|
+
// Built-in presets
|
|
1031
|
+
date.format("iso"); // 2024-03-13T14:30:45.123Z
|
|
1032
|
+
date.format("date"); // 2024-03-13
|
|
1033
|
+
date.format("time"); // 14:30:45
|
|
1034
|
+
date.format("datetime"); // 2024-03-13 14:30:45
|
|
1035
|
+
date.format("rfc2822"); // Wed, 13 Mar 2024 14:30:45 +0000
|
|
1036
|
+
date.format("rfc3339"); // 2024-03-13T14:30:45Z
|
|
1037
|
+
date.format("utc"); // 2024-03-13T14:30:45.123Z
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
#### Format Tokens
|
|
1041
|
+
|
|
1042
|
+
```typescript
|
|
1043
|
+
// Year
|
|
1044
|
+
'YYYY' // 2024 (4-digit)
|
|
1045
|
+
'YY' // 24 (2-digit)
|
|
1046
|
+
|
|
1047
|
+
// Month
|
|
1048
|
+
'MMMM' // March
|
|
1049
|
+
'MMM' // Mar
|
|
1050
|
+
'MM' // 03 (zero-padded)
|
|
1051
|
+
'M' // 3 (no padding)
|
|
1052
|
+
|
|
1053
|
+
// Day
|
|
1054
|
+
'DDDD' or 'DDD' // Monday (full day name)
|
|
1055
|
+
'ddd' // Mon (abbreviated)
|
|
1056
|
+
'DD' // 13 (zero-padded)
|
|
1057
|
+
'D' // 13 (no padding)
|
|
1058
|
+
|
|
1059
|
+
// Hours, minutes, seconds
|
|
1060
|
+
'HH' // 14 (24-hour, zero-padded)
|
|
1061
|
+
'H' // 14
|
|
1062
|
+
'hh' // 02 (12-hour, zero-padded)
|
|
1063
|
+
'h' // 2
|
|
1064
|
+
'mm' // 30
|
|
1065
|
+
'm' // 30
|
|
1066
|
+
'ss' // 45
|
|
1067
|
+
's' // 45
|
|
1068
|
+
'A' // AM or PM
|
|
1069
|
+
'a' // am or pm
|
|
1070
|
+
|
|
1071
|
+
// Milliseconds & Week
|
|
1072
|
+
'SSS' // 123 (milliseconds)
|
|
1073
|
+
'SS' // 12
|
|
1074
|
+
'S' // 1
|
|
1075
|
+
'ww' // 11 (week with padding)
|
|
1076
|
+
'w' // 11 (week no padding)
|
|
1077
|
+
|
|
1078
|
+
// Escaped text
|
|
1079
|
+
'[text]' // Protects text: [UTC]
|
|
1080
|
+
'"text"' // Alternative protection: "o'clock"
|
|
1081
|
+
```
|
|
1082
|
+
|
|
1083
|
+
#### Custom Format Examples
|
|
1084
|
+
|
|
1085
|
+
```typescript
|
|
1086
|
+
date.format("YYYY-MM-DD"); // 2024-03-13
|
|
1087
|
+
date.format("DD/MM/YYYY"); // 13/03/2024
|
|
1088
|
+
date.format("MMMM D, YYYY"); // March 13, 2024
|
|
1089
|
+
date.format("dddd, MMMM D, YYYY"); // Wednesday, March 13, 2024
|
|
1090
|
+
date.format("DD-MMMM-YY"); // 13-Mar-24
|
|
1091
|
+
date.format("h:mm A"); // 2:30 PM
|
|
1092
|
+
date.format("HH:mm:ss"); // 14:30:45
|
|
1093
|
+
date.format("[Today is] dddd"); // Today is Wednesday
|
|
1094
|
+
date.format("HH:mm [UTC]"); // 14:30 UTC
|
|
1095
|
+
date.format('DD/MM/YYYY "at" HH:mm'); // 13/03/2024 at 14:30
|
|
1096
|
+
```
|
|
1097
|
+
|
|
1098
|
+
**📖 Complete Format Guide:** See [EXAMPLES.md](EXAMPLES.md) for more patterns and use cases.
|
|
1099
|
+
|
|
1100
|
+
---
|
|
1101
|
+
|
|
1102
|
+
## 🧪 Testing
|
|
1103
|
+
|
|
1104
|
+
TimeGuard includes **530+ comprehensive tests** covering:
|
|
1105
|
+
|
|
1106
|
+
- ✅ Core functionality (creation, manipulation, querying)
|
|
1107
|
+
- ✅ Advanced features (timezones, locales, formatting)
|
|
1108
|
+
- ✅ Edge cases (leap years, month boundaries, DST)
|
|
1109
|
+
- ✅ SOLID principle validation
|
|
1110
|
+
- ✅ Type safety verification
|
|
1111
|
+
|
|
1112
|
+
### Run Tests
|
|
1113
|
+
|
|
1114
|
+
```bash
|
|
1115
|
+
# Run all tests
|
|
1116
|
+
npm test
|
|
1117
|
+
|
|
1118
|
+
# Run with coverage
|
|
1119
|
+
npm test -- --coverage
|
|
1120
|
+
|
|
1121
|
+
# Run specific test file
|
|
1122
|
+
npm test -- locales.test.ts
|
|
1123
|
+
|
|
1124
|
+
# Watch mode
|
|
1125
|
+
npm test -- --watch
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
### Test Coverage
|
|
1129
|
+
|
|
1130
|
+
```
|
|
1131
|
+
Core functionality: 65+ tests
|
|
1132
|
+
Advanced features: 50+ tests
|
|
1133
|
+
Locale support: 100+ tests
|
|
1134
|
+
Integration scenarios: 250+ tests
|
|
1135
|
+
Edge cases: 65+ tests
|
|
1136
|
+
```
|
|
1137
|
+
|
|
1138
|
+
---
|
|
1139
|
+
|
|
1140
|
+
## 🏛️ Architecture
|
|
1141
|
+
|
|
1142
|
+
TimeGuard is built on **SOLID principles** ensuring clean, maintainable, and extensible code:
|
|
1143
|
+
|
|
1144
|
+
### Key Principles
|
|
1145
|
+
|
|
1146
|
+
- **Single Responsibility** - Each class has one reason to change
|
|
1147
|
+
- **Open/Closed** - Open for extension, closed for modification
|
|
1148
|
+
- **Liskov Substitution** - Proper interface contracts
|
|
1149
|
+
- **Interface Segregation** - Minimal, focused interfaces
|
|
1150
|
+
- **Dependency Inversion** - Depend on abstractions, not concretions
|
|
1151
|
+
|
|
1152
|
+
### Design Patterns
|
|
1153
|
+
|
|
1154
|
+
- **Factory Pattern** - Date creation and parsing
|
|
1155
|
+
- **Adapter Pattern** - Temporal API abstraction
|
|
1156
|
+
- **Strategy Pattern** - Multiple formatting strategies
|
|
1157
|
+
- **Singleton Pattern** - Locale manager
|
|
1158
|
+
- **Facade Pattern** - Simple public API
|
|
1159
|
+
- **Immutable Pattern** - Safe data handling
|
|
1160
|
+
|
|
1161
|
+
**📖 Deep Dive:** See [ARCHITECTURE.md](ARCHITECTURE.md) for detailed architecture explanation.
|
|
1162
|
+
|
|
1163
|
+
---
|
|
1164
|
+
|
|
1165
|
+
## 🔧 Development
|
|
1166
|
+
|
|
1167
|
+
### Build
|
|
1168
|
+
|
|
1169
|
+
```bash
|
|
1170
|
+
# Build for production
|
|
1171
|
+
npm run build
|
|
1172
|
+
|
|
1173
|
+
# Watch mode for development
|
|
1174
|
+
npm run dev
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
### Project Structure
|
|
1178
|
+
|
|
1179
|
+
```
|
|
1180
|
+
time-guard/
|
|
1181
|
+
├── src/
|
|
1182
|
+
│ ├── index.ts # Public API exports
|
|
1183
|
+
│ ├── types.ts # Type definitions
|
|
1184
|
+
│ ├── time-guard.ts # Main class
|
|
1185
|
+
│ ├── adapters/
|
|
1186
|
+
│ │ └── temporal.adapter.ts # Temporal API wrapper
|
|
1187
|
+
│ ├── formatters/
|
|
1188
|
+
│ │ └── date.formatter.ts # Format strategies
|
|
1189
|
+
│ └── locales/
|
|
1190
|
+
│ ├── index.ts # Locale registry
|
|
1191
|
+
│ └── ... # 9+ locale files
|
|
1192
|
+
├── test/
|
|
1193
|
+
│ ├── time-guard.test.ts # Core tests
|
|
1194
|
+
│ ├── advanced.test.ts # Advanced tests
|
|
1195
|
+
│ └── locales.test.ts # Locale tests
|
|
1196
|
+
└── docs/
|
|
1197
|
+
├── ARCHITECTURE.md # Architecture guide
|
|
1198
|
+
├── EXAMPLES.md # Usage examples
|
|
1199
|
+
└── LOCALES.md # Locale documentation
|
|
1200
|
+
```
|
|
1201
|
+
|
|
1202
|
+
---
|
|
1203
|
+
|
|
1204
|
+
## 🤝 Contributing
|
|
1205
|
+
|
|
1206
|
+
We welcome contributions! Please:
|
|
1207
|
+
|
|
1208
|
+
1. Follow SOLID principles and existing code patterns
|
|
1209
|
+
2. Write tests for new features
|
|
1210
|
+
3. Update documentation
|
|
1211
|
+
4. Ensure all tests pass (`npm test`)
|
|
1212
|
+
5. Check types pass (`npx tsc --noEmit`)
|
|
1213
|
+
|
|
1214
|
+
---
|
|
1215
|
+
|
|
1216
|
+
## 📄 License
|
|
1217
|
+
|
|
1218
|
+
MIT License © 2024 Berea-Soft
|
|
1219
|
+
|
|
1220
|
+
See [LICENSE](LICENSE) file for details.
|
|
1221
|
+
|
|
1222
|
+
---
|
|
1223
|
+
|
|
1224
|
+
## 🔗 Quick Links
|
|
1225
|
+
|
|
1226
|
+
- 📖 [Full API Reference](EXAMPLES.md)
|
|
1227
|
+
- 🏛️ [Architecture Guide](ARCHITECTURE.md)
|
|
1228
|
+
- 🌍 [Localization Guide](LOCALES.md)
|
|
1229
|
+
- 🐛 [Issue Tracker](https://github.com/bereasoftware/time-guard/issues)
|
|
1230
|
+
- 💬 [Discussions](https://github.com/bereasoftware/time-guard/discussions)
|
|
1231
|
+
|
|
1232
|
+
---
|
|
1233
|
+
|
|
1234
|
+
## 📞 Support
|
|
1235
|
+
|
|
1236
|
+
For questions, issues, or feature requests:
|
|
1237
|
+
|
|
1238
|
+
- Open an issue on GitHub
|
|
1239
|
+
- Start a discussion
|
|
1240
|
+
- Check existing documentation
|
|
1241
|
+
|
|
1242
|
+
---
|
|
1243
|
+
|
|
1244
|
+
---
|
|
1245
|
+
|
|
1246
|
+
## Built with ❤️ by Berea-Soft
|
|
1247
|
+
|
|
1248
|
+
A modern date/time library with SOLID principles and TypeScript
|