Time
Moduł Time daje helpery do dat w strefie czasowej firmy: parsowanie, formatowanie, granice dnia i dodawanie dni kalendarzowych, bez zależności od TZ kontenera ani od przeglądarki (od SDK 4.3.0).
const { Time } = require('@orbito/api-lib');
Time.inZone(timeZone) // -> helpery dla wskazanej strefy (synchronicznie)
Time.forCompany() // -> Promise helperów dla strefy firmy
Po co to jest
Moduł działa w kontenerze, którego lokalna strefa czasowa nic nie mówi o firmie. „Dziś”, „zamówienia z 2026-10-06” czy „termin płatności za 14 dni” oznaczają dzień roboczy firmy, czyli strefę ustawioną przez jej administratora (Core.getCompany().timezone, nazwa IANA, domyślnie Europe/Warsaw). Każdy helper przyjmuje strefę jawnie, więc nic nie jest przybite do jednej strefy i nic nie czyta process.env.TZ.
Wspólna semantyka wszystkich helperów:
- znacznik z offsetem (
Z,+02:00),Datei liczba milisekund zachowują swoją chwilę. Tekst bez offsetu (2026-10-06 14:30,2026-10-06) oznacza czas w strefie, nigdy lokalny czas kontenera, - godzina, która nie istnieje w strefie (wiosenna luka przy zmianie czasu), jest nieprawidłowa (
null), a godzina występująca dwa razy (jesienne cofnięcie) daje swoje pierwsze wystąpienie, - dni są kalendarzowe: przy zmianie czasu dzień trwa 23 lub 25 godzin, więc „+1 dzień” to nigdy „+24 h”.
Time.inZone
Zwraca helpery dla wskazanej strefy. Funkcja jest synchroniczna i czysta. Zwrócony obiekt jest zamrożony i współdzielony przez wszystkich proszących o tę samą strefę, więc można go bezpiecznie przekazywać dalej. Intl.DateTimeFormat strefy powstaje raz, dlatego wielokrotne wołanie jest tanie.
const warsaw = Time.inZone('Europe/Warsaw');
warsaw.parseDate('2026-10-06 14:30'); // 2026-10-06T12:30:00.000Z
warsaw.formatDate(new Date(), 'YYYY-MM-DD'); // dzisiaj w Warszawie
| Parametr | Typ | Opis |
|---|---|---|
timeZone | string | Nazwa strefy IANA, np. Europe/Warsaw |
Pusta lub nieznana strefa rzuca RangeError (Invalid time zone specified: ...).
Zwrócony obiekt zawiera timeZone (strefa tak, jak ją podano) oraz funkcje:
| Helper | Opis |
|---|---|
parseDate(value) | Zwraca Date albo null. Przyjmuje Date, liczbę milisekund lub tekst YYYY-MM-DD, opcjonalnie z HH:mm[:ss[.fff]] lub THH:mm..., opcjonalnie z Z/±HH:mm. null dla nieprawidłowej daty i godziny z wiosennej luki |
formatDate(value, pattern) | Tekst w strefie. Tokeny: YYYY MM DD HH mm ss, reszta jest kopiowana. Domyślny wzorzec to DD.MM.YYYY HH:mm. Zwraca '', gdy value się nie parsuje |
dateBoundary(value, endOfDay) | Dla YYYY-MM-DD początek (00:00:00.000) albo koniec (23:59:59.999, gdy endOfDay to true) tego dnia w strefie. Każda inna wartość jest parsowana jak w parseDate |
addCalendarDays(value, days) | Dzień kalendarzowy value w strefie przesunięty o days dni, jako YYYY-MM-DD (bezpieczne przy zmianie czasu). Zwraca '' dla nieprawidłowego wejścia |
const ny = Time.inZone('America/New_York');
ny.parseDate('2026-10-06 09:00'); // 2026-10-06T13:00:00.000Z
ny.formatDate('2026-10-06T13:00:00Z'); // '06.10.2026 09:00'
ny.addCalendarDays('2026-10-06T13:00:00Z', 14); // '2026-10-20'
Time.forCompany
Zwraca Promise helperów dla bieżącej strefy firmy, czyli Time.inZone ze strefą z Core.getCompany(). Przy każdym wywołaniu pyta rdzeń (bez cache i bez powiadomień o zmianie), a gdy Core.getCompany() odrzuci Promise, odrzuca go również.
const time = await Time.forCompany();
Zalecany wzorzec
Pobierz strefę raz na początku handlera metody lub hooka i przekaż helpery w dół do kodu synchronicznego (budowanie zapytań, formatowanie):
const { Core, DB, Time } = require('@orbito/api-lib');
Core.registerMethod('orders.list', async (params) => {
const time = await Time.forCompany(); // raz na wywołanie, potem przekazywane w dół
return DB.find('orders', buildQuery(params, time));
});
// funkcja synchroniczna dostaje helpery zamiast czytać globalną strefę
function buildQuery({ dateFrom, dateTo }, time) {
return {
createdAt: {
$gte: time.dateBoundary(dateFrom), // 00:00:00 tego dnia w strefie firmy
$lte: time.dateBoundary(dateTo, true) // 23:59:59.999 tego dnia
}
};
}
Termin płatności liczony w dniach kalendarzowych firmy:
Core.registerMethod('payments.dueDate', async ({ issuedAt, termDays }) => {
const time = await Time.forCompany();
return { dueDate: time.addCalendarDays(issuedAt, termDays) };
});
Czego nie robić
Nie trzymaj helperów w zmiennej modułu
Administrator może zmienić strefę w każdej chwili. Wartość pobrana przy starcie kontenera po cichu się zestarzeje. Wołaj Time.forCompany() w handlerze, a nie na poziomie modułu.
Nie czytaj process.env.TZ
TZ kontenera nie ma związku ze strefą firmy. Nie używaj też metod Date zależnych od lokalnej strefy (getHours, toLocaleString bez timeZone, new Date('2026-10-06 14:30')), tylko helperów z tego rozdziału. Gdy potrzebujesz stałej strefy (np. w testach albo strefy dostawcy), użyj Time.inZone('...') z jawną nazwą.
