Immutable date and time library for JavaScript
Introduction
js-joda is an immutable date and time library for JavaScript. It provides a simple, domain-driven and clean API based on the ISO calendar system, which is the de facto world calendar following the proleptic Gregorian rules.
js-joda has a lightweight footprint, only 43 kB minified and compressed, no third party dependencies.
js-joda is fast. It is about 2 to 10 times faster than other JavaScript date libraries.
js-joda comes with built-in parsers/ formatters for ISO 8601 as specified in RFC 3339, that can be easily customized.
js-joda supports ECMAScript 5 browsers down to IE11.
js-joda is a port of the threeten backport, which is the base for JSR-310 implementation of the Java SE 8 java.time package. Threeten is inspired by Joda-Time, having similar concepts and the same author.
js-joda is robust and stable. We ported more then 1700 test-cases with a lots of test-permutations from the threetenbp project. We run the automated karma test-suite against Firefox, Chrome, Node and phantomjs.
Why yet another JavaScript date and time library?
Popular JavaScript date libraries like moment or date-utils are wrappers around the native JavaScript
Date
object, providing syntactic sugar. The nativeDate
object always consist of a date, time and a timezone part. In contrast, js-joda is a standalone date and time implementation.The API has a domain-driven design with classes for each of the different use cases, like
LocalDate
,ZonedDateTime
orPeriod
. For example,LocalDate
allows you to handle dates without times (like birthdays or holidays) in a clean and error-safe way, especially if these dates are persisted to an external server.js-joda is immutable. Immutability aligns well with pure functions and with the architecture of frameworks like React and Flux.
The ThreeTen domain models
Dates and Times
LocalDate represents a date without a time and timezone in the ISO-8601 calendar system, such as 2007-12-24.
LocalTime represents a time without timezone in the ISO-8601 calendar system such as '11:55:00'.
LocalDateTime is a description of the date (LocalDate), as used for birthdays, combined with the local time (LocalTime) as seen on a wall clock.
ZonedDateTime is a date-time with a timezone in the ISO-8601 calendar system, such as 2007-12-24T16:15:30+01:00 UTC+01:00.
Instant is an instantaneous point on the time-line measured from the epoch of 1970-01-01T00:00:00Z in epoch-seconds and nanosecond-of-second.
Duration and Period
Duration is a time-based amount of time, such as '34.5 seconds'.
Period is a date-based amount of time in the ISO-8601 calendar system, such as '2 years, 3 months and 4 days'.
Additional value types
Year represents a year in the ISO-8601 calendar system, such as '2016'.
YearMonth represents a year and a month in the ISO-8601 calendar system, such as '2016-01'.
Month represents a month-of-year in the ISO-8601 calendar system, such as 'July'.
MonthDay represents a month-day in the ISO-8601 calendar system, such as '--12-03'. Could be used to represent e.g. Birthdays.
DayOfWeek represents a day-of-week in the ISO-8601 calendar system, such as 'Tuesday'.
Getting started
Node
Install joda using npm
npm install @js-joda/core
Then require it to any module
var LocalDate = require('@js-joda/core').LocalDate;
var d = LocalDate.parse('2012-12-24').atStartOfDay().plusMonths(2); // 2013-02-24T00:00:00
Browser
To use js-joda from a browser, download js-joda from a cdn (eg https://cdn.jsdelivr.net/npm/@js-joda/core@<version>)
either dist/js-joda.min.js
or dist/js-joda.js
(with sourcemaps for development).
Then add it as a script tag to your page
<script src="js-joda.min.js"></script>
<script>
var LocalDate = JSJoda.LocalDate;
var d = LocalDate.parse('2012-12-24').atStartOfDay().plusMonths(2); // 2013-02-24T00:00:00
</script>
js-joda packages
js-joda consist of four packages:
package name | description | path |
---|---|---|
@js-joda/core |
Implementation of the ThreeTen Classes and API | /packages/core |
@js-joda/timezone |
Implementation of timezone calculation based on the iana Time Zone Database | /packages/timezone |
@js-joda/locale |
Implementation of locale specific functionality for js-joda, especially for formatting and parsing locale specific dates | /packages/locale |
@js-joda/extra |
Implementation of the ThreeTen-Extra Classes and API | /packages/extra |
The @js-joda/examples package is for testing the different build artifacts in different context, like webpack, browser node, etc.
Documentation
- js-joda Quick start guide Quick start guide and examples
- API ESDoc generated API documentation
Contributing
Contributions are always welcome. Before contributing please read the code of conduct & search the issue tracker. We use GitHub issues. Your issue may have already been discussed or fixed. To contribute, fork js-joda, commit your changes, & send a pull request.
By contributing to js-joda, you agree that your contributions will be licensed under its BSD license.
Note that only pull requests and issues that match the threeten backport API will be considered. Additional requested features will be rejected.
License
js-joda
is released under the BSD 3-clause license.js-joda
uses the ThreeTen-Backport implementation (http://www.threeten.org/threetenbp/) as a reference base for implementation. This allows us to release js-joda under the BSD License while the OpenJDK java.time implementation is under GNU GPL+linking exception. The API of the ThreeTen-Backport is mostly identical to the official Java SE 8 API from the view of our JavaScript port.Our implementation reference base ThreeTen-Backport (http://www.threeten.org/threetenbp/) is also released under the BSD 3-clause license
OpenJDK
is under GNU GPL+linking exception.The author of
Joda-Time
and the lead architect of the JSR-310 is Stephen Colebourne.
The API of this project (as far as possible with JavaScript), a lot of implementation details and documentation are just copied but never equalled.
Roadmap
Milestone 1: Core domains (reached with version v1.0.0)
- Support for the domain models
LocalDate
,LocalDateTime
,ZonedDateTime
,Instant
,Duration
andPeriod
converting to and from ISO8601. ZonedDateTime
(without support for loading iana timezone databases) currently supports only fixed offsets like UTC or UTC+02:00 and the system default time zone.
Milestone 2: IANA timezone support (reached with version v1.2.0)
- Add IANA timezone database support to js-joda. Implement handling of daylight saving transitions, mainly in
ZonedDateTime
. - For access to the IANA timezone database, the plugin @js-joda/timezone is required. It provides an implementation of the ZoneRulesProvider and contains the iana timezone database.
Milestone 3: Locale support (reached with v2.0.0 of @js-joda/locale)
- Add locale support.
- Extend pattern parser/ formatter for text with locale support.
see the plugin @js-joda/locale
Future Milestones
- Reduce library size by removing redundant code, especially by refactoring code for formatting/ parsing dates.
- Increase test coverage (ongoing task)
- Cleanup documentation (ongoing task)
Getting started
Node
Install joda using npm
npm install @js-joda/core
Then require it to any module
var LocalDate = require("@js-joda/core").LocalDate;
var d = LocalDate.parse("2012-12-24")
.atStartOfDay()
.plusMonths(2); // 2013-02-24T00:00:00
Browser
To use js-joda from a browser, download either dist/js-joda.min.js or dist/js-joda.js (with sourcemaps for development)
Then add it as a script tag to your page
<script src="js-joda.min.js"></script>
<script>
var LocalDate = JSJoda.LocalDate;
var d = LocalDate.parse('2012-12-24').atStartOfDay().plusMonths(2); // 2013-02-24T00:00:00
</script>
Fiddle around
Fiddle around with js-joda, here on this page in the browser developer console, the latest js-joda code of all packages is always injected into this documentation.
Or find a simple example setup at JSFiddle https://jsfiddle.net/shto0ze6/, but don't forget to update the cdnjs resources to the desired versions.
Usage
The API is immutable. An existing instance is never changed. All manipulating methods (plus
, at
, etc.) return new instances.
An existing instance is always valid. If you try to create an invalid value, you'll get an exception instead of a null
or undefined
value.
Method naming conventions
The API uses consistently named methods.
method name or prefix | usage | examples |
---|---|---|
.of |
static factory method for building by parts | LocalDate.of(2016, 2, 23) LocalDate.ofInstant(i) |
.parse |
static factory method for parsing strings | LocalDate.parse('2016-02-23') LocalTime.parse('12:34') |
.is |
checks for certain conditions | t1.isAfter(t2) d1.isLeapYear() |
.equals |
checks for equivalence between two instances | t1.equals(t2) |
.with |
the immutable equivalent of a setter | d.withDayOfMonth(1) t.withHour(9) |
.plus |
adds an amount to an object | t.plusMinutes(5) d.plus(3, ChronoUnit.YEARS) |
.minus |
subtracts an amount from an object | t.minusHours(1) d.minus(1, ChronoUnit.DAYS) |
.to |
converts this object to another type | dt.toLocalDate() d1.until(d2).toTotalMonths() |
.at |
combines one object with another | date.atTime(time) localDate.atZone(tz) |
Note that getter methods for instance properties omit the get keyword: d.year()
, not .d.getYear()
LocalDate
A LocalDate
represents a date with no time and no time zone in the ISO-8601 calendar system, such as 2007-12-24.
Create a LocalDate
// obtain the current date in the system default time zone, e.g. 2016-02-23
LocalDate.now();
// obtain the current date in the UTC time zone, e.g. 2016-02-23
LocalDate.now(ZoneOffset.UTC);
// obtain an instance of LocalDate from an ISO 8601 formatted text string
LocalDate.parse("2016-02-23");
// obtain an instance of LocalDate from a year, month, and dayOfMonth value
LocalDate.of(2016, 2, 23); // 2016-02-23
// obtain an instance of LocalDate from a year, month, and dayOfMonth value
LocalDate.of(2016, Month.FEBRUARY, 23); // 2016-02-23
// obtain an instance of LocalDate from an epochDay where day 0 is 1970-01-01
LocalDate.ofEpochDay(-1); // 1969-12-31
// obtain an instance of LocalDate from an epochDay where day 0 is 1970-01-01
LocalDate.ofYearDay(2016, 42); // 2016-02-11
Get values from LocalDate
var d = LocalDate.parse("2016-12-24");
d.toString(); // '2016-12-24' ISO 8601 format
d.dayOfMonth(); // 24
d.month(); // Month.DECEMBER
d.monthValue(); // 12
d.year(); // 2016
d.dayOfWeek(); // DayOfWeek.SATURDAY
d.dayOfWeek().value(); // 6
d.dayOfYear(); // 359
d.isLeapYear(); // true - 2016 is a leap year
d.plusYears(1).isLeapYear(); // false
// get the epoch day where 0 is 1970-01-01
d.toEpochDay(); // 17159
// get range of month
d.lengthOfMonth(); // 31
d.range(ChronoField.DAY_OF_MONTH); // ValueRange(1 - 31)
// get range of year
d.lengthOfYear(); // 366
d.range(ChronoField.DAY_OF_YEAR); // ValueRange(1 - 366)
// get other date-based field like the aligned week of year
d.get(ChronoField.ALIGNED_WEEK_OF_YEAR); // 52
// or the day of week aligned to the first day of month
d.get(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH); // 3
Get week of week-based year, quarter of year, day of quarter
// get week of week-based year as defined by ISO 8601, with a Monday-based week
d.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); // 51
d.isoWeekOfWeekyear(); // 51, equivalent to the above
d.isoWeekyear(); // 2016
LocalDate.of(2017, 1, 1).isoWeekOfWeekyear(); // 52
LocalDate.of(2017, 1, 1).isoWeekyear(); // 2016
// set the date to week 52 of week-based year with the same day of week
d.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 52); // 2016-12-31
// get the quarter of the year
d.get(IsoFields.QUARTER_OF_YEAR); // 4
d.get(IsoFields.DAY_OF_QUARTER); // 85
// set the date to the 15th day of the third quarter
d.with(IsoFields.QUARTER_OF_YEAR, 3).with(IsoFields.DAY_OF_QUARTER, 15); // 2016-07-15
Adding to and subtracting from a LocalDate
Note that each of these methods returns a new LocalDate
instance.
var d = LocalDate.parse("2016-02-23");
// add/subtract 366 days
d.plusDays(366); // '2017-02-23'
d.minusDays(366); // '2015-02-22'
// add/subtract 12 months
d.plusMonths(12); // '2017-02-23'
d.minusMonths(12); // '2015-02-23'
// add/subtract 4 weeks
d.plusWeeks(4); // '2016-03-22'
d.minusWeeks(4); // '2016-01-26'
// add/subtract 1 year
d.plusYears(1); // '2017-02-23'
d.minusYears(1); // '2015-02-23'
// add/subtract 30 years
d.plus(3, ChronoUnit.DECADES); // '2046-02-23'
d.minus(3, ChronoUnit.DECADES); // '1986-02-23'
// add/subtract a Period of 3 Months and 3 Days
d.plus(Period.ofMonths(3).plusDays(3)); // '2016-05-26'
d.minus(Period.ofMonths(3).plusDays(3)); // '2015-11-20'
Alter specific fields of a LocalDate
var d = LocalDate.parse("2016-12-24");
// set the day of month to 1
d.withDayOfMonth(1); // '2016-12-01'
// set month and the day of month to 1
d.withMonth(1).withDayOfMonth(1); // '2016-01-01'
// set month to November and the day of month to 1
d.withMonth(Month.NOVEMBER).withDayOfMonth(1); // '2016-11-01'
// set the year to beginning of era
d.withYear(1); // '0001-12-24'
// get the last day of the current month
LocalDate.now()
.plusMonths(1)
.withDayOfMonth(1)
.minusDays(1);
// set the day of year
d.withDayOfYear(42); // 2016-02-11
// set the week of week-based year to 52
d.with(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 52); // 2016-12-31
Compare one LocalDate
with another
var d1 = LocalDate.parse("2016-12-24");
var d2 = d1.plusDays(2);
d1.isAfter(d2); // false
d1.isBefore(d2); // true
d1.equals(d2); // false
d1.equals(d1.plusDays(0)); // true
d1.equals(d1.plusDays(1)); // false
d1.compareTo(d1) === 0; // true
d1.compareTo(d2) < 0; // true
d2.compareTo(d1) > 0; // true
d1.hashCode(); // 4129560
d2.hashCode(); // 4129562
d1.hashCode() !== d2.hashCode(); // true
Distance on the timeline
var d1 = LocalDate.parse("2016-12-24");
var d2 = d1.plusMonths(13).plusDays(42);
// obtain the Period between the two dates
d1.until(d2).toString(); // 'P1Y2M11D' (1 year, 2 months, 11 days in ISO-8601 period format)
d1.until(d2).toTotalMonths(); // 14
// obtain the distance between the two dates with a specific precision
d1.until(d2, ChronoUnit.MONTHS); // 14, returns the distance in total months
d1.until(d2, ChronoUnit.DAYS); // 438, returns the distance in total days
Converting from and to other temporals
// obtain a LocalDate from a LocalDateTime instance
var dt = LocalDateTime.now();
LocalDate.from(dt); // LocalDate from LocalDateTime
dt.toLocalDate(); // LocalDateTime to LocalDate (equivalent to the above)
var d1 = LocalDate.parse("2016-02-25");
// obtain a LocalDateTime at a certain LocalTime
d1.atStartOfDay(); // '2016-02-25T00:00'
d1.atTime(LocalTime.of(11, 55)); // '2016-02-25T11:55'
d1.atTime(LocalTime.NOON); // '2016-02-25T12:00'
// obtain a LocalDate from a JavaScript Date
// the manual way
var d = LocalDate.ofInstant(Instant.ofEpochMilli(new Date().getTime()));
// the recommended way with the JavaScript temporal
d = LocalDate.from(nativeJs(new Date()));
// converting from a moment works the same way
d = LocalDate.from(nativeJs(moment()));
Adjust a date to another date
TemporalAdjusters
provide compact business logic for date-based temporals such as LocalDate
, LocalDateTime
or ZonedDateTime
.
var d = LocalDate.parse("2016-12-24");
// get first/ last day of month
d.with(TemporalAdjusters.firstDayOfMonth()); // 2016-12-01
d.with(TemporalAdjusters.lastDayOfMonth()); // 2016-12-31
// get the next specified weekday
d.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)); // 2016-12-25
d.with(TemporalAdjusters.nextOrSame(DayOfWeek.SATURDAY)); // 2016-12-24
d.with(TemporalAdjusters.next(DayOfWeek.SATURDAY)); // 2016-12-31
// get the first/last weekday of month
d.with(TemporalAdjusters.lastInMonth(DayOfWeek.SATURDAY)); // 2016-12-31
d.with(TemporalAdjusters.firstInMonth(DayOfWeek.SATURDAY)); // 2016-12-03
Find more adjusters in the TemporalAdjusters API documentation.
LocalTime
A LocalTime
represents a time with no date and no time zone in the ISO-8601 calendar system, such as '10:15:30'
Create a LocalTime
instance
// obtain the current time in the system default time zone, e.g. '10:29:05.743'
LocalTime.now();
// obtain the current time in the UTC time zone, e.g. '09:29:05.743'
LocalTime.now(ZoneOffset.UTC);
// obtain an instance of LocalTime from an ISO 8601 formatted text string
LocalTime.parse("09:42"); // '09:42'
LocalTime.parse("09:42:42"); // '09:42:42'
LocalTime.parse("09:42:42.123"); // '09:42:42.123'
LocalTime.parse("09:42:42.123456789"); // '09:42:42.123456789'
// obtain an instance of LocalTime from hour, minute, second, and nanosecond values
LocalTime.of(23, 55); // '23:55'
LocalTime.of(23, 55, 42); // '23:55:42'
LocalTime.of(23, 55, 42, 123000000); // '23:55:42.123'
// obtain an instance of LocalTime from second of day
LocalTime.ofSecondOfDay(3666); // '01:01:06'
Get values from LocalTime
var t = LocalTime.parse("23:55:42.123");
t.toString(); // '23:55:42.123' ISO 8601 format
t.hour(); // 23
t.minute(); // 55
t.second(); // 42
t.nano(); // 123000000
// get other time-based fields
t.get(ChronoField.SECOND_OF_DAY); // 86142
t.get(ChronoField.MILLI_OF_SECOND); // 123
t.get(ChronoField.HOUR_OF_AMPM); // 11
// any other time-based ChronoField is allowed as param for get
Adding to/ subtracting from a LocalTime
instance
var t = LocalTime.parse("11:55:42");
// add/subtract 12 hours
t.plusHours(12); // '23:55:42'
t.minusHours(12); // '23:55:42'
// add/subtract 30 minutes
t.plusMinutes(30); // '12:25:42'
t.minusMinutes(30); // '11:25:42'
// add/subtract 30 seconds
t.plusSeconds(30); // '11:56:12'
t.minusSeconds(30); // '11:55:12'
// add/subtract 1 million nanoseconds (1 millisecond)
t.plusNanos(1000000); // '11:56:42.001'
t.minusNanos(1000000); // '11:55:41.999'
// add/subtract a time-based unit
t.plus(1, ChronoUnit.MILLIS); // '11:55:42.001'
t.plus(1, ChronoUnit.HALF_DAYS); // '23:55:42'
// add/subtract a duration of 15 minutes
t.plus(Duration.ofMinutes(15)); // '12:10:42'
t.minus(Duration.ofMinutes(15)); // '11:40:42'
Alter specific fields of a LocalTime
instance
var t = LocalTime.parse("11:55:42");
// set the hour of day to 1
t.withHour(1); // '01:55:42'
// set the minute of hour to 1
t.withMinute(1); // '11:01:42'
// set the second of minute to 1
t.withSecond(1); // '11:55:01'
// set the MILLI_OF_SECOND to 51
t.with(ChronoField.MILLI_OF_SECOND, 51); // '11:55:42.051'
// set by a custom TemporalAdjusters
// sample of a custom adjuster that adjust to the next even second
nextEvenSecond = {
adjustInto: function(t) {
return t.second() % 2 === 0 ? t.plusSeconds(2) : t.plusSeconds(1);
}
};
t.with(nextEvenSecond); // '11:55:44'
t.plusSeconds(1).with(nextEvenSecond); // '11:55:44'
Truncate a LocalTime
instance
var t = LocalTime.parse("23:55:42.123");
t.truncatedTo(ChronoUnit.SECONDS); // '23:55:42'
t.truncatedTo(ChronoUnit.MINUTES); // '23:55:00'
t.truncatedTo(ChronoUnit.HOURS); // '23:00'
t.truncatedTo(ChronoUnit.HALF_DAYS); // '12:00'
t.truncatedTo(ChronoUnit.DAYS); // '00:00'
Compare LocalTime
instances
var t1 = LocalTime.parse("11:55:42");
var t2 = t1.plusHours(2);
t1.isAfter(t2); // false
t1.isBefore(t2); // true
t1.equals(t1.plusHours(0)); // true
t1.equals(t1.plusHours(1)); // false
t1.compareTo(t1) === 0; // true
t1.compareTo(t2) < 0; // true
t2.compareTo(t1) > 0; // true
t1.hashCode(); // 916974646
t2.hashCode(); // -1743180648
t1.hashCode() !== t2.hashCode(); // true
Distance between times
var t1 = LocalTime.parse("11:00");
var t2 = t1
.plusHours(2)
.plusMinutes(42)
.plusSeconds(12);
// obtain the duration between the two dates
t1.until(t2, ChronoUnit.HOURS); // 2
t1.until(t2, ChronoUnit.MINUTES); // 162
t1.until(t2, ChronoUnit.SECONDS); // 9732
Convert a LocalTime
from a moment
or JavaScript Date
// obtain a LocalTime instance from a JavaScript Date
// the manual way
var t = LocalTime.ofInstant(Instant.ofEpochMilli(new Date().getTime()));
// the recommended way with the JavaScript temporal
t = LocalTime.from(nativeJs(new Date()));
// converting from a `moment` instance works the same way
d = LocalTime.from(nativeJs(moment()));
LocalDateTime
A LocalDateTime represents a date-time with no time zone in the ISO-8601 calendar system, such as '2007-12-03T10:15:30'.
Create a LocalDateTime
instance
// obtain the current date and time in the system default time zone, e.g. '2016-02-26T10:29:05.743'
LocalDateTime.now();
// obtain the current date and time in the UTC time zone
LocalDateTime.now(ZoneOffset.UTC);
// obtain an instance of LocalDateTime from an ISO 8601 formatted text string
LocalDateTime.parse("2016-02-26T09:42"); // '2016-02-26T09:42'
LocalDateTime.parse("2016-02-26T09:42:42.123"); // '2016-02-26T09:42:42.123'
// obtain an instance of LocalDateTime from year, month, dayOfMonth, hour, minute, second and nanosecond values
LocalDateTime.of(2016, 2, 29); // '2016-02-29T00:00'
LocalDateTime.of(2016, 2, 29, 12, 55, 42); // '2016-02-29T12:55:42'
LocalDateTime.of(2016, 2, 29, 12, 55, 42, 9); // '2016-02-29T12:55:42.000000009'
// obtain an instance of LocalDateTime from epoch seconds and a ZoneOffset
LocalDateTime.ofEpochSecond(0, ZoneOffset.UTC); // '1970-01-01T00:00'
LocalDateTime.ofInstant(Instant.now()); // current local date-time
LocalDateTime.ofInstant(Instant.now(), ZoneOffset.UTC); // current local UTC date-time
Get values from LocalDateTime
var dt = LocalDateTime.parse("2016-02-26T23:55:42.123");
dt.toString(); // '2016-02-26T23:55:42.123' ISO 8601 format
dt.year(); // 2016
dt.month(); // Month.FEBRUARY
dt.monthValue(); // 2
dt.dayOfMonth(); // 26
dt.hour(); // 23
dt.minute(); // 55
dt.second(); // 42
dt.nano(); // 123000000
dt.dayOfWeek(); // DayOfWeek.FRIDAY
dt.dayOfWeek().value(); // 5
dt.dayOfYear(); // 57
dt.toLocalDate().isLeapYear(); // true 2016 is a leap year
// obtain the date and time components of the LocalDateTime
dt.toLocalDate();
dt.toLocalTime();
// get range of month
dt.toLocalDate().lengthOfMonth(); // 29
dt.range(ChronoField.DAY_OF_MONTH); // ValueRange(1 - 29)
// get range of year
dt.toLocalDate().lengthOfYear(); // 366
dt.range(ChronoField.DAY_OF_YEAR); // ValueRange(1 - 366)
// get other date-based fields like the aligned week of year
dt.get(ChronoField.ALIGNED_WEEK_OF_YEAR); // 9
// get week of week-based year
dt.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR); // 8
dt.toLocalDate().isoWeekOfWeekyear();
// get other time-based fields
dt.get(ChronoField.SECOND_OF_DAY); // 86142
dt.get(ChronoField.MILLI_OF_SECOND); // 123
dt.get(ChronoField.HOUR_OF_AMPM); // 11
// any other date or time-based ChronoField can be passed to `get`
Adding to and subtracting from a LocalDateTime
instance
var dt = LocalDateTime.parse("2016-02-26T23:55:42.123");
// add/subtract 366 days
dt.plusDays(366); // '2017-02-26T23:55:42.123'
dt.minusDays(366); // '2015-02-25T23:55:42.123'
// add/subtract 12 months
dt.plusMonths(12); // '2017-02-26'
dt.minusMonths(12); // '2015-02-26'
// add/subtract 4 weeks
dt.plusWeeks(4); // '2016-03-25T23:55:42.123'
dt.minusWeeks(4); // '2016-01-29T23:55:42.123'
// add/subtract 1 year to the parsed LocalDate and returns a new instance
dt.plusYears(1); // '2017-02-26T23:55:42.123'
dt.minusYears(1); // '2015-02-26T23:55:42.123'
// add/subtract 30 years
dt.plus(3, ChronoUnit.DECADES); // '2046-02-26T23:55:42.123'
dt.minus(3, ChronoUnit.DECADES); // '1986-02-26T23:55:42.123'
// add subtract a Period of 3 Months and 3 Days
dt.plus(Period.ofMonths(3).plusDays(3)); // '2016-05-29T23:55:42.123'
dt.minus(Period.ofMonths(3).plusDays(3)); // '2015-11-23T23:55:42.123'
// add/subtract 12 hours
dt.plusHours(12); // '2016-02-27T11:55:42.123'
dt.minusHours(12); // '2016-02-26T11:55:42.123'
// add/subtract 30 minutes
dt.plusMinutes(30); // '2016-02-27T00:25:42.123'
dt.minusMinutes(30); // '2016-02-26T23:25:42.123'
// add/subtract 30 seconds
dt.plusSeconds(30); // '2016-02-26T23:56:12.123'
dt.minusSeconds(30); // '2016-02-26T23:55:12.123'
// add/subtract 1 million nanoseconds (1 millisecond)
dt.plusNanos(1000000); // '2016-02-26T23:55:42.124'
dt.minusNanos(1000000); // '2016-02-26T23:55:42.122'
// add/subtract a time-based unit
dt.plus(1, ChronoUnit.MILLIS); // '2016-02-26T23:55:42.124'
dt.plus(1, ChronoUnit.HALF_DAYS); // '2016-02-26T11:55:42.123'
// add/subtract a duration of 30 hours and 45 minutes
dt.plus(Duration.ofHours(30).plusMinutes(45)); // '2016-02-28T06:40:42.123'
dt.minus(Duration.ofHours(30).plusMinutes(45)); // '2016-02-25T17:10:42.123'
Alter specific fields of a LocalDateTime
instance
var dt = LocalDateTime.parse("2016-02-26T23:55:42.123");
// set the hour of day to 1
dt.withHour(1); // '2016-02-26T01:55:42.123'
// set the minute of hour to 1
dt.withMinute(1); // '2016-02-26T23:01:42.123'
// set the second of minute to 1
dt.withSecond(1); // '2016-02-26T23:55:01.123'
// set the nanosecond of second to 1
dt.withNano(0); // '2016-02-26T23:55:42'
// set the millisecond of second to 51
dt.with(ChronoField.MILLI_OF_SECOND, 51); // '2016-02-26T23:55:42.051'
// set by a custom TemporalAdjuster that adjusts to the next even second
var nextEvenSecond = {
adjustInto: function(t) {
return t.second() % 2 === 0 ? t.plusSeconds(2) : t.plusSeconds(1);
}
};
dt.with(nextEvenSecond); // '2016-02-26T23:55:44.123'
dt.plusSeconds(1).with(nextEvenSecond); // '2016-02-26T23:55:44.123'
Truncate a LocalDateTime
instance
var dt = LocalDateTime.parse("2016-02-26T23:55:42.123");
dt.truncatedTo(ChronoUnit.SECONDS); // '2016-02-26T23:55:42'
dt.truncatedTo(ChronoUnit.MINUTES); // '2016-02-26T23:55:00'
dt.truncatedTo(ChronoUnit.HOURS); // '2016-02-26T23:00'
dt.truncatedTo(ChronoUnit.HALF_DAYS); // '2016-02-26T12:00'
dt.truncatedTo(ChronoUnit.DAYS); // '2016-02-26T00:00'
Compare LocalDateTime
instances
var dt1 = LocalDateTime.parse("2016-02-26T23:55:42.123");
var dt2 = dt1.plusHours(2);
dt1.isAfter(dt2); // false
dt1.isBefore(dt2); // true
dt1.equals(dt1.plusHours(0)); // true
dt1.equals(dt1.plusHours(1)); // false
dt1.compareTo(dt1) === 0; // true
dt1.compareTo(dt2) < 0; // true
dt2.compareTo(dt1) > 0; // true
// Warn! hashCode is equal if in instances are equal, but might be equal for unequal instances as well
dt1.hashCode(); // -2036645668
dt2.hashCode(); // 1459191821
dt1.hashCode() !== dt2.hashCode(); // true
Distance between two LocalDateTime
instances
var dt1 = LocalDateTime.parse("2016-02-26T23:55:42.123");
var dt2 = dt1
.plusYears(6)
.plusMonths(12)
.plusHours(2)
.plusMinutes(42)
.plusSeconds(12);
// obtain the duration between the two dates
dt1.until(dt2, ChronoUnit.YEARS); // 7
dt1.until(dt2, ChronoUnit.MONTHS); // 84
dt1.until(dt2, ChronoUnit.WEEKS); // 356
dt1.until(dt2, ChronoUnit.DAYS); // 2557
dt1.until(dt2, ChronoUnit.HOURS); // 61370
dt1.until(dt2, ChronoUnit.MINUTES); // 3682242
dt1.until(dt2, ChronoUnit.SECONDS); // 220934532
Convert from a moment
or JavaScript Date
// obtain a LocalDateTime instance from a JavaScript Date
// the manual way
var t = LocalDateTime.ofInstant(Instant.ofEpochMilli(new Date().getTime()));
// the recommended way with the JavaScript temporal
t = LocalDateTime.from(nativeJs(new Date()));
// converting from a moment works the same way
d = LocalDateTime.from(nativeJs(moment()));
ZonedDateTime
A ZonedDateTime
represents a date-time with a time offset and/or a time zone in the ISO-8601 calendar system.
On its own, ZonedDateTime
only supports specifying time offsets such as UTC
or UTC+02:00
, plus the SYSTEM
time zone ID.
The SYSTEM
zone ID
The SYSTEM
zone ID is a non-standard ID that is specific to js-joda
. It represents the default time zone of the current JavaScript runtime. The JavaScript spec does not provide an API this; it only provides the system default time offset for a point in the timeline (Date.prototype.getTimezoneOffset()
).
You should not exchange ZonedDateTime
instances using the SYSTEM
zone ID between JavaScript environments (e.g. between server and client, or between two servers). The time offset on another machine won't necessarily be the same as yours. Before sending a ZonedDateTime
to someone else, convert it to a fixed offset:
// current time with default `SYSTEM`
ZonedDateTime.now().toString(); // e.g. 2016-03-18T12:38:23.561+01:00[SYSTEM]
// converted to a fixed time offset
ZonedDateTime.now()
.withFixedOffsetZone()
.toString(); // e.g. 2016-03-18T12:38:23.561+01:00
Working with time zones
A time zone and a time offset are not the same thing. Some timezones change from standard time to daylight savings time and back every year:
- In the
Europe/Berlin
time zone, the time offset isUTC+2
during the summer, andUTC+1
during the rest of the year. - In the
Africa/Lagos
time zone, on the other hand, the time offset isUTC+1
all year round.
Calculations that might span time zones or daylight savings transitions need to reference the time zone, not just the offset.
The @js-joda/timezone package provides bindings to the the IANA tz database, making joda-js
's calculations time zone aware. The tz
database uses zone names like Africa/Bujumbura
, America/New_York
, and Europe/Lisbon
(see the full list).
To specify time zones using these names, you just need to require
@js-joda/timezone.
var jsJoda = require("@js-joda/core");
require("@js-joda/timezone");
var zdt = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
Create a ZonedDateTime
// get now with the default system time zone
ZonedDateTime.now().toString(); // e.g. 2016-03-18T12:38:23.561+01:00[SYSTEM]
// get now with the UTC time zone
ZonedDateTime.now(ZoneOffset.UTC).toString(); // e.g. 2016-03-18T11:38:23.561Z
// get now with a fixed offset time zone
ZonedDateTime.now(ZoneId.of("UTC-05:00")).toString(); // e.g. 2016-03-18T06:38:23.561-05:00[UTC-05:00]
// get now with a ZoneRegion (requires `@js-joda/timezone`)
ZonedDateTime.now(ZoneId.of("Europe/Paris")).toString(); // e.g. 2017-02-04T17:01:15.846+01:00[Europe/Paris]
// parse a date time with a time zone ISO String
ZonedDateTime.parse("2016-03-18T12:38:23.561+01:00[SYSTEM]");
ZonedDateTime.parse("2016-03-18T12:38:23.561+01:00");
ZonedDateTime.parse("2016-03-18T11:38:23.561Z");
ZonedDateTime.parse("2016-03-18T06:38:23.561-05:00[UTC-05:00]");
ZonedDateTime.parse("2017-02-04T17:01:15.846+01:00[Europe/Paris]");
// create from a LocalDate(Time) (requires `@js-joda/timezone`)
LocalDate.parse("2012-06-06")
.atStartOfDay()
.atZone(ZoneId.of("Europe/Paris")); // 2012-06-06T00:00+02:00[Europe/Paris]
ZonedDateTime.of(
LocalDateTime.parse("2012-06-06T00:00"),
ZoneId.of("Europe/Paris")
); // 2012-06-06T00:00+02:00[Europe/Paris]
ZonedDateTime.of(
LocalDate.parse("2012-06-06"),
LocalTime.MIDNIGHT,
ZoneId.of("Europe/Paris")
); // 2012-06-06T00:00+02:00[Europe/Paris]
// create from an Instant
ZonedDateTime.ofInstant(Instant.now(), ZoneId.SYSTEM); // current system time
Switch time zones
These examples require
@js-joda/timezone
.
var d = LocalDate.of(2016, 3, 18);
var zdt = d.atTime(LocalTime.NOON).atZone(ZoneId.of("America/New_York")); //2016-03-18T12:00-04:00[America/New_York]
// switch time zone retaining the local date-time if possible
zdt.withZoneSameLocal(ZoneId.of("Europe/Berlin")); // 2016-03-18T12:00+01:00[Europe/Berlin]
// switch time zone and retain the instant
zdt.withZoneSameInstant(ZoneId.of("Europe/Berlin")); // 2016-03-18T17:00+01:00[Europe/Berlin]
Get and manipulate values from a ZonedDateTime
ZonedDateTime
implements the same methods as LocalDateTime
for getting or setting values. See the examples above for LocalDateTime
.
Calculate values across daylight savings transitions
When adding to or subtracting from a ZonedDateTime
instance, the calculation is different depending on whether date or time units are passed.
- Addition/subtraction of date units are made on the local timeline.
- Addition/subtraction of time units are made on the instant timeline.
This example shows the difference for a daylight saving transition.
// assume the system default time zone is CET; we define a time as 2016-03-18 at 17:00 local time
var zdt = ZonedDateTime.parse("2016-03-18T17:00+01:00[Europe/Berlin]");
// adding a date unit of 2 weeks, crossing a daylight saving transition
zdt.plusWeeks(2); // 2016-04-01T17:00+02:00[Europe/Berlin] (still 17:00)
// adding a time unit of 2 weeks (2 * 7 * 24)
zdt.plusHours(2 * 7 * 24); // 2016-04-01T18:00+02:00[Europe/Berlin] (now 18:00)
Period
Period
is a date-based amount of time in the ISO-8601 calendar system, such as '2 years, 3 months and 4 days'.
// parse and format ISO 8601 period strings
Period.parse("P1Y10M").toString(); // 'P1Y10M'
// obtain a Period of 10 years, 5 month and 30 days
Period.of(10, 5, 30).toString(); // 'P10Y5M30D'
// 10 years
Period.ofYears(10).toString(); // 'P10Y'
// add 45 days to a Period
Period.ofYears(10)
.plusDays(45)
.toString(); // 'P10Y45D'
// normalize a Period of years and month
Period.of(1, 37, 0)
.normalized()
.toString(); // 'P4Y1M'
// add/subtract from a Period
Period.ofYears(10)
.plusMonths(10)
.minusDays(42)
.toString(); // 'P10Y10M-42D'
// add a Period to LocalDate
var p = Period.ofMonths(1);
LocalDate.parse("2012-12-12").plus(p); // '2013-01-12';
LocalDate.parse("2012-01-31").plus(p); // '2012-02-29';
LocalDateTime.parse("2012-05-31T12:00").plus(p); // '2012-06-30T12:00';
// calculate the Period between two Dates
Period.between(LocalDate.parse("2012-06-30"), LocalDate.parse("2012-08-31")); // 'P2M1D'
Duration
Duration
is a time-based amount of time, such as '34.5 seconds'.
// obtain a Duration of 10 hours
Duration.ofHours(10).toString(); // 'PT10H'
// obtain a Duration of 10 days (10 x 24 hours)
Duration.ofDays(10).toString(); // 'PT240H'
// add/subtract a duration from a LocalDateTime
var dt = LocalDateTime.parse("2012-12-24T12:00");
dt.plus(Duration.ofHours(10).plusMinutes(30)).toString(); // '2012-12-24T22:30'
dt.minus(Duration.ofHours(12).multipliedBy(10)).toString(); // '2012-12-19T12:00'
// calculate the duration between two time-based values
var dt1 = LocalDateTime.parse("2012-12-24T12:00");
Duration.between(dt1, dt1.plusHours(10)).toString(); // 'PT10H'
Instant
An Instant
is an instantaneous point on the time-line measured from the epoch of 1970-01-01T00:00:00Z in epoch-seconds and nanosecond-of-second.
Create an Instant
// Obtain the current instant from the system clock
Instant.now();
// Obtain an instance of Instant using microseconds from the epoch of 1970-01-01T00:00:00Z. In this example, the Saturday, August 12, 2023 2:57:21 PM GMT
Instant.ofEpochMicro(1691852241000000);
// Obtain an instance of Instant using milliseconds from the epoch of 1970-01-01T00:00:00Z. In this example, the Saturday, August 12, 2023 2:57:21 PM GMT
Instant.ofEpochMilli(1691852241000);
// Obtain an instance of Instant using milliseconds from a JavaScript Date object
Instant.ofEpochMilli(new Date().getTime());
// Obtain an instance of Instant using milliseconds from the epoch of 1970-01-01T00:00:00Z
Instant.ofEpochSecond(1691926326);
// Obtain an instance of Instant from a text string such as 2007-12-03T10:15:30.000Z.
Instant.parse('2007-12-03T10:15:30.000Z');
Parsing and converting an Instant
var ins = Instant.parse('2007-12-03T10:15:30.000Z')
ins.toString(); // '2007-12-03T10:15:30Z'
ins.epochSecond(); // 1196676930
ins.toEpochMilli(); // 1196676930000
ins.atOffset(ZoneOffset.ofHours(1)); // '2007-12-03T11:15:30+01:00' returns an OffsetDateTime instance
ins.atZone(ZoneId.UTC); // '2007-12-03T10:15:30Z' returns a ZonedDateTime instance
Adding to and subtracting from an Instant
Note that each of these methods returns a new Instant
instance.
var ins = Instant.parse('2007-12-03T10:15:30.000Z') // 1196676930 in epoch seconds
// add/subtract seconds
ins.plusSeconds(1); // 1196676931 or '2007-12-03T10:15:31.000Z'
ins.minusSeconds(1); // 1196676929 or '2007-12-03T10:15:29.000Z'
// add/subtract milliseconds
ins.plusMillis(1); // '2007-12-03T10:15:30.001Z'
ins.minusMillis(1); // '2007-12-03T10:15:29.999Z'
// add/subtract microseconds
ins.plusMicros(1); // '2007-12-03T10:15:30.000001Z'
ins.minusMicros(1); // '2007-12-03T10:15:29.999999Z'
Formatting / Parsing
Formatting
To format a date and/or time, create a DateTimeFormatter
and pass it to the .format
method of a LocalDate
, LocalTime
, LocalDateTime
, or ZonedDateTime
instance.
js-joda built-in DateTimeFormatter parses and formats dates and times from /to ISO 8601 as specified in RFC 3339.
const d = LocalDateTime.parse('2018-04-28T12:34')
d.format(DateTimeFormatter.ofPattern('M/d/yyyy')) // 4/28/2018
d.format(DateTimeFormatter.ofPattern('HH:mm')) // 12:34
Formatting with locales
Non-numeric date and time formats need to know what language to use, for things like names of months and days of the week. For example, the format eeee (d MMMM)
might return Saturday (28 April)
in English, and samedi (28 avril)
in French. If you try to use a locale-dependent format pattern without specifying the locale, you'll get this error message:
ERROR: Pattern using (localized) text not implemented, use @js-joda/locale plugin!
To specify a locale, you'll need to import the @js-joda/timezone
and @js-joda/locale
plugins. The simplest way to use @js-joda/locale
is to install one of the locale-specific builds from npm:
- @js-joda/locale_de
- @js-joda/locale_de-de
- @js-joda/locale_en
- @js-joda/locale_en-us
- @js-joda/locale_es
- @js-joda/locale_fi
- @js-joda/locale_fi-fi
- @js-joda/locale_fr
- @js-joda/locale_hi
- @js-joda/locale_it
- @js-joda/locale_it-it
- @js-joda/locale_zh
You can then use localized format strings as follows.
import '@js-joda/timezone' // Just needs to be imported; registers itself automatically
import { Locale } from '@js-joda/locale_fr' // Get `Locale` from the prebuilt package of your choice
import { DateTimeFormatter, LocalDateTime } from 'js-joda'
const d = LocalDateTime.parse('2018-04-28T12:34')
const formatter = DateTimeFormatter
.ofPattern('eeee (d MMMM)')
.withLocale(Locale.FRANCE)
d.format(formatter) // samedi (28 avril)
Note: If internationalization is an important aspect of your application, you might consider using the standard Intl.DateTimeFormat
API instead. It is built into modern browsers, supports a comprehensive set of locales, and handles a lot of internationalization subtleties that go beyond the scope of this library. To do this, you would need to convert your js-joda
dates and times to JavaScript Date
objects just before outputting them:
const ldt = LocalDateTime.parse('2018-04-28T12:34')
const jsDate = convert(ldt).toDate() // Convert to JavaScript `Date` object
var options = {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: '2-digit'
}
jsDate.toLocaleDateString('en-US', options) // Saturday, April 28, 2018, 12:34 PM
jsDate.toLocaleDateString('de-DE', options) // Samstag, 28. April 2018, 12:34
jsDate.toLocaleDateString('ar-EG', options) // السبت، ٢٨ أبريل ٢٠١٨ ١٢:٣٤ م
jsDate.toLocaleDateString('ko-KR', options) // 2018년 4월 28일 토요일 오후 12:34
Format patterns
Date and time formats are based on the pattern strings from Java DateTimeFormatter.
Symbol | Meaning | Presentation | Examples |
---|---|---|---|
G | era | number/text | 1; 01; AD; Anno Domini |
u | year | year | 2004; 04 |
y | year-of-era | year | 2004; 04 |
D | day-of-year | number | 189 |
M/L | month-of-year | number/text | 7; 07; Jul; July; J |
d | day-of-month | number | 10 |
Q/q | quarter-of-year | number/text | 3; 03; Q3; 3rd quarter; 3 |
Y | week-based-year | year | 1996; 96 |
w | week-of-year | number | 27 |
W | week-of-month | number | 4 |
E | day-of-week | text | Tue; Tuesday; T |
e/c | localized day-of-week | number | 2; 02; Tue; Tuesday; T |
F | day-of-week-in-month | number | 3 |
a | am-pm-of-day | text | PM |
h | clock-hour-of-am-pm (1-12) | number | 12 |
K | hour-of-am-pm (0-11) | number | 0 |
k | clock-hour-of-day (1-24) | number | 24 |
H | hour-of-day (0-23) | number | 0 |
m | minute-of-hour | number | 30 |
s | second-of-minute | number | 55 |
S | fraction-of-second | fraction | 978 |
A | milli-of-day | number | 1234 |
n | nano-of-second | number | 987654321 |
N | nano-of-day | number | 1234000000 |
V | time-zone ID | zone-id | America/Los_Angeles; Z; -08:30 |
z | time-zone name | zone-name | Pacific Standard Time; PST |
O | localized zone-offset | offset-O | GMT; GMT-8; GMT+6 |
X | zone-offset 'Z' for zero | offset-X | Z; -08; -0830; -08:30; -083015; -08:30:15 |
x | zone-offset | offset-x | +0000; -08; -0830; -08:30; -083015; -08:30:15 |
Z | zone-offset | offset-Z | +0000; -0800; -08:00 |
p | pad next | pad modifier | 1 |
' | escape for text | delimiter | |
'' | single quote | literal | ' |
[ | optional section start | ||
] | optional section end | ||
{} | reserved for future use |
The patterns g
, B
and v
from Java are not available in js-joda
Parsing
Parsing is similar to formatting, the same DateTimeFormatter pattern are used as for formatting.
Customized parser can be build with the DateTimeFormatter
.
Simple parser example
import { DateTimeFormatter, LocalDate } from '@js-joda/core';
const formatter = DateTimeFormatter.ofPattern('M/d/yyyy');
const date = LocalDate.parse('4/28/2018', formatter);
console.log(date.toString()); // 2018-04-28
http date parser example
Example for an HTTP dates formatter as specified in RFC 7321,
like returned by javascript native Date
toUTCString
method.
This formatter requires the @js-joda/locale
package.
This formatter is built-in since @js-joda/locale@4.2.0 -> RFC_1123_DATE_TIME
import { DateTimeFormatter, ZonedDateTime } from '@js-joda/core';
import '@js-joda/timezone'
import { Locale } from '@js-joda/locale';
const df = DateTimeFormatter.ofPattern('EEE, dd MMM yyyy HH:mm:ss z').withLocale(Locale.ENGLISH);
const z = ZonedDateTime.parse('Tue, 05 Oct 2021 17:08:24 GMT', df);
console.log(z.toString()); // 2021-10-05T17:08:24+01:00[GMT]
Built-in DateTimeFormatter
Formatter | Example |
---|---|
ISO_LOCAL_DATE | '2011-12-03' |
ISO_LOCAL_TIME | '10:15:30' |
ISO_LOCAL_DATE_TIME | '2011-12-03T10:15:30' |
ISO_INSTANT | '2011-12-03T10:15:30Z' |
ISO_OFFSET_DATE_TIME | '2011-12-03T10:15:30+01:00' |
ISO_ZONED_DATE_TIME | '2011-12-03T10:15:30+01:00[Europe/Paris]' |
BASIC_ISO_DATE | '20111203' |
ISO_OFFSET_DATE | '2011-12-03+01:00' |
ISO_OFFSET_TIME | '10:15:30+01:00' |
ISO_ORDINAL_DATE | '2012-337' |
ISO_WEEK_DATE | '2012-W48-6' |
ISO_DATE | '2011-12-03+01:00', '2011-12-03' |
ISO_TIME | '10:15:30+01:00', '10:15:30' |
ISO_DATE_TIME | '2011-12-03T10:15:30+01:00' |
RFC_1123_DATE_TIME | 'Tue, 05 Oct 2021 17:08:24 GMT' requires @js-joda/locale |
Usage example for a built-in DateTimeFormatter
const localDate = LocalDate.parse('2012-12-12', DateTimeFormatter.ISO_LOCAL_DATE);
const dateAsString = LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE);
Hint
Whenever you stumble over a Cannot read property 'localeString' of null
error,
its probably because the locale of the formatter is not set.
In that case add the @js-joda/locale
package to your project and set the locale
of the formatter, eg DateTimeFormatter.ofPattern('eeee (d MMMM)').withLocale(Locale.FRANCE)
.
Using locale package
Motivation
Implementation of locale specific functionality for js-joda, providing function not implemented in js-joda core
Especially this implements patterns elements to print and parse locale specific dates.
Node
In a node environment, the best choice is to install @js-joda/locale
and
the cldr data cldr-data
separately. With that you have support for all locales defined in the cldr project.
The timezone package is required as soon as timezone locales come into play.
npm install @js-joda/core
npm install @js-joda/timezone
npm install cldr-data
npm install cldrjs
npm install @js-joda/locale
Browser
In a browser environment, to save space, the better choice is to install one of the pre-built packages for a certain language. The pre-built packages contain the implementation and all cldr data required for that specific locale.
For more information check the README.md in the locale package.
npm install @js-joda/locale_en
npm install @js-joda/timezone
Usage
const {
DateTimeFormatter,
ZonedDateTime,
ZoneId,
} = require('@js-joda/core');
require('@js-joda/timezone');
const {
Locale,
} = require('@js-joda/locale_en-us');
var zdt = ZonedDateTime.of(2016, 1, 1, 0, 0, 0, 0, ZoneId.of('Europe/Berlin'));
console.log('en_US formatted string:',
zdt.format(
DateTimeFormatter
.ofPattern('eeee MMMM dd yyyy GGGG, hh:mm:ss a zzzz, \'Week \' ww, \'Quarter \' QQQ')
.withLocale(Locale.US)));
this will output en_US formatted string: Friday January 01 2016 Anno Domini, 12:00:00 AM Central European Time, Week 01, Quarter Q1
Links
For more information check the README.md in the locale package.
Customizing js-joda
This package is extensible, allowing you to create your own custom temporal calculations. See the temporal interface documentation for more information.
Custom temporal adjuster
// implement a TemporalAdjuster that the next or same even day of month
var nextOrSameEvenDay = {
adjustInto: function(t) {
return t.dayOfMonth() % 2 === 0 ? t : t.plusDays(1);
}
};
LocalDateTime.parse("2012-12-23T12:00").with(nextOrSameEvenDay); // '2012-12-24T12:00'
LocalDate.parse("2012-12-24").with(nextOrSameEvenDay); // '2012-12-24'
Custom temporal fields and temporal units
See the source for temporal/IsoFields as an example how to implement custom fields and units. IsoFields
implements fields and units for an ISO week-based year.
Custom formatter and queries
The following example implements a parser for a local date with an optional local time. It returns either a LocalDate
or a LocalDateTime
, depending on the parsed fields.
// build a custom date time formatter where the time field is optional
var OPTIONAL_FORMATTER = DateTimeFormatter.ofPattern(
'yyyy-MM-dd['T'HH:mm[:ss]]'
);
// create a temporal query that create a new Temporal depending on the existing fields
dateOrDateTimeQuery = {
queryFrom: function(temporal) {
var date = temporal.query(TemporalQueries.localDate());
var time = temporal.query(TemporalQueries.localTime());
if (time == null) return date;
else return date.atTime(time);
}
};
localDate = OPTIONAL_FORMATTER.parse('2012-12-24', dateOrDateTimeQuery);
localDateTime = OPTIONAL_FORMATTER.parse(
'2012-12-24T23:59',
dateOrDateTimeQuery
);
Convert from/ to native js
Convert from Date to a js-joda temporal
use method nativeJs
to convert from native javascript Date
to a js-joda ZonedDateTime
.
Hint: nativeJs
accepts moment
objects as well.
Be aware of that a Date always represent a certain point in time without a timezone.
You can provide one by passing it as a second argument.
Otherwise, ZoneId.systemDefault()
will be used.
import { ZonedDateTime, nativeJs } from '@js-joda/core';
const zonedDateTime = nativeJs(new Date());
// or with momentjs object
const zonedDateTime = nativeJs(moment());
Convert from js-joda temporal to a Date
Use method convert
to convert a LocalDate
| LocalDateTime
| ZonedDateTime
| Instant
to javascript Date
.
const date = convert(Instant.now()).toDate();