ts-time/ZonedDateTime

Consumption

import ZonedDateTime from "ts-time/ZonedDateTime";

Default export#

Hierarchy#

  • class ZonedDateTime

Description#

Comprises a specific instant bound to a specific time zone. In other words, this is a tuple of (Instant, ZoneId). Unambiguously identifies an OffsetDateTime, i.e. LocalDateTime and ZoneOffset.

Construct#

Typically you don't construct ZonedDateTime directly, but create it from other data structures:

ZonedDateTime.ofInstant(instant, zone);   // From Instant in a given ZoneId
instant.atZone(zone);                     // Equivalent
ZonedDateTime.ofDateTime(dateTime, zone); // From LocalDateTime in a given ZoneId
dateTime.atZone(zone);                    // Equivalent
offsetDateTime.instant.atZone(zone);      // From OffsetDateTime in a given ZoneId, preserving instant component
offsetDateTime.dateTime.atZone(zone);     // From OffsetDateTime in a given ZoneId, preserving dateTime component

Please notice that:

  • Conversion from Instant may be counter-intuitive, as string presentation of the date/time may change:
    const zone    = ZoneId.of("America/New_York");
    const instant = Instant.parse("2022-06-14T00:00:00.000Z");
    console.log(instant.atZone(zone));           // "2022-06-13T20:00:00.000-04:00[America/New_York]"
    It happens, because ZonedDateTime preserves its instant component in this case, not dateTime:
    console.log(instant.atZone(zone).instant);   // "2022-06-14T00:00:00.000Z"
    console.log(instant.atZone(zone).dateTime);  // "2022-06-13T20:00:00.000"
  • Conversion from LocalDateTime, on the contrary, preserves dateTime component:
    const dateTime = LocalDateTime.parse("2022-06-14T00:00:00.000");
    console.log(dateTime.atZone(zone));          // "2022-06-14T00:00:00.000-04:00[America/New_York]"
    console.log(dateTime.atZone(zone).dateTime); // "2022-06-14T00:00:00.000"
    console.log(dateTime.atZone(zone).instant);  // "2022-06-14T04:00:00.000Z"
  • Conversion from OffsetDateTime results in loss of the original offset.

As opposed to Java API, there's no common way to get the current instance of ZonedDateTime in ts-time, because ts-time doesn't have a concept of default time zone. Instead, you must get the current Instant and convert it to an object that you need, taking time zone into consideration.

Instant.now().atZone(UTC);             // Current ZonedDateTime in UTC
Instant.now().atZone(LOCAL_ZONE_ID);   // Current ZonedDateTime in the local time zone
Instant.now().atZone(zone);            // Current ZonedDateTime in a given ZoneId/ZoneOffset

It makes ts-time API more robust. It leaves less room for a mistake.

A common way to convert a native JavaScript Date object to a ts-time object is to call fromNative* static method:

Instant.fromNative(date).atZone(zone); // ZonedDateTime from a given Date in a given ZoneId/ZoneOffset
Parse#

A common way to parse an ISO 8601 compliant string in ts-time is to call parse static method. For example, the following ZonedDateTime instance represents 18 hours, 30 minutes, 15 seconds, 225 milliseconds on 15th of February, 2022 in New York:

ZonedDateTime.parse("2022-02-15T18:30:15.225-05:00[America/New_York]");

The library doesn't yet support parsing non-compliant strings.

Inspect#

In the following example, we inspect various properties of a ZonedDateTime object. Please notice the difference in return value types:

const zonedDateTime  = ZonedDateTime.parse("2022-02-15T18:30:15.225-05:00[America/New_York]");
const year           = zonedDateTime.year;            // 2022
const month          = zonedDateTime.month;           // FEBRUARY
const monthValue     = zonedDateTime.month.value;     // 2
const dayOfMonth     = zonedDateTime.dayOfMonth;      // 15
const dayOfWeek      = zonedDateTime.dayOfWeek;       // TUESDAY
const dayOfWeekValue = zonedDateTime.dayOfWeek.value; // 2
const hour           = zonedDateTime.hour;            // 18
const minute         = zonedDateTime.minute;          // 30
const second         = zonedDateTime.second;          // 15
const ms             = zonedDateTime.ms;              // 225
const zone           = zonedDateTime.zone;            // Instance of ZoneId
const zoneId         = zonedDateTime.zone.id;         // "America/New_York"
const offset         = zonedDateTime.offset;          // Instance of ZoneOffset
const offsetHours    = zonedDateTime.offset.hours;    // -5
const offsetMinutes  = zonedDateTime.offset.minutes;  // 0
const offsetSeconds  = zonedDateTime.offset.seconds;  // 0

Other sophisticated features for ZonedDateTime inspection: epochMs, era, yearOfEra, weekBasedYear, weekOfWeekBasedYear, dayOfYear, dayOfWeekBasedYear, epochDay, quarterOfYear, isLeapYear, lengthOfYear.

Compare#

A common way to compare objects in ts-time is to call equals, compareTo methods:

const d1 = ZonedDateTime.parse("2022-02-15T18:30:15.225-05:00[America/New_York]");
const d2 = ZonedDateTime.parse("2022-02-15T18:30:15.226-05:00[America/New_York]");
d1.equals(d2);    // false
d1.compareTo(d2); // -1

The objects are first compared by instant, and then by zone text identifier.

For nullable objects, use static methods instead. Null and undefined are considered less than anything, except each other:

const d1: ZonedDateTime = null;
const d2 = ZonedDateTime.parse("2022-02-15T18:30:15.226-05:00[America/New_York]");
ZonedDateTime.equal(d1, d2);   // false
ZonedDateTime.compare(d1, d2); // -1

As opposed to the majority of objects in ts-time, ZonedDateTime doesn't have isBefore and isAfter methods. You must explicitly specify which component you want to compare: instant or dateTime.

const d1 = ZonedDateTime.parse("2022-02-15T18:30:15.225-05:00[America/New_York]");
const d2 = ZonedDateTime.parse("2022-02-15T20:30:15.226+01:00[Europe/Berlin]");
d1.instant.isBefore(d2.instant);   // false
d1.dateTime.isBefore(d2.dateTime); // true
Manipulate#

Every object in ts-time is immutable. Therefore every manipulation returns a new object.

To add/subtract a Period, call plusPeriod/minusPeriod method:

const zonedDateTime = ZonedDateTime.parse("2022-02-15T18:30:15.225-05:00[America/New_York]");
const d1 = zonedDateTime.plusPeriod(DAY_PERIOD);                // 18:30:15.225 on 16th of February, 2022 in New York
const d2 = zonedDateTime.plusPeriod(Period.ofDays(2));          // 18:30:15.225 on 17th of February, 2022 in New York
const d3 = zonedDateTime.minusPeriod(MONTH_PERIOD);             // 18:30:15.225 on 15th of January, 2022 in New York

The algorithm respects dateTime to align periods, not instant. In the following example, zonedDateTime is the 1st of March in Berlin, but still 28th of February in UTC. When adding a month, the library considers zonedDateTime to be the 1st of March, so it adds 31 days, not 28:

const zonedDateTime = ZonedDateTime.parse("2022-03-01T00:00:00.000+01:00[Europe/Berlin]");
const d1 = zonedDateTime.plusPeriod(MONTH_PERIOD);              // Midnight on 1st of April, 2022 in Berlin

If you expect a month to be added in UTC, convert the instant explicitly to UTC first:

const d2 = zonedDateTime.instant.atZone(UTC).plusPeriod(MONTH_PERIOD); // 23:00 on 28th of March, 2022, UTC

If the date/time jumps over daylight saving borderline, the result will have a different offset:

const winterTime = ZonedDateTime.parse("2022-03-01T00:00:00.000+01:00[Europe/Berlin]");
const summerTime = winterTime.plusPeriod(Period.ofMonths(3));
console.log(summerTime);            // "2022-06-01T00:00:00.000+02:00[Europe/Berlin]"

The same may happen in rare cases of historical time zone rule changes (i.e. regulations of local governments).

To add/subtract a Duration, call plusDuration/minusDuration method:

const zonedDateTime = ZonedDateTime.parse("2022-02-15T18:30:15.225-05:00[America/New_York]");
const d1 = zonedDateTime.plusDuration(MINUTE_DURATION);         // 18:31:15.225 on 15th of February in New York
const d2 = zonedDateTime.plusDuration(Duration.ofHours(10));    // 04:30:15.225 on 16th of February in New York
const d3 = zonedDateTime.minusDuration(Duration.ofSeconds(30)); // 18:29:45.225 on 15th of February in New York

For difference between Period and Duration, see their documentation. When manipulating ZonedDateTime, this difference is important to understand.

To change one of the components, preserving all the rest, call with* methods:

const zonedDateTime = ZonedDateTime.parse("2022-02-15T18:30:15.225-05:00[America/New_York]");
const d1 = zonedDateTime.withYear(2025);                        // 18:30:15.225 on 15th of February, 2025 in New York
const d2 = zonedDateTime.withMonth(APRIL);                      // 18:30:15.225 on 15th of April, 2022 in New York
const d3 = zonedDateTime.withDayOfMonth(10);                    // 18:30:15.225 on 10th of February, 2022 in New York
const d4 = zonedDateTime.withDayOfWeek(SUNDAY);                 // 18:30:15.225 on 20th of February, 2022, Sunday in New York
const d5 = zonedDateTime.withHour(20);                          // 20:30:15.225 on 15th of February, 2022 in New York
const d6 = zonedDateTime.withMinute(20);                        // 18:20:15.225 on 15th of February, 2022 in New York
const d7 = zonedDateTime.withSecond(20);                        // 18:30:20.225 on 15th of February, 2022 in New York
const d8 = zonedDateTime.withMs(20);                            // 18:30:15.020 on 15th of February, 2022 in New York

For manipulating zone component, see Convert.

The library doesn't yet support ZonedDateTime truncating. Truncate its dateTime component instead.

Another sophisticated feature for ZonedDateTime manipulation: withDayOfYear.

Convert#

You can convert ZonedDateTime to other kinds of objects via its properties:

const zonedDateTime = ZonedDateTime.parse("2022-02-15T18:30:15.225-05:00[America/New_York]");
zonedDateTime.instant;                   // To Instant: 2022-02-15T23:30:15.225Z
zonedDateTime.date;                      // To LocalDate: 2022-02-15
zonedDateTime.time;                      // To LocalTime: 18:30:15.225
zonedDateTime.dateTime;                  // To LocalDateTime: 2022-02-15T18:30:15.225
zonedDateTime.instant.atOffset(offset);  // To OffsetDateTime in a given ZoneOffset, preserving instant component: 2022-02-16T03:30:15.225+04:00
zonedDateTime.dateTime.atOffset(offset); // To OffsetDateTime in a given ZoneOffset, preserving dateTime component: 2022-02-15T18:30:15.225+04:00
zonedDateTime.instant.atZone(zone);      // To ZonedDateTime with another ZoneId, preserving instant component: 2022-02-16T00:30:15.225+01:00[Europe/Berlin]
zonedDateTime.dateTime.atZone(zone);     // To ZonedDateTime with another ZoneId, preserving dateTime component: 2022-02-15T18:30:15.225+01:00[Europe/Berlin]

Please notice that all conversions result in a partial data loss (date, time, original time zone).

You can as well convert ZonedDateTime to a native JavaScript Date:

const zonedDateTime = ZonedDateTime.parse("2022-02-15T18:30:15.225-05:00[America/New_York]");
zonedDateTime.native;                    // Date representing 23:30:15.225 on 15th of February, 2022 (UTC)

Please notice that native Date is always stored in UTC or local time zone, so you can see a different date/time when printing it as a string. It will be the same instant, just a different time zone.

For backward conversion, see Construct.

Format#

Every class in ts-time has ISO 8601 compliant toString method:

const zonedDateTime = ZonedDateTime.parse("2022-02-15T18:30:15.225-05:00[America/New_York]");
zonedDateTime.toString(); // "2022-02-15T18:30:15.225-05:00[America/New_York]"

For more sophisticated string formatting, add ts-time-format library to your list of dependencies:

npm install --save ts-time-format

Now you can construct an instance of ZonedDateTimeFormatter in order to format arbitrary ZonedDateTime instances:

const formatter = ZonedDateTimeFormatter.ofPattern("dd.MMM''yy, hh:mm a ('UTC'x, V)");
const zonedDateTime = ZonedDateTime.parse("2022-02-15T18:30:15.225-05:00[America/New_York]");
formatter.format(zonedDateTime); // "15.Feb'22, 06:30 PM (UTC-05, America/New_York)"

You can define a custom context object to internationalize the formatted strings:

const context = {monthShortNames: ["Янв", "Фев", "Мар"]};
formatter.format(zonedDateTime, context); // "15.Фев'22, 06:30 PM (UTC-05, America/New_York)"

Fields#

dateTime#

readonly dateTime: LocalDateTime

Date/time representing instant in zone.
instant#

readonly instant: Instant

Instant representing dateTime in zone.
zone#

readonly zone: ZoneId

Time zone. Connection between instant and dateTime.
offset#

readonly offset: ZoneOffset

Offset of zone at instant.
date#

readonly date: LocalDate

Date part.
time#

readonly time: LocalTime

Time part.
offsetDateTime#

readonly offsetDateTime: OffsetDateTime

Offset date/time representing instant with offset.
native#

readonly native: Date

Native JS Date representing instant, for compatibility with native and third party API.
epochMs#

readonly epochMs: number

Number of milliseconds since epoch.
era#

readonly era: Era

Era.
year#

readonly year: number

Absolute year.
yearOfEra#

readonly yearOfEra: number

Year in era. See Era for details.
weekBasedYear#

readonly weekBasedYear: number

Absolute week based year.

By definition, the 1st week of week based year contains the 1st Thursday of the year, and the week based year starts from the Monday of this week.

month#

readonly month: Month

Month.
weekOfWeekBasedYear#

readonly weekOfWeekBasedYear: number

1-based week of week-based year.

By definition, the 1st week of week based year contains the 1st Thursday of the year, and the week based year starts from the Monday of this week.

dayOfYear#

readonly dayOfYear: number

1-based day of year.
dayOfWeekBasedYear#

readonly dayOfWeekBasedYear: number

1-based day of week-based year.

By definition, the 1st week of week based year contains the 1st Thursday of the year, and the week based year starts from the Monday of this week.

dayOfMonth#

readonly dayOfMonth: number

1-based day of month.
dayOfWeek#

readonly dayOfWeek: DayOfWeek

Day of week.
epochDay#

readonly epochDay: number

1-based day since epoch (i.e. 1st of JANUARY 1970 is the 1st epoch day).
quarterOfYear#

readonly quarterOfYear: number

1-based quarter of year.
isLeapYear#

readonly isLeapYear: boolean

True if belongs to a leap year.
lengthOfYear#

readonly lengthOfYear: number

Number of days in year (365 for non-leap, 366 for leap).
hour#

readonly hour: number

Hour of a day (0-23).
minute#

readonly minute: number

Minute of an hour (0-59).
second#

readonly second: number

Second of a minute (0-59).
ms#

readonly ms: number

Millisecond of a second (0-999).

Methods#

compareTo#

(other: ZonedDateTime): number

other
Zoned date/time to compare to.
returns
  • 0 if this is the same zoned date/time;
  • positive value if this zoned date/time goes after other;
  • negative value if this zoned date/time goes before other.
The objects are first compared by instant, and then by zone text identifier. Null and undefined are considered less than anything, except each other.

Note that a method call on null or undefined always leads to an error. So, if your variable may contain null or undefined, use the respective static method instead.

equals#

(other: ZonedDateTime): boolean

other
Zoned date/time to compare to.
returns
True if this zoned date/time is equal to other, i.e. all components are equal. Null and undefined are only equal to each other.

Note that a method call on null or undefined always leads to an error. So, if your variable may contain null or undefined, use the respective static method instead.

plusDuration#

(duration: Duration): ZonedDateTime

duration
Duration to add.
returns
New ZonedDateTime shifted onwards from this one by the specified duration in the same zone. The algorithm respects instant to add the duration.
plusPeriod#

(period: Period): ZonedDateTime

period
Period to add.
returns
New ZonedDateTime shifted onwards from this one by the specified period in the same zone. The algorithm respects dateTime to align periods.
minusDuration#

(duration: Duration): ZonedDateTime

duration
Duration to subtract.
returns
New ZonedDateTime shifted backwards from this one by the specified duration in the same zone. The algorithm respects instant to add the duration.
minusPeriod#

(period: Period): ZonedDateTime

period
Period to subtract.
returns
New ZonedDateTime shifted backwards from this one by the specified period in the same zone. The algorithm respects dateTime to align periods.
withYear#

(year: number): ZonedDateTime

year
Absolute year.
returns
New ZonedDateTime with the specified year and its current month/day of month/time/zone. If such date doesn't exist, it shifts the date back to the nearest valid one, preserving the time (e.g. 29th of FEBRUARY in 2019, 18:30 [Europe/Berlin] gets shifted to 28th of FEBRUARY, 18:30 [Europe/Berlin]).
withMonth#

(month: number | Month): ZonedDateTime

month
Month.
returns
New ZonedDateTime with the specified month and its current year/day of month/time/zone. If such date doesn't exist, it shifts the date back to the nearest valid one, preserving the time (e.g. 31st of APRIL, 18:30 [Europe/Berlin] gets shifted to 30th of APRIL, 18:30 [Europe/Berlin]).
withDayOfMonth#

(dayOfMonth: number): ZonedDateTime

dayOfMonth
1-based day of month.
returns
New ZonedDateTime with the specified day of month and its current year/month/time/zone.
withDayOfWeek#

(dayOfWeek: number | DayOfWeek): ZonedDateTime

dayOfWeek
Day of week or its numeric value
returns
New ZonedDateTime with the specified day of week and its current week/time/zone.
withDayOfYear#

(dayOfYear: number): ZonedDateTime

dayOfYear
1-based day of year.
returns
New ZonedDateTime with the specified day of year and its current year/time/zone.
withHour#

(hour: number): ZonedDateTime

hour
Hour of a day.
returns
New ZonedDateTime with the specified hour of a day. All other properties don't change.
withMinute#

(minute: number): ZonedDateTime

minute
Minute of an hour.
returns
New ZonedDateTime with the specified minute of an hour. All other properties don't change.
withSecond#

(second: number): ZonedDateTime

second
Second of a minute.
returns
New ZonedDateTime with the specified second of a minute. All other properties don't change.
withMs#

(ms: number): ZonedDateTime

ms
Millisecond of a second.
returns
New ZonedDateTime with the specified millisecond of a second. All other properties don't change.
toString#

(): string

returns
String representation of the offset date/time in ISO format, such as "2019-12-30T18:30:15.225+01:00[Europe/Berlin]".

Static methods#

ofInstant#

(instant: Instant, zone: ZoneId): ZonedDateTime

instant
Instant.
zone
Time zone.
returns
New ZonedDateTime representing instant in zone.
ofDateTime#

(localDateTime: LocalDateTime, zone: ZoneId): ZonedDateTime

localDateTime
Local date/time.
zone
Time zone.
returns
New ZonedDateTime representing dateTime in zone.
parse#

(str: string): ZonedDateTime throws TemporalParsingError

str
String representation of offset date/time in ISO format, such as '2019-12-30T18:30:15.225+01:00[Europe/Berlin]'.
returns
ZonedDateTime representation.
compare#

(x: ZonedDateTime, y: ZonedDateTime): number

x
One zoned date/time.
y
Another zoned date/time.
returns
  • 0 if this x and y are the same zoned date/time;
  • positive value if x goes after y;
  • negative value if x goes before y.
The objects are first compared by instant, and then by zone text identifier. Null and undefined are considered less than anything, except each other.
equal#

(x: ZonedDateTime, y: ZonedDateTime): boolean

x
One zoned date/time.
y
Another zoned date/time.
returns
True if x is equal to y, i.e. all components are equal. Null and undefined are only equal to each other.