Date and Timezone
Elemental provides a powerful and reactive system for handling date and time localization, built upon the robust dayjs
library. This guide will walk you through setting up your application's localization environment, working with dates using the LmnDate
class, and formatting them for display with our custom pipes. All functionalities discussed here are available from @elemental/common
, unless specified otherwise.
Core Concepts
Understanding these core concepts is key to effectively using Elemental's date and time features:
- Locales (
LmnLocale
): A locale defines language-specific formatting conventions, including number formats, date representations, and day/month names. Locales are typically represented by a language code and an optional region/country code (e.g.,'en'
for English,'en-US'
for US English,'fr-CA'
for Canadian French). Elemental provides an extensive list of supported locales. - Languages (
LmnLanguage
): While locales handle formatting, the language setting (e.g.,'en'
,'it'
) is primarily used by the translation engine and influences language-specific aspects ofdayjs
(like month/day names if not fully specified by the locale data). - Date Formats (
LmnDateFormatPreset
): Elemental defines standard date and time format presets for'short'
,'medium'
,'long'
, and'full'
lengths. These presets dictate how dates, times, and datetimes are structured for each locale. - Timezones (
LmnTimezone
): Timezones are identified using TZ database names (e.g.,'America/New_York'
,'Europe/Rome'
,'UTC'
). Elemental allows for both global timezone settings and instance-specific timezone handling. LmnDate
Class: This is your primary tool for all date and time operations. It's a reactive wrapper around adayjs
object, internally managing all dates in UTC and handling timezone conversions transparently for display and manipulation.- Date Pipes (
lmnDate
,lmnTime
,lmnDatetime
,lmnTimezone
): Angular pipes for easily formattingLmnDate
objects directly within your templates, respecting the current locale and timezone settings.
Setting Up Your Localization Environment
Properly configuring your application's localization environment is the first step. This typically involves setting default values for locale, language, and timezone during your application's bootstrap process.
Setting the Default Locale
The locale dictates how dates, numbers, and other locale-sensitive information are formatted.
setLocale(locale: LmnLocale, localeSpec?: LmnLocaleSpecification, dateFormatSpec?: LmnDateFormatPreset): Promise<void>
- Use
setLocale
to define the application-wide default locale. This function will also attempt to dynamically load the correspondingdayjs
locale module. - You can optionally provide a custom
LmnLocaleSpecification
to fine-tunedayjs
behavior for that locale (e.g., first day of the week, custom month names). - You can also provide a
LmnDateFormatPreset
to define entirely custom date/time formats for this locale, which will override any built-in formats. - This updates the
currentLocale():
, which many formatting functions and pipes depend on.Signal <LmnLocale>
// Example: app.config.ts
import { ApplicationConfig } from '@angular/core';
import { setLocale } from '@elemental/common';
// Assuming you might also set language and timezone
import { setLanguage, setTimezone } from '@elemental/common';
export function initializeLocalization(): Promise<void> {
setLanguage('en'); // Set base language for translations
setTimezone('America/New_York'); // Set default operating timezone
return setLocale('en-US'); // Set default locale for formatting
}
export const appConfig: ApplicationConfig = {
providers: [
// ... other providers
{
provide: APP_INITIALIZER ,
useFactory: () => initializeLocalization,
multi: true,
},
],
};
Setting the Default Language
While setLocale
handles formatting, setLanguage
influences the language used by dayjs
for names (if not overridden by LmnLocaleSpecification
) and is crucial for the
setLanguage(language: LmnLanguage): void
- Updates the
currentLanguage():
.Signal <LmnLanguage>
import { setLanguage } from '@elemental/common';
// Typically called once during app initialization
setLanguage('fr');
Setting the Default Timezone
Define a default timezone for your application. All LmnDate
formatting will default to this timezone unless explicitly overridden.
setTimezone(timezone: LmnTimezone): void
- Updates the
currentTimezone():
.Signal <LmnTimezone>
import { setTimezone } from '@elemental/common';
// Typically called once during app initialization
setTimezone('Europe/Paris');
Customizing Date Formats for a Locale
If the default date formats for a locale aren't suitable, you can provide a complete custom LmnDateFormatPreset
.
setDateFormatCustom(locale: LmnLocale, dateFormatPreset?: LmnDateFormatPreset): void
- This custom format will be used whenever
getFormatByLocale(locale)
orcurrentFormat()
(iflocale
is the current locale) is called, taking precedence over built-in formats.
import { setDateFormatCustom, LmnDateFormatPreset, LmnLocale } from '@elemental/common';
const myCustomGermanFormats: LmnDateFormatPreset = {
short: {
datetime: 'DD.MM.YY HH:mm',
date: 'DD.MM.YY',
time: 'HH:mm',
// ... other lengths and parts (year, month, day, etc.)
},
// ... medium, long, full definitions
};
setDateFormatCustom('de', myCustomGermanFormats);
// If currentLocale() is 'de', currentFormat() will now return myCustomGermanFormats.
Working with Dates: The LmnDate
Class
The LmnDate
class is the cornerstone for handling dates and times in Elemental. It provides a rich, reactive API for parsing, manipulating, formatting, and querying dates.
For a complete list of all methods and their detailed parameters, please refer to the LmnDate
Introduction to LmnDate
- Reactive Wrapper:
LmnDate
instances are built around Angular Signals, making them inherently reactive to changes in global locale/timezone settings or their own internal state. - Internal UTC: All date and time values within an
LmnDate
object are stored and managed in UTC. Timezone conversions are applied during formatting or when specific timezone-aware methods are called.
Creating LmnDate
Instances
You can create LmnDate
objects from various sources:
Current Date/Time:
new LmnDate()
creates an instance with the current timestamp.From String, Number, or JS Date:
const dateFromISO = new LmnDate('2023-10-26T10:00:00Z'); const dateFromTimestamp = new LmnDate(1698314400000); // Milliseconds since epoch const dateFromJsDate = new LmnDate(new Date());
Parsing with Specific Format and Timezone: If you have a date string in a non-standard format or a specific timezone, provide those details:
// Date string is in 'America/Denver' time const dateFromString = new LmnDate('10/26/2023 12:30 PM', 'MM/DD/YYYY hh:mm A', 'America/Denver'); console.log(dateFromString.value()); // Will show the UTC equivalent
Instance-Specific Locale: You can also create an
LmnDate
with its own locale, which will override the globalcurrentLocale()
for that specific instance's formatting methods:const dateInFrench = new LmnDate(undefined, undefined, undefined, undefined, 'fr-CA'); console.log(dateInFrench.format({ as: 'date', length: 'full' })); // Formats as per 'fr-CA'
Cloning: Create a copy with
const clonedDate = myLmnDate.clone();
.Validation: Check if a date was parsed correctly with
myLmnDate.isValid()
.
Basic Formatting with LmnDate
LmnDate
instances expose several computed Signals for common formatting needs. These automatically use the instance's effective locale (instance-specific or global currentLocale()
) and the global currentTimezone()
.
Reactive Properties:
myLmnDate.value()
: Returns the date as an ISO 8601 string in UTC (e.g.,"2023-10-26T17:00:00.000Z"
).myLmnDate.date()
: Formatted date string (e.g.,"10/26/2023"
).myLmnDate.time()
: Formatted time string (e.g.,"01:00 PM"
).myLmnDate.datetime()
: Formatted date and time string (e.g.,"10/26/2023 01:00 PM"
).- Similar properties exist for
fullDate()
,fullTime()
,fullDatetime()
, and UTC-specific versions likedateUTC()
.
.format(options?: LmnDateFormatOptions)
Method: For more control over formatting, use the.format()
method:const myDate = new LmnDate(); // Default short date format for current locale/timezone console.log(myDate.format({ as: 'date' })); // Full date format console.log(myDate.format({ as: 'date', length: 'full' })); // Custom format string, specific timezone console.log(myDate.format({ format: 'YYYY-MM-DD HH:mm (dddd)', timezone: 'Europe/Berlin' }));
Common Date Manipulations
Modify dates easily:
Adding/Subtracting Time:
const today = new LmnDate(); const nextWeek = today.clone().add(7, 'days'); const lastMonth = today.clone().subtract(1, 'months');
Start/End of a Time Unit:
const startOfThisMonth = new LmnDate().startOf('month'); const endOfToday = new LmnDate().endOf('day');
Comparisons and Queries
LmnDate
offers a comprehensive set of methods for comparing dates (e.g., isBefore()
, isSameOrAfter()
, isBetween()
) and querying information like isLeapYear()
.
const date1 = new LmnDate('2024-01-15');
const date2 = new LmnDate('2024-02-20');
if (date1.isBefore(date2)) {
console.log('Date 1 is earlier.');
}
Human-Readable Time (Relative Time)
Display time relative to now or another date:
myLmnDate.getHumanizedTimeRelativeToNow(hideSuffix?: boolean)
: E.g., "in 5 minutes", "2 hours ago".myLmnDate.getHumanizedTimeRelativeToDate(otherDate: LmnDate, hideSuffix?: boolean)
.
These respect the current locale for phrasing.
Displaying Dates and Times in Templates (Pipes)
Elemental UI provides convenient Angular pipes for formatting LmnDate
objects directly in your component templates. These pipes automatically respect the global currentLocale()
and currentTimezone()
settings but can also be customized.
Refer to the individual pipes API documentation for detailed options.
lmnDate
Pipe: Formats theLmnDate
as a date string.<!-- Assumes myEventDate is an LmnDate instance in your component --> <p>Event Date: {{ (myEventDate | lmnDate)() }}</p> <!-- Default short date --> <p>Full Date: {{ (myEventDate | lmnDate: { length: 'full' })() }}</p> <p>Custom: {{ (myEventDate | lmnDate: { format: 'DD/MM/YY', timezone: 'UTC' })() }}</p>
lmnTime
Pipe: Formats theLmnDate
as a time string.<p>Event Time: {{ (myEventDate | lmnTime)() }}</p> <!-- Default short time --> <p>Detailed Time: {{ (myEventDate | lmnTime: { length: 'medium', timezone: 'America/New_York' })() }}</p>
lmnDatetime
Pipe: Formats theLmnDate
as a combined date and time string.<p>Timestamp: {{ (myEventDate | lmnDatetime: { length: 'long' })() }}</p>
Working with Timezones
Proper timezone handling is critical for many applications.
Global Default: As shown in setup,
setTimezone()
establishes the application's default timezone, whichcurrentTimezone()
reflects. Pipes andLmnDate
formatting methods use this default if no specific timezone is provided.Displaying Timezone Information:
currentTimezoneLabel():
: A computed Signal providing the full, DST-aware label of the current default timezone (e.g.,Signal <string>(GMT -04:00) America/New_York
).getTimezoneLabel(timezone: LmnTimezone, referenceDate?: LmnDate): string
: Programmatically get the DST-aware label for any timezone, optionally using a specificLmnDate
as the reference for DST calculation.lmnTimezone
Pipe: Displays the DST-aware label for a givenLmnDate
and timezone.<!-- Uses global currentTimezone() for referenceDate's timezone label --> <p>Event Timezone: {{ (myEventDate | lmnTimezone)() }}</p> <!-- Shows label for a specific timezone, considering myEventDate for DST --> <p>In London: {{ (myEventDate | lmnTimezone: 'Europe/London')() }}</p>
Formatting in Specific Timezones: Both
LmnDate.format()
and the date/time pipes accept atimezone
option to render the date as it would appear in that target timezone.
Locale-Specific Date Utilities
For building UIs like custom calendars or date pickers, you might need locale-specific names for days and months. These utilities respect the currentLocale()
.
getWeekdays(localOrder?: boolean): string[]
getWeekdaysShort(localOrder?: boolean): string[]
getWeekdaysMin(localOrder?: boolean): string[]
getWeekdaysInitials(localOrder?: boolean): string[]
getMonths(): string[]
getMonthsShort(): string[]
import { getMonths, getWeekdaysShort, currentLocale, setLocale } from '@elemental/common';
await setLocale('es-ES'); // Set to Spanish
console.log(getMonths()); // Outputs: ['enero', 'febrero', ...]
console.log(getWeekdaysShort(true)); // Outputs weekday names starting with the locale's first day of week
Common Workflows
- Application Initialization:
- In
app.config.ts
or an
, callAPP_INITIALIZER setLanguage()
,setLocale()
, andsetTimezone()
to establish application-wide defaults. - Optionally use
setDateFormatCustom()
if default formats for certain locales need overriding.
- In
- Displaying a Server-Provided UTC Timestamp:
- Receive a timestamp or ISO string (assumed to be UTC).
- Create
new LmnDate(timestampOrIsoString)
. - Use
{{ (myLmnDate | lmnDatetime)() }}
in the template. It will automatically display in the user'scurrentTimezone()
andcurrentLocale()
format.
- Date Input from User:
- User inputs a date string, possibly with a specific format.
- Create
new LmnDate(userInputString, 'MM/DD/YYYY', userSelectedTimezone)
. Usestrict: true
for reliable parsing if the format is fixed.
- Calculating Future Dates:
const expiryDate = new LmnDate().add(30, 'days');
- Display with
{{ (expiryDate | lmnDate: { length: 'long' })() }}
.
This comprehensive date and time localization system in Elemental provides the flexibility and reactivity needed for modern global applications. Remember to consult the specific API documentation for LmnDate
and related utilities for exhaustive details on all available methods and options.
Related Concepts: Durations
For representing and formatting periods of time (e.g., "2 hours 30 minutes", "3 days"), Elemental provides the LmnDuration class and lmnDuration pipe. See the