DateTime
About
This class is inspired by one of the most popular JavaScript date packages, dayjs. 🚀
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 time in milliseconds.
TIP
This form is fully compatible with the result of the JavaScript Date.getTime() 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 byT.An optional millisecond value in the format
SSS, separated from the time by..An optional timezone offset, which may either be
Zto 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:
| Property | Type |
|---|---|
| .date | Date |
| .time | Time/Number |
| .year | Number |
| .month | Number |
| .day | Number |
| .hour | Number |
| .minute | Number |
| .second | Number |
| .ms | Number |
| .timezone | Text |
A few rules apply:
You must pass either
.date, or.year,.monthand.day. If you pass.date,.year,.monthand.dayare ignored.The rest of the properties are optional. Omitted properties default to a zero/empty value.
If you pass
.time,.hour,.minute, and.secondare 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 asEurope, you may pass the area as the timezone name. For example,CET|Europeis valid becauseCETis unambiguous within the areaEurope."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:
| Error | Cause |
|---|---|
| TypeError | The first parameter is an invalid type |
| TypeError | The first parameter is a number, but the following two are not |
| TypeError | hour is not a number |
| TypeError | config contains .year but not .month and .day |
| RangeError | timezone is invalid or ambiguous |
| SyntaxError | input 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) 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:
| Unit | Shorthand |
|---|---|
| day | d |
| week | w |
| month | M |
| year | y |
| hour | h |
| minute | m |
| second | s |
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
DateTimeis before datetime,-1is returned. - If this
DateTimeis after datetime,1is returned. - If they are equal,
0is 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:
| Category | Token | Output |
|---|---|---|
| Month | M | 1 2 … 11 12 |
| sM | Some as M, but padded with leading space for 1-9 | |
| MM | 01 02 … 11 12 | |
| MMM | Jan Feb … Nov Dec | |
| MMMM | January February … November December | |
| Day of Month | D | 1 2 … 30 31 |
| sD | Same as D, but padded with leading space for 1-9 | |
| Do | 1st 2nd … 30th 31st | |
| DD | 01 02 … 30 31 | |
| Day of Week | d | 1 2 … 6 7 |
| dd | Su Mo … Fr Sa | |
| ddd | Sun Mon … Fri Sat | |
| dddd | Sunday Monday … Friday Saturday | |
| Year | YY | 70 71 … 29 30 |
| YYYY | 1970 1971 … 2029 2030 | |
| At | @ | at (localized proposition used before a time) |
| AM/PM | A | AM PM |
| a | am pm | |
| Hour | H | 0 1 … 22 23 |
| HH | 00 01 … 22 23 | |
| h | 1 2 … 11 12 | |
| hh | 01 02 … 11 12 | |
| Minute | m | 0 1 … 58 59 |
| mm | 00 01 … 58 59 | |
| Second | s | 0 1 … 58 59 |
| ss | 00 01 … 58 59 | |
| Millisecond | SSS | 000 001 … 998 999 |
| Timezone | Z | -07:00 -06:00 … +06:00 +07:00 |
| ZZ | -0700 -0600 … +0600 +0700 | |
| z | PST (Timezone abbreviation) | |
| zz | America/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.