3.1.0 • Published 4 months ago

@servicetitan/temporal-lite v3.1.0

Weekly downloads
-
License
-
Repository
github
Last release
4 months ago

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 with Temporal = 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.

3.1.0

4 months ago

3.0.0

4 months ago

2.1.0

7 months ago

2.0.0

1 year ago

0.1.1

2 years ago