Introduction
Tempo is a new library in a proud tradition of JavaScript date and time libraries. Inspired by the likes of moment.js, day.js, and date-fns, Tempo is built from the ground up to be as small and easy to use as possible (all features ~5kB compressed) — including first-class support for timezone operations.
Tempo is best thought of as a collection of utilities for working with the native Date
object — an important distinction from other libraries that provide custom date primitives. Under the hood, Tempo mines JavaScript's Intl.DateTimeFormat
to extract complex data like timezones offsets and locale aware date formats, giving you a simple API to format, parse, and manipulate dates.
Install
Pshhh, come on — you already know how to do this. All you’re looking for is the package name (it’s @formkit/tempo
), but to make it even easier just click your package manager of choice to copy the install command.
Since tempo is just a collection of functions, you use them by importing them from the @formkit/tempo
project — great for tree shaking.
Tempo’s format()
function outputs dates in two ways:
- Format styles — Knowing how to display dates to an international audience is tough. Fortunately
Intl.DateTimeFormat
has a pretty good idea of what the user expects based on their locale (or the locale you specify). - Format tokens — If you already know the format you need to display — Tempo’s formatting tokens give you this ability in a way you are already familiar with.
Format styles
When displaying dates to users, it’s a good idea to use the formats they are familiar with. Tempo uses Intl.DateTimeFormat
’s language-sensitive date and time formatting to make this easy. By using a date or time "style", you indicate the level of specificity you’d like to show the date to the end user with, but no further details. It’s then up to the Intl.DateTimeFormat
to decide how to most appropriately display the date.
Date styles
When using the format()
function, the second argument can be any of the following date styles, or an object with a date property (ex: format(new Date(), { date: 'long' })
)
Style | Example |
---|---|
full | en de zh |
long | en de zh |
medium | en de zh |
short | en de zh |
Time styles
To use a time style format you must provide an object as the second argument of the format()
function with a time property. You can also use the time property with the date property.
Style | Example |
---|---|
full | en de zh |
long | en de zh |
medium | en de zh |
short | en de zh |
Format tokens
If you already know the format you need to display — Tempo’s formatting tokens allow for any arbitrary format in a way you are already familiar with (tokens are similar to day.js). These tokens automatically leverage the user’s locale or the one specified in the format function.
Token | Example | Description |
---|---|---|
YY | 24 | 2 digit year |
YYYY | 2024 | 4 digit year |
M | 10 | The month 1-12 |
MM | 10 | The month 01-12 |
MMM | Oct | Short name Jan-Dec |
MMMM | October | Full name January - December |
D | 10 | The day of the month 1-31 |
DD | 10 | The day of the month 01-31 |
d | T | Single digit day "T" |
ddd | Thu | Short day name |
dddd | Thursday | Full day name Wednesday |
H | 1, 13 | Minimum hour digits, 24 hour, 0-23 |
HH | 01, 13 | 2 hour digits, 24 hour, 00-23 |
h | 1, 12 | Minimum hour digits, 12 hour clock, 1-12 |
hh | 01, 12 | 2 hour digits, 12 hour clock, 01-12 |
m | 2, 33 | The minute 0-59 |
mm | 02, 33 | The minute 00-59 |
s | 7, 17 | The second 0-59 |
ss | 07, 17 | The second 00-59 |
a | pm | am/pm |
A | PM | AM/PM |
Z | +08:00, +05:30, -13:45 | The timezone offset from GMT ([+-]HH:mm ) |
ZZ | +0800, +0530, -1345 | The timezone offset from GMT ([+-]HHmm ) |
Format options
The format()
function can accept an object of options as its argument to provide more control over the output.
Timezone
The tz
option allows you to format the provided date from the “perspective” of any given timezone.
Part filter
The partFilter
option allows you to filter out parts of the formatted date. The function is called with each "part" of the formatted date and should return a boolean indicating whether or not to include that part in final formatted string.
Genitive case
Some languages have a genitive case for months and weekdays. When the genitive option is set to true, the month and weekday names will be in the genitive case for locales where it is applicable.
To convert a date string into a Date
object we use the parse
function. This allows us to parse any output from the format
function — including style formats!
A Date
object in JavaScript is fundamentally a timestamp, in other words, always includes both date and time. The parse
function does not need to include both date and time, but the resulting Date
object will always include both. For consistent behavior, the undefined portions of the full date will use the current date at midnight local time.
Parsing options
The parse
function can accept an object of options as its argument:
The date
, format
, locale
options are familiar, but what is partFilter
and dataOverflow
?
partFilter
The partFilter
option gives you fine-grained control over which pieces and parts of a date you’d like to include in the resulting Date
object (remember, missing "parts" will default to the today’s date at midnight local).
dateOverflow
The dateOverflow
option determines how an “out of range” date should be parsed (ex: February 30th). Options are backward
(default), forward
, throw
.
Modify
Tempo includes a number of (tree-shakable) utility functions to assist you in your date modifying needs. These functions all accept either an ISO 8601 string or a Date object and return a new Date object (they do not change the date argument).
Returns a new Date object with a positive or negative number of days applied to date argument. To subtract days, use a negative number.
Returns a new Date object with a positive or negative number of hours applied to date argument. To subtract hours, use a negative number.
Returns a new Date object with a positive or negative number of minutes applied to date argument. To subtract minutes, use a negative number.
Returns a new Date object with a positive or negative number of
months applied to date argument. To subtract months, use a negative number.
Sometimes the result will "overflow" the available days of
the result month. For example when adding 1 month to January 31st the
resulting date would be February 31st, which does not exist. By default, the
date will be set to the last day of February but you could opt for it
to "overflow" into March by setting dateOverflow
to
true
.
Returns a new Date object with a positive or negative number of seconds applied to date argument. To subtract seconds, use a negative number.
Returns a new Date object with a positive or negative number of years
applied to date argument. To subtract years, use a negative number.
Sometimes the result will "overflow" the available days of
the result month. For example when adding 1 year to February 29, 2024 the
resulting date would be February 29, 2025, which does not exist (2025 is
not a leap year). By default, the date will be set to February 28, 2025 but
you could opt for it to "overflow" into March by setting
dateOverflow
to true
.
Returns a new Date object with a timezone offset applied to date argument — this function does fundamentally change the date but can be very useful when working with timezones. Read more in the timezone section.
Converts an ISO 8601 like string into a Date object (noop on Date
objects). ISO 8601 strings do not need to be complete to be accepted, but you need at least a year and month.
Returns a new Date object with the time set to 23:59:59.999 (local time).
Returns a new Date object with the time set to 00:00:00.000 (local time).
Returns a new Date object with the minutes part of the time set to 59:59.999 (local time).
Returns a new Date object with the minutes part of the time set to 00:00.000 (local time).
Returns a new Date object with the seconds part of the time set to 59.999 (local time).
Returns a new Date object with the seconds part of the time set to 00.000 (local time).
Returns a new Date object with the date set to the last day of the current month (does not modify the time).
Returns a new Date object with the date set to the first day of the current month and the time set to 00:00:00 (local).
Returns a new Date object with the inverse of the specified offset applied. This can be helpful to normalize time information across timezones.
Converts an ISO 8601 like string into a Date object with a timezone applied. For example, tzDate('2021-01-01T00:00', 'America/Los_Angeles')
will return a Date object representing 2021-01-01 00:00 in L.A.
Returns a new Date object with the date set to the last day of the current week with the time set to 23:59:59 (local).
Returns a new Date object with the date set to the first day of the current week with the time set to 00:00:00 (local).
Returns a new Date object with the date set to the end of the year
Data
Tempo also includes functions to extract date information. These functions make no changes to the date object and are only used to extract useful data that is commonly needed to build applications.
Returns either am or pm but in any given locale.
Gets the day of the year a given date is. For example, August 1st is the 213th day of the year on non-leap years and 214th on leap years.
This little gem of a function returns the token format for a given format style.
Converts a 2 digit year into a 4 digit year. This function assumes years 20 years into the future belong to the current century, and the past 80 are in the past century.
Validates that a given date passes “acceptable” levels of ISO 8601 compatibility and can be utilized within Tempo. This allows incomplete dates but must include at least the year and month. Does not require the T
separator.
Performs a bidirectional search for the nearest date that passes a given search function. It stops searching when it finds a result or when it reaches the constraint bounds (on both sides).
Returns the offset between two (IANA) timezones on a given date. The results are ISO 8601 compatible string offsets like -0800 or +0530.
Given a date string like "2019/12/31" and the parts (like those returned from the parts
function) this function returns the parts with the appropriate values extracted from the date string and added to a value
property.
Given a format and locale, this function produces an array of "parts". Similar to Intl.DateTimeFormat.formatToParts()
but it accepts style formats and token formats and returns parts with granular data such as the part’s token and a regex to match for it.
Returns an array of options for a given token in a given locale. For example, the token MMMM
in the locale en-US
would return ['January', 'February', 'March', ...]
.
Helpers
Tempo includes a number of (tree-shakable) helper functions to assist you in your date workarounds. These functions all accept either an ISO 8601 string or a Date object and return a boolean.
Returns the number of milliseconds difference between two date objects.
Returns the number of seconds difference between two date objects. An optional third argument controls what kind of “rounding” should be used for partial seconds.
Returns the number of minutes difference between two date objects. An optional third argument controls what kind of “rounding” should be used for partial minutes.
Returns the number of hours difference between two date objects. An optional third argument controls what kind of “rounding” should be used for partial hours.
Returns the number of days difference between two date objects. An optional third argument controls what kind of “rounding” should be used for partial days.
Returns the number of weeks difference between two date objects. An optional third argument controls what kind of “rounding” should be used for partial weeks.
Returns the number of months difference between two date objects. An optional third argument controls what kind of “rounding” should be used for partial months.
Returns the number of years difference between two date objects. An optional third argument controls what kind of “rounding” should be used for partial years.
Returns true if the first date is after the second date, otherwise false.
Returns true if the first date is before the second date, otherwise false.
Returns true if the first date is equal to the second date, otherwise false.
Checks if two dates are the same second. This function is useful for comparing dates but ignoring the milliseconds.
Checks if two dates are the same minute. This function is useful for comparing dates but ignoring the seconds and milliseconds.
Checks if two dates are the same hour. This function is useful for comparing dates but ignoring the minutes, seconds, and milliseconds.
Checks if two dates are the same day. This function is useful for comparing dates but ignoring the time.
Timezones
Timezones are challenging for 2 reasons:
- 1. They are conceptually difficult to understand.
- 2. They involve a lot of geography, history, and politics.
Tempo provides timezone support via format()
, tzDate()
, offset
, applyOffset
, and removeOffset
functions.
Key concept
A timezone is really an expression or "view" of a given absolute time. An airplane departing Amsterdam 2012-04-07 11:00:00 UTC
leaves the ground at the same moment in every timezone on earth. JavaScript’s Date
object is "absolute" in the same way as the airplane’s takeoff. A timezone is only a way to express that moment relative the geography and politics of a given region.
Using timezones
Creating timezone dates
The most basic timezone aware function is tzDate
which allows you to create a new Date object at in a particular timezone.
Formatting timezones
The format
function can accept a tz
option to format a date in a specific timezone.
Calculating offsets
Tempo uses the Intl.DateTimeFormat
API to extract timezone information, that makes working with timezones as simple as possible. The offset()
function calculates the amount of offset between any two timezones (given in +-HHmm
).
Removing offsets
To display the time of a Date
object in a specific timezone you only need to remove the relative offset. Since Tempo operates with native Date
objects the resulting Date
object is one whose internal methods (like getHours()
) will return the time "at" the desired timezone.
Applying offsets
If you are creating a car rental booking app you want the pickup time to always be relative to the local time of the pickup location. The applyOffset
function is used to apply a given offset to a Date
object to determine the absolute time in a different timezone.
Support us
Tempo is made with love by the FormKit team — the creators of open source projects such as:
- FormKit - The open-source form framework for Vue.
- AutoAnimate - Add motion to your apps with a single line of code.
- ArrowJS - Reactivity without the Framework.
If you find our projects useful and would like to support their ongoing development, please consider sponsoring us on GitHub!