@servicetitan/temporal-lite
v3.2.0
Published
A lightweight, forward-compatible version of [Temporal](https://tc39.es/proposal-temporal/docs/). Its purpose is to reap the benefits of Temporal before it's released while providing a relatively seamless migration to Temporal when it's released.
Downloads
4,543
Keywords
Readme
Temporal-lite
A lightweight, forward-compatible version of Temporal. Its purpose is to reap the benefits of Temporal before it's released while providing a relatively seamless migration to Temporal when it's released.
Benefits include:
- timezone support
- built-in immutability
- differentiating between time-zoned date/time vs plain date/time
- handles DST calculations
- Intl compatible (in that it preserves epoch time)
This package also includes
- custom Axios handlers to serialize/deserialize Temporal's ZonedDateTime and Duration for ServiceTitan APIs that use ServiceTitan's
TypescriptCodeGen
attribute withTemporal = true
.
Sandbox
Feel free to play around with Temporal-lite here (does not include ServiceTitan-specific TemporalFactory
, TemporalFormatter
, or Axios handlers). Please report any bugs.
Usage
ZonedDateTime
import { ZonedDateTime } from '@servicetitan/temporal-lite';
ZonedDateTime.from({ timeZone: 'Asia/Taipei', year: 2022, month: 1, day: 1 });
// -> 2022-01-01T00:00+08:00
PlainDateTime
import { PlainDateTime } from '@servicetitan/temporal-lite';
new PlainDateTime(2022, 1, 1);
// -> 2022-01-01T00:00
PlainDate
import { PlainDate } from '@servicetitan/temporal-lite';
new PlainDate(2022, 1, 1);
// -> 2022-01-01
PlainTime
import { PlainTime } from '@servicetitan/temporal-lite';
new PlainTime(23, 30, 30, 30);
// -> 23:30:30.030
Now
import { Now } from '@servicetitan/temporal-lite';
Now.zonedDateTimeISO(); // -> 2022-08-17T00:00-08:00
Now.plainDateTimeISO(); // -> 2022-08-17T00:00
Now.plainDateISO(); // -> 2022-08-17
Now.plainTimeISO(); // -> 23:30:30.030
Duration
import { Duration } from '@servicetitan/temporal-lite';
const duration = Duration.from({ hours: 48 });
duration.total('day'); // -> 2
duration.total('hour'); // -> 48
duration.total('minute'); // -> 2880
Temporal Factory
const [{ getZonedDateTime, getZonedDateTimeNow, getPlainDateNow, getPlainTimeNow }] =
useDependencies(TemporalFactory);
// results change depending on TemporalFactory's auto-calculation of time zone
const plainDateNow = getPlainDateNow();
const plainTimeNow = getPlainTimeNow();
const zonedDateTimeNow = getZonedDateTimeNow();
getZonedDateTime(plainDateNow, plainTimeNow);
getZonedDateTime(zonedDateTimeNow);
getZonedDateTime(new Date());
Common Scenario - weekly view
import { Duration } from '@servicetitan/temporal-lite';
const [{ getPlainDateNow }, { format }] = useDependencies(TemporalFactory, TemporalFormatter);
const today = getPlainDateNow();
const displayWeek = (Array(7).fill("") as PlainDate[])
.map((_value, index) => {
const current = todayPlainDate.add(Duration.from({ days: index }));
return format(current, {
month: "short",
day: "numeric"
});
})
.join(", ");
// America/Los_Angeles -> Aug 17, Aug 18, Aug 19, Aug 20, Aug 21, Aug 22, Aug 23
// Asia/Taipei -> Aug 18, Aug 19, Aug 20, Aug 21, Aug 22, Aug 23, Aug 24
const nextWeekStart = today.add(Duration.from({ weeks: 1 }); // America/Los_Angeles -> Aug 24
const previousWeekStart = today.add(Duration.from({ weeks: -1 }); // America/Los_Angeles -> Aug 10
Common Scenario - formstate
@injectable()
export class FormStore {
formState = new FormState({
startDate: new FieldState<PlainDate>(this.temporalFactory.getPlainDateNow()),
endDate: new FieldState<PlainDate>(this.temporalFactory.getPlainDateNow()),
startTime: new FieldState<PlainTime>(PlainTime.from({ hour: 9 })),
endTime: new FieldState<PlainTime>(PlainTime.from({ hour: 17 })),
});
constructor(@inject(TemporalFactory) private temporalFactory: TemporalFactory) {
makeObservable(this);
}
@computed
get formData() {
const { getZonedDateTime } = this.temporalFactory;
const formData = formStateToJS(this.formState);
return {
start: getZonedDateTime(formData.startDate, formData.startTime),
end: getZonedDateTime(formData.endDate, formData.endTime),
};
}
}
Common Scenario - comparisons
import { ZonedDateTime } from '@servicetitan/temporal-lite';
const appointments = [
{
id: 1,
date: ZonedDateTime.from({
timeZone: 'America/Los_Angeles',
year: 2022,
month: 8,
day: 17,
hour: 8,
}),
},
{
id: 2,
date: ZonedDateTime.from({
timeZone: 'Asia/Taipei',
year: 2022,
month: 8,
day: 17,
hour: 13,
}),
},
{
id: 3,
date: ZonedDateTime.from({
timeZone: 'Asia/Taipei',
year: 2022,
month: 8,
day: 17,
hour: 9,
}),
},
];
appointments.map(a => a.date).sort(ZonedDateTime.compare); // id order -> 3, 2, 1
Common Scenario - conversions
// Developers will almost always want to utilize TemporalFactory for creating or converting
// to ZoneDateTime instances so that the time zone is abstracted away.
// legacy Date => ZonedDateTime
const [{ getZonedDateTime }] = useDependencies(TemporalFactory);
const legacyDate = new Date();
getZonedDateTime(legacyDate);
ZonedDateTime.from(legacyDate.toISOString()); // non-TemporalFactory way
// ZonedDateTime => legacy Date
const zonedDateTime = Now.zonedDateTimeISO();
new Date(zonedDateTime.toString());
// Plain Date + Plain Time => PlainDateTime
const plainDate = Now.plainDateISO();
const plainTime = Now.plainTimeISO();
PlainDateTime.from({ …plainDate, …plainTime })
Contributing
Pull requests are welcome. Please make sure to update tests as appropriate.