DateTime

About

This class is inspired by one of the most popular JavaScript date packages, dayjsopen in new window. 🚀

DateTime lets you create an object that represents a single point in time with millisecond precision between midnight on January 1st, 0 CE, and 23:59:59.999 on December 31st, 9999 CE.

Once you have a DateTime, you can:

  • Add or subtract days and/or time
  • Compare it with another DateTime
  • Convert it to another timezone
  • Convert it to/from UTC or local time
  • Format it as a localized string with total flexibility

Instances of DateTime are immutable. All functions that would change the value of a DateTime return a new DateTime instance.

IMPORTANT

Do not attempt to save DateTime objects or JSON stringified objects to the database or pass them to remote machines, since they may be read later by a machine in a different timezone.

Instead, serialize them to a UTC string using .timestamp and then deserialize them by passing the timestamp to the DateTime constructor.

Timezone mode

Internally DateTime is stored as UTC, along with:

  • The offset from UTC at the moment represented by the DateTime
  • The timezone abbreviation
  • The timezone name

DateTime is always created in local mode, meaning that all functions that retrieve or display values operate in the local timezone. If you wish to retrieve or display UTC values, you can switch to UTC mode with .utc property, and back to local mode with the .local property.

// 2022-08-27T20:13:27.123-07:00 in PDT
// 2022-08-28T03:13:27.123Z in UTC
$dt:=cs.js.DateTime.new(!08/27/22!; ?20:13:27?; 123)

$date:=$dt.date     // 2022-08-27
$date:=$dt.utc.date // 2022-08-28

$day:=$dt.day     // 27
$day:=$dt.utc.day // 28

$time:=$dt.time     // 20:13:27
$time:=$dt.utc.time // 03:13:27

$hour:=$dt.hour     // 20
$hour:=$dt.utc.hour // 3

$timestamp:=$dt.timestamp     // 2022-08-27T20:13:27.123-07:00
$timestamp:=$dt.utc.timestamp // 2022-08-28T03:13:27.123Z

Creation

constructor()

cs.js.DateTime.new()
cs.js.DateTime.new(epochTime : Real)
cs.js.DateTime.new(input : Text)
cs.js.DateTime.new(date : Date { ; time : Time { ; ms : Integer { ; timezone : Text }}})
cs.js.DateTime.new(
    year : Integer; month : Integer; day : Integer
    { ; hour : Integer { ; minute : Integer { ; second : Integer { ; ms : Integer { ; timezone : Text }}}}}
)
cs.js.DateTime.new(config : Object)
cs.js.DateTime.new(dateTime : cs.js.DateTime)

Creates a new DateTime instance, which is always in local mode. A DateTime can be created in a variety of ways:

Current date/time

In the first form, a DateTime is created with the current date, time, and milliseconds in the local timezone.

TIP

DateTime.now() is a shortcut for the first constructor form.

From epoch time

In the second form, a DateTime is created from a Unix epoch timeopen in new window in milliseconds.

TIP

This form is fully compatible with the result of the JavaScript Date.getTime()open in new window method.

From a string

In the third form, input should be a string consisting of:

  • A date in the format YYYY-MM-DD.

  • An optional 24-hour time in the format HH:MM:SS, separated from the date by T.

  • An optional millisecond value in the format SSS, separated from the time by ..

  • An optional timezone offset, which may either be Z to indicate UTC, or an offset in the format ±HHMM, with an optional : separator between the hours and minutes.

If input is malformed, an error is thrown and the DateTime is considered invalid.

From parts

In the fourth and fifth forms, you pass the constituent parts of DateTime. Omitted parameters default to a zero value. If timezone is omitted, the local timezone at the given date and time is used.

In the sixth form, you pass an object with any of the following properties:

PropertyType
.dateDate
.timeTime/Number
.yearNumber
.monthNumber
.dayNumber
.hourNumber
.minuteNumber
.secondNumber
.msNumber
.timezoneText

A few rules apply:

  • You must pass either .date, or .year, .month and .day. If you pass .date, .year, .month and .day are ignored.

  • The rest of the properties are optional. Omitted properties default to a zero/empty value.

  • If you pass .time, .hour, .minute, and .second are ignored.

Passing a timezone

In any of the above forms, if a timezone is passed as a parameter or as a property of config, it should consist of either:

  • A valid IANA timezone abbreviation and timezone name, separated by |. If the abbreviation is unambiguous within an area such as Europe, you may pass the area as the timezone name. For example, CET|Europe is valid because CET is unambiguous within the area Europe.

  • "UTC" (no timezone name is necessary), in which case the input values are considered to be in UTC.

TIP

An easier and more flexible way to create a UTC DateTime is to use DateTime.utc().

If the timezone is invalid or ambiguous, an error is thrown and the DateTime is considered invalid.

Passing a timezone does not set the local timezone abbreviation and name. What it does do is to determine which timezone the given date and time belong to, and thus the UTC time they represent. For example, if the timezone is CET|Europe/Paris, the UTC time will be one hour less than the given time.

Copying a DateTime

In the final form (the copy constructor), a copy of dateTime is created.

TIP

.clone() is a shortcut for passing This to the copy constructor.

The following errors are thrown if the constructor is called with invalid parameters:

ErrorCause
TypeErrorThe first parameter is an invalid type
TypeErrorThe first parameter is a number, but the following two are not
TypeErrorhour is not a number
TypeErrorconfig contains .year but not .month and .day
RangeErrortimezone is invalid or ambiguous
SyntaxErrorinput is malformed

Examples

// First form
$dt:=cs.js.DateTime.new()

// Second form, all are valid
$dt:=cs.js.DateTime.new("2020-01-01")
$dt:=cs.js.DateTime.new("2020-01-01T12:34:56")
$dt:=cs.js.DateTime.new("2020-01-01T12:34:56.789")
$dt:=cs.js.DateTime.new("2020-01-01T12:34:56Z") // UTC
$dt:=cs.js.DateTime.new("2020-01-01T12:34:56.789Z") // UTC
$dt:=cs.js.DateTime.new("2020-01-01T12:34:56.789-0800")
$dt:=cs.js.DateTime.new("2020-01-01T12:34:56.789-08:00")

// Third form, all are valid
$dt:=cs.js.DateTime.new(!2020-01-01!)
$dt:=cs.js.DateTime.new(!2020-01-01!; ?12:34:56)
$dt:=cs.js.DateTime.new(!2020-01-01!; ?12:34:56; 789)

// Date and time are UTC
$dt:=cs.js.DateTime.new(!2020-01-01!; ?12:34:56; 789; "UTC")

// The UTC time will be 12:34:56 +8 hours. This is independent of
// the local time.
$dt:=cs.js.DateTime.new(!2020-01-01!; ?12:34:56; 789; "PST|America/Los_Angeles")

// PST is unique within the "America" timezone area, this is also valid
$dt:=cs.js.DateTime.new(!2020-01-01!; ?12:34:56; 789; "PST|America")

// Values are considered to be UTC
$dt:=DateTime.utc("2020-01-01T12:34:56.789")
$dt:=DateTime.utc(!2020-01-01!; ?12:34:56; 789)

If invalid input is passed to the constructor, an error is thrown and the created DateTime is considered invalid.


.clone()

.clone()

Returns a copy of this DateTime. This is equivalent to passing This to the copy constructor.

Properties

.date

.date : Date

Returns the local or UTC date of this DateTime, depending on the timezone mode. This property is read-only.


.day

.day : Integer

Returns the local or UTC day of the month (1-31) of this DateTime, depending on the timezone mode. This property is read-only.


.daysInMonth

.daysInMonth : Integer

Returns the number of days in the local or UTC month of this DateTime, depending on the timezone mode. This property is read-only.


.epochTime

.epochTime : Real

Returns the number of milliseconds since January 1, 1970, 00:00:00 UTC. Negative values are returned for prior times. The value returned by this property can be passed directly to the JavaScript Date(value)open in new window constructor.

This property is read-only.


.hour

.hour : Integer

Returns the local or UTC hour (0-23) of this DateTime, depending on the timezone mode. This property is read-only.


.milliseconds

.milliseconds : Integer

Returns the milliseconds (0-999) of this DateTime. This property is read-only.


.minute

.minute : Integer

Returns the local or UTC minute (0-59) of this DateTime, depending on the timezone mode. This property is read-only.


.month

.month : Integer

Returns the local or UTC month (1-12) of this DateTime, depending on the timezone mode. This property is read-only.


.second

.second : Integer

Returns the local or UTC second (0-59) of this DateTime, depending on the timezone mode. This property is read-only.


.time

.time : Time

Returns the local or UTC time of this DateTime, depending on the timezone mode. This property is read-only.


.valid

.valid : Boolean

Returns True if this DateTime is valid, False otherwise. A DateTime is considered invalid if it was created with invalid input, or if it was created with a timezone that does not exist.

IMPORTANT

The results of operating on an invalid DateTime are undefined. It is up to you to check the validity of this DateTime before using it.


.weekday

.weekday : Integer

Returns the local or UTC day of the week (1-7) of this DateTime, depending on the timezone mode. This property is read-only.


.year

.year : Integer

Returns the local or UTC full year of this DateTime, depending on the timezone mode. This property is read-only.

Manipulation

.add()

.add(years : Integer { ; months : Integer { ; days : Integer { ; time : Time }}}) : cs.js.DateTime
.add(amount : Integer; unit : String) : cs.js.DateTime
.add(amounts : Object) : cs.js.DateTime

Returns a new DateTime adjusted by the given amounts.

The first form works just like the 4D Add to date command but allows you to add time as well.

The second form allows you to specify a single unit of time to add. The unit parameter can be one of the following:

UnitShorthand
dayd
weekw
monthM
yeary
hourh
minutem
seconds

NOTE

The full unit names may have a plural or singular form. For example, day and days are both valid.

The third form is an object which may have one or more properties which match the plural units listed above (e.g. .years, .minutes, etc.). Missing units are treated as zero.

If the parameters do not match any of the forms, a TypeError is thrown.

Overflows or underflows adjust the next highest unit accordingly. For example:

$dt:=cs.js.DateTime.new(!2019-01-27!; ?23:59:59?)
$d2:=$dt.add(1; 1; 1; ?00:00:01?)
// $d2 => 2020-02-29 00:00:00 (2020 is a leap year)

$dt:=cs.js.DateTime.new(!2022-08-27!; ?23:59:59?)
$d2:=$dt.add(5, 'seconds')
// $d2 => 2022-08-28 00:00:04

$dt:=cs.js.DateTime.new(!2022-08-27!; ?23:59:59?)
$d2:=$dt.add(_.json("{ 'days': 1, 'hours': 2, 'seconds': 1 }"))
// $d2 => 2022-08-29 02:00:00

TIP

While you can add negative amounts, it is probably clearer to use .subtract() instead.


.offset()

.offset(seconds : Integer) : cs.js.DateTime

Returns a new DateTime with the given UTC offset applied. Note that the timezone will not be adjusted accordingly. This is useful when you need to display a DateTime in a different timezone, but you don’t want to look up (or don’t have) the timezone abbreviation and name.

Example

// UTC offset is -7 hours
$dt:=cs.js.DateTime.new(!2022-03-30!; ?00:05:00?; 0; "PDT|America/Los_Angeles")

// We want to show the time in another timezone whose UTC offset is -4 hours
$offset:=[users]tzOffset
$formatted:=$dt.offset([users]tzOffset).format("LT")
// $formatted => 3:05 AM

.subtract()

.subtract(years : Integer { ; months : Integer { ; days : Integer { ; time : Time }}}) : cs.js.DateTime
.subtract(amount : Integer; unit : String) : cs.js.DateTime
.subtract(amounts : Object) : cs.js.DateTime

Returns a new DateTime adjusted by the given amounts. This is the same as .add(), but subtracts values instead of adding.

Queries

.compareWith()

.compareWith(datetime : cs.js.DateTime) : Integer

Compares this DateTime with another, including date and time:

  • If this DateTime is before datetime, -1 is returned.
  • If this DateTime is after datetime, 1 is returned.
  • If they are equal, 0 is returned.

.diff()

.diff(dateTime : cs.js.DateTime { ; factorSeconds : Boolean }) : Object

Calculates the difference between this DateTime and dateTime.

If factorSeconds is false (the default), the result is an object with the following properties:

{
  "days": Integer;
  "seconds: Integer;
  "ms": Integer
}

If factorSeconds is true, the total difference in seconds is factored into hours, minutes, and seconds, and the result is an object with the following properties:

{
  "days": Integer;
  "hours": Integer;
  "minutes": Integer;
  "seconds: Integer;
  "ms": Integer
}

.isAfter()

.isAfter(datetime : cs.js.DateTime) : Boolean

Returns whether this DateTime is after datetime.


.isBefore()

.isBefore(datetime : cs.js.DateTime) : Boolean

Returns whether this DateTime is before datetime.


.isSameAs()

.isSameAs(datetime : cs.js.DateTime) : Boolean

Returns whether this DateTime is the same as datetime.


.isSameOrAfter()

.isSameOrAfter(datetime : cs.js.DateTime) : Boolean

Returns whether this DateTime is the same as or after datetime.


.isSameOrBefore()

.isSameOrBefore(datetime : cs.js.DateTime) : Boolean

Returns whether this DateTime is the same as or before datetime.

String conversion

.description()

.description() : Text

Returns a debug description of this DateTime.


.format()

.format(format : Text) : Text

This function allows you to easily format this DateTime with total flexibility. format is a string that specifies the contents and format of the output. The following formatting tokens are recognized:

CategoryTokenOutput
MonthM1 2 … 11 12
sMSome as M, but padded with leading space for 1-9
MM01 02 … 11 12
MMMJan Feb … Nov Dec
MMMMJanuary February … November December
Day of MonthD1 2 … 30 31
sDSame as D, but padded with leading space for 1-9
Do1st 2nd … 30th 31st
DD01 02 … 30 31
Day of Weekd1 2 … 6 7
ddSu Mo … Fr Sa
dddSun Mon … Fri Sat
ddddSunday Monday … Friday Saturday
YearYY70 71 … 29 30
YYYY1970 1971 … 2029 2030
At@at (localized proposition used before a time)
AM/PMAAM PM
aam pm
HourH0 1 … 22 23
HH00 01 … 22 23
h1 2 … 11 12
hh01 02 … 11 12
Minutem0 1 … 58 59
mm00 01 … 58 59
Seconds0 1 … 58 59
ss00 01 … 58 59
MillisecondSSS000 001 … 998 999
TimezoneZ-07:00 -06:00 … +06:00 +07:00
ZZ-0700 -0600 … +0600 +0700
zPST (Timezone abbreviation)
zzAmerica/Los_Angeles (Timezone name)

NOTE

The Do (date ordinal) token uses the current locale’s ordinal function to format the day of the month.

The value that some tokens represent depends on the current timezone mode and the current locale.

To include text in format that is not a token (other than spaces), enclose it in []. The [] is ignored, and the text within is passed through untouched.

In addition to the tokens listed above, you may also use format tokens in format. For a list of the localized format tokens that are built-in, see the .datetime.formats object in the Locale file structure section.

Alternately, instead of tokens, you may also pass a custom format as format. Unlike format tokens, custom formats are not composable; format must match the custom format name exactly.

If format is empty, the result of This.toString() is returned.

Examples

$dt:=cs.js.DateTime.new(!1931-08-27!)
$formatted:=$dt.format("dddd, MMMM Do YYYY, h:mm:ss a")
// => "Sunday, August 27th 1931, 12:00:00 am"

$now:=DateTime.now()
$formatted:=$now.format("[The time is now ]h:mm a [on ]dddd, MMMM Do")
// => "The time is now 3:27 pm on Friday, November 18th"

$formatted:=$dt.format("shortDate")
// => "11/18/22"

// You can also pass DateTime formats via _.format(),
// which are passed through to the DateTime.format() function.
$dt:=cs.js.DateTime.new(!2022-12-01!; ?10:00:00?)
$formatted:=_.format("${1|LWDOM @ lt z}"; $dt.tz("CST|America/Chicago"))
// => "Friday, December 1st at 10:00 am CST"

.formatUTCOffset()

.formatUTCOffset({ separator: Boolean }) : Text

Returns the UTC offset of this DateTime in standard ISO format. If separator is true, : is placed between the hours and minutes.

Examples

// Assuming the current timezone is America/Los_Angeles
$dt:=cs.js.DateTime.new(!2022-12-01!; ?10:00:00?)

$offset:=$dt.formatUTCOffset()
// => "-0800"

$offset:=$dt.formatUTCOffset(True)
// => "-08:00"

$offset:=$dt.tz("UTC|UTC").formatUTCOffset()
// => "+0000"

.timestamp

.timestamp : Text

Returns this DateTime as a UTC timestamp in the format YYYY-MM-DDTHH:mm:ss.SSSZ. This property is read-only.


.toString()

.toString({ format : Text }) : Text

Returns this DateTime as a string:

  • If format is not empty, the result of This.format($format) is returned.

  • If the timezone mode is "local", the string represents local date/time in the format YYYY-MM-DDTHH:mm:ss.SSS±HHMM.

  • If the timezone mode is "utc", the string represents UTC date/time in the format YYYY-MM-DDTHH:mm:ss.SSSZ.

TIP

Remember that .toString() will be used by js.component by default to convert this DateTime to a string in any function that needs to do so. For example, _.format() will call .toString() for a placeholder if the value is a DateTime, and pass any format along.

Examples

$dt:=cs.js.DateTime.new(!2022-12-01!;?12:00:00?; "CST|America/Chicago")
$str:=$dt.toString()
// => "2022-12-01T10:00:00.000-0800"

$str:=$dt.utc.toString()
// => "2022-12-01T18:00:00.000Z"

// Local timezone is PST
$message:=_.format("We will convene at ${1|LT z} on ${1|LWDOM} on zoom."; $dt)
// => "We will convene at 10:00 AM PST on Thursday, December 1st on zoom."

.toUTCString()

.toUTCString() : Text

Returns this DateTime as a UTC string in the format YYYY-MM-DDTHH:mm:ss.SSSZ.


Timezones

.local

.local : cs.js.DateTime

If this DateTime is already in local mode, returns this DateTime. Otherwise, returns a copy of this DateTime with the timezone mode set to "local". This property is read-only.


.mode

.mode : Text

Returns the current timezone mode ("local" or "utc") for this DateTime. This property is read-only.


.timezone

.timezone : Text

Returns .timezoneAbbrev and .timezoneName separated by |. This property is read-only.


.timezoneAbbrev

.timezoneAbbrev : Text

Returns the local IANA timezone abbreviation for this DateTime. This property is read-only.


.timezoneName

.timezoneName : Text

Returns the local IANA timezone name for this DateTime. This property is read-only.


.tz()

.tz(timezone : Text) : cs.js.DateTime

Returns a copy of DateTime but with the timezone offset specified by timezone, which should be in the standard <abbrev>|<name> format used by the constructor.

If timezone does not specify a valid timezone, a RangeError is thrown and the returned DateTime will be in the same timezone as this DateTime.

This function does not change the underlying UTC date/time. It only changes the timezone offset, and thus what is considered local time. This is primarily useful for displaying a DateTime in a different timezone than the local timezone.

IMPORTANT

js.component currently does not know if the specified timezone actually corresponds to the timezone at the date and time of this DateTime. For example, specifying a Daylight Saving Time timezone for a DateTime that is in Standard Time will result in a timezone offset — and thus local times — that are incorrect.

Example

$dt:=cs.js.DateTime.new(!2022-11-11!;?08:31:00?) // PST|America/Los_Angeles
$ts:=$dt.toString() // => "2022-11-11T08:31:00.000-0800"
$dt2:=$dt.tz("EET|Europe/Kyiv")
$ts2:=$dt2.toString() // => "2022-11-11T18:31:00.000+0200"

// Careful! This is the wrong timezone for this date/time.
// The correct abbreviation for this date/time is "PST".
$dt3:=$dt.tz("PDT|America/Los_Angeles")

// Should be "2022-11-11T08:31:00.000-0800" this date/time
$ts3:=$dt3.toString() // => "2022-11-11T09:31:00.000-0700"

// The timezone name is necessary because CST is ambiguous otherwise
$dt:=cs.DateTime.new(!2022-12-01!; ?12:00:00?; 0; "CST|America/Chicago")

// $dt is in CST, but the local timezone is PST.
// If we convert to a string, it shows PST time, not CST time.

$formatted:=_.format("${1|dddd, MMMM Do} at ${1|h:mm a}"; $dt)
// => "Thursday, December 1st at 10:00 am"

// To show CST time, we need to convert to CST first
$formatted:=_.format(\
  "${1|dddd, MMMM Do} at ${1|h:mm a} CST"; \
  $dt.tz("CST|America/Chicago"))

.utc

.utc : cs.js.DateTime

If this DateTime is already in UTC mode, returns this DateTime. Otherwise, returns a copy of this DateTime with the timezone mode set to "utc". This property is read-only.


.utcOffset

.utcOffset : Integer

Returns the offset in seconds of the local time zone from UTC at the moment in time represented by this DateTime. This property is read-only.

Examples

$dt:=cs.js.DateTime.new(!2021-01-01!) // America/Los_Angeles PST
$dt.timezoneOffset // -28800 (-08:00)

$dt:=cs.js.DateTime.new(!2021-07-01!) // America/Los_Angeles PDT
$dt.timezoneOffset // -25200 (-07:00)

i18n

.loc()

.loc() : Text
.loc(locale : Text) : cs.js.DateTime

Shorthand for .locale.


.locale()

.locale() : Text
.locale(locale : Text) : cs.js.DateTime

With no parameters, returns the current locale for this DateTime.

With a locale parameter, returns a copy of this DateTime with the locale set to the resolved locale.


.localeData

.localeData : Object

Returns the locale data for this DateTime’s locale. The returned object should not be modified.

Last Updated:
Contributors: Aparajita