Source: extdate.js

  1. /** ExtDate
  2. * @module extdate
  3. */
  4. // Character set is UTF-8
  5. /* Version M2022-08-06 Handle monthCode.
  6. */
  7. /* Copyright Louis A. de Fouquières https://github.com/Louis-Aime 2016-2022
  8. Permission is hereby granted, free of charge, to any person obtaining
  9. a copy of this software and associated documentation files (the
  10. "Software"), to deal in the Software without restriction, including
  11. without limitation the rights to use, copy, modify, merge, publish,
  12. distribute, sublicense, and/or sell copies of the Software, and to
  13. permit persons to whom the Software is furnished to do so, subject to
  14. the following conditions:
  15. 1. The above copyright notice and this permission notice shall be included
  16. in all copies or substantial portions of the Software.
  17. 2. Changes with respect to any former version shall be documented.
  18. The software is provided "as is", without warranty of any kind,
  19. express of implied, including but not limited to the warranties of
  20. merchantability, fitness for a particular purpose and noninfringement.
  21. In no event shall the authors of copyright holders be liable for any
  22. claim, damages or other liability, whether in an action of contract,
  23. tort or otherwise, arising from, out of or in connection with the software
  24. or the use or other dealings in the software.
  25. */
  26. "use strict";
  27. /** Compute the system time zone offset at this date, in milliseconds.
  28. * This extension is not exported. JSDoc is not generated.
  29. * Rationale: with Chrome (and others ?), the TZOffset returned value, in min, losses the seconds.
  30. * @static
  31. * @function Date.getRealTZmsOffset
  32. * @extends Date
  33. * @return {number} the time zone offset in milliseconds: UTC - local (same sign as TimezoneOffset)
  34. */
  35. Date.prototype.getRealTZmsOffset = function () { // this prototype extension necessary prior to extending Date, and this method is redefined and enlarged within ExtDate.
  36. /* Gregorian coordinates of the system local date */
  37. let localCoord =
  38. {year: this.getFullYear(), month: this.getMonth(), date: this.getDate(),
  39. hours: this.getHours(), minutes: this.getMinutes(), seconds: this.getSeconds(), milliseconds: this.getMilliseconds()};
  40. /* UTC Date constructed with the local date coordinates */
  41. let localDate = new Date (0);
  42. localDate.setUTCFullYear (localCoord.year, localCoord.month, localCoord.date);
  43. localDate.setUTCHours (localCoord.hours, localCoord.minutes, localCoord.seconds, localCoord.milliseconds);
  44. return this.valueOf() - localDate.valueOf()
  45. }
  46. /** ExtDate (default exported class): extends the Date object with the flavour of Temporal proposal, using custom calendars.
  47. * All methods of the Date object are also available.
  48. * However, with the built-in methods, the figure that represents the month begins with 0, with the extended ones, it begins with 1.
  49. * @version M2022-08-06
  50. * @author Louis A. de Fouquières https://github.com/Louis-Aime
  51. * @license MIT 2016-2022
  52. * @see {@link customcalendarmodel.js}
  53. * @extends Date.
  54. * @requires chronos.js
  55. * @requires time-units.js
  56. * @class
  57. * @param {string|object} [calendar]
  58. * the calendar object that describes the custom calendar,
  59. * or a string that refers to a built-in calendar;
  60. * if undefined, set to "iso8601";
  61. * In this version, the string for a built-in calendar may only be "iso8601" (default) or "gregory".
  62. * @see customcalendarmodel.js for the custom calendar model.
  63. * @param {string|number[]} [dateArguments] - same parameter list as would be passed to the legacy Date object:
  64. * empty -> now;
  65. * one numerical argument: Posix counter in milliseconds, as for Date;
  66. * one string argument: an ISO string for the date, passed to Date;
  67. * several numerical arguments: the arguments of Date constructor, as would be passed to Date, but
  68. * year is an algebraic full year, e.g. 1 means year 0001, not year 1901, and negative numbers may be used;
  69. * first month is always 1, not 0;
  70. * default day is 1;
  71. * default time elements are 0;
  72. * the date elements are those of the target calendar, which may differ from ISO 8601;
  73. * the date elements passed are considered those of the local date, i.e. of the terminal's time zone.
  74. */
  75. export default class ExtDate extends Date {
  76. constructor (calendar, ...dateArguments) {
  77. let myCalendar = (calendar == undefined) ? "iso8601" : calendar;
  78. switch (typeof myCalendar) {
  79. case "string" : switch (myCalendar) {
  80. case "iso8601" : case "gregory" : break;
  81. default : throw new RangeError ("Only iso8601 and gregory built-in calendars enable ExtDate object construction, not " + myCalendar);
  82. } break;
  83. case "object": ; break; // ExtDate constructed although calendar object may be incomplete
  84. default : throw new TypeError ('Calendar parameter is neither a string nor an object');
  85. }
  86. if (dateArguments.length > 1) { // more than 1 argument to compute the Date: at least year and month, not a timestamp.
  87. if (myCalendar == "iso8601" || myCalendar == "gregory") { // First arguments are a year and a month. Year is alwasy full, month is always based 1.
  88. dateArguments[1]--; // month argument decremented for the legacy Date
  89. super (...dateArguments);
  90. if (dateArguments[0] < 100 && dateArguments[0] >= 0) this.setFullYear(dateArguments[0]);
  91. }
  92. else { // analyse fields in terms of the specified custom calendar
  93. let fields = new Object;
  94. for (let i = 0; i < ExtDate.numericFields().length; i++) {
  95. if (i < dateArguments.length) {
  96. if (!Number.isInteger(dateArguments[i])) throw new TypeError
  97. ('Argument ' + ExtDate.numericFields()[i].name + ' is not integer: ' + dateArguments[i]);
  98. fields[ExtDate.numericFields()[i].name] = dateArguments[i];
  99. } else {fields[ExtDate.numericFields()[i].name] = ExtDate.numericFields()[i].value} // If no value specified among arguments, set default value.
  100. }
  101. let UTCDate = new Date (calendar.counterFromFields (fields));
  102. super (UTCDate.valueOf() + UTCDate.getRealTZmsOffset());
  103. }
  104. }
  105. else // 0 or 1 argument for legacy Date, i.e. Now (0 argument), a string or a timestamp. Nothing calendar-dependant.
  106. super (...dateArguments);
  107. this.calendar = myCalendar; // because this may only appear after super.
  108. }
  109. /* Basic data
  110. */
  111. /** Give the list of numeric fields in a date object, and of their respective default values.
  112. * @static
  113. * @return {Object} ( name_of_field : field default value )
  114. */
  115. static numericFields() { return [ {name : "fullYear", value : 0}, {name : "month", value : 1}, {name : "day", value : 1},
  116. {name : "hours", value : 0}, {name : "minutes", value : 0}, {name : "seconds", value : 0}, {name : "milliseconds", value : 0} ]
  117. }
  118. /** Give the list of numeric fields in a week day date object, and of their respective default values.
  119. * @static
  120. * @return {Object} ( name_of_field : field default value )
  121. */
  122. static numericWeekFields() { return [ {name : "weekYear", value : 0}, {name : "weekNumber", value : 1}, {name : "weekday", value : 1},
  123. {name : "hours", value : 0}, {name : "minutes", value : 0}, {name : "seconds", value : 0}, {name : "milliseconds", value : 0} ]
  124. }
  125. /** Basic utility fonction: get UTC date from ISO 8601 UTC date figures,
  126. * including full year, i.e. 2-digit year is a year of the first century.
  127. * Please notice the slight differences with the legacy Date.UTC() function.
  128. * @static
  129. * @param {number} [fullYear=0] The year expressed as an algebraic unambiguous number, as specified by ISO 8601.
  130. * @param {number} [month=1] The month number, 1 to 12 for Jan. to Dec.
  131. * @param {number} [day=1] The day number in the month.
  132. * @param {number} [hours=0] The UTC hour
  133. * @param {number} [minutes=0] The UTC minutes
  134. * @param {number} [seconds=0] The UTC seconds
  135. * @param {number} [milliseconds=0] The UTC milliseconds
  136. * @return {number} the Posix timestamp corresponding to the specified UTC date.
  137. */
  138. static fullUTC (fullYear=0, month=1, day=1, hours=0, minutes=0, seconds=0, milliseconds=0) {
  139. arguments[1]--; // From base 1 month to month of legacy Date
  140. let myDate = new Date(Date.UTC(...arguments)); // Date.UTC requires at least one argument, which is always the UTC year, shifted to 1900-1999 if specified 0..99
  141. if (fullYear <100 && fullYear >=0) myDate.setUTCFullYear(fullYear);
  142. return myDate.valueOf()
  143. }
  144. /** Compute the system time zone offset at this date, or the time zone offset of a named time zone in ms.
  145. * This method is defined because there are discrepancies among navigators for the ***Date.prototype.getTimezoneOffset()*** function,
  146. * when used for date before 1847 in UK or even later in most other countries.
  147. * As there were no time zones, the real offset is computed to the second, but the legacy method may round to minutes,
  148. * depending on the navigator.
  149. * @param {string} [TZ] - the named time zone. If undefined or "", system timezone. "UTC" is always accepted.
  150. * @return {number} the time zone offset in milliseconds: UTC - local (same sign as TimezoneOffset).
  151. */
  152. getRealTZmsOffset (TZ) {
  153. if (TZ == "UTC") return 0; // avoid complex computation for a trivial case.
  154. if (TZ == undefined || TZ == "") { // system time zone
  155. // Gregorian coordinates of the system local date
  156. let localCoord =
  157. {year: this.getFullYear(), month: this.getMonth(), date: this.getDate(),
  158. hours: this.getHours(), minutes: this.getMinutes(), seconds: this.getSeconds(), milliseconds: this.getMilliseconds()};
  159. // UTC Date constructed with the local date coordinates
  160. let localDate = new Date (0);
  161. localDate.setUTCFullYear (localCoord.year, localCoord.month, localCoord.date);
  162. localDate.setUTCHours (localCoord.hours, localCoord.minutes, localCoord.seconds, localCoord.milliseconds);
  163. return this.valueOf() - localDate.valueOf()
  164. }
  165. else return this.valueOf() - this.toResolvedLocalDate(TZ).valueOf()
  166. }
  167. /** Construct a date that represents the "best fit" value of the given date shifted as UTC to the named time zone.
  168. * The computation of the time zone is that of Unicode, or of the standard TZOffset if Unicode's is not available.
  169. * @method
  170. * @param {string} [TZ] - the named time zone. If undefined or "", system timezone. "UTC" is always accepted.
  171. * @return {Date} the best possible result given by the navigator.
  172. */
  173. toResolvedLocalDate = function (TZ) { // This routine assumes that Intl.DateTimeFormat works. If not, exception is thrown.
  174. var localTime = new ExtDate (this.calendar,this.valueOf()); // Initiate a draft date that is the same as this.
  175. if (TZ == "UTC") return localTime; // Trivial case: time zone asked is UTC.
  176. // There is no try ! TZ has to be a valid TZ name.
  177. if (TZ == (undefined || ""))
  178. var localOptions = new Intl.DateTimeFormat ("en-GB")
  179. else
  180. var localOptions = new Intl.DateTimeFormat ("en-GB", {timeZone : TZ}); // Submit specified time zone
  181. // Here localOptions is set with valid asked timeZone
  182. // Set a format object suitable to extract numeric components from Date string
  183. let numericSettings = {weekday: 'long', era: 'short', year: 'numeric', month: 'numeric', day: 'numeric',
  184. hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: false};
  185. if (!(TZ == (undefined || ""))) numericSettings.timeZone = TZ;
  186. var numericOptions = new Intl.DateTimeFormat ("en-GB", numericSettings); // gregory calendar in British english
  187. let localTC = numericOptions.formatToParts(this); // Local date and time components at TZ
  188. return new ExtDate(this.calendar, ExtDate.fullUTC (
  189. localTC[8].value == "BC" ? 1-localTC[6].value : +localTC[6].value, // year component (a full year)
  190. +localTC[4].value, +localTC[2].value, // month and date components (month is 1..12)
  191. +localTC[10].value, +localTC[12].value, +localTC[14].value, //Hours, minutes and seconds
  192. localTime.getUTCMilliseconds())); // We can't obtain milliseconds from DateTimeFormat, but they always remain the same while changing time zone.
  193. }
  194. /** calendar date fields generator method from Date.valueOf(), local or UTC. Month in range 1..12
  195. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  196. * @return {Object} object with date fields { (era if applicable), year, month (range 1..12), day, hours, minutes, seconds, milliseconds}
  197. */
  198. getFields(TZ) {
  199. // compute offset to use
  200. var offset = this.getRealTZmsOffset(TZ),
  201. shiftDate, result;
  202. // compute Fields from a shifted value. Month is in the range 1..12
  203. if (typeof this.calendar == "string") {
  204. switch (this.calendar) { // calendar is a string: a built-in calendar, presently only "gregory" or "iso8601"
  205. case "iso8601": case "gregory" :
  206. shiftDate = new Date (this.valueOf() - offset);
  207. result = {
  208. fullYear : shiftDate.getUTCFullYear(),
  209. month : shiftDate.getUTCMonth()+1,
  210. day : shiftDate.getUTCDate(),
  211. hours : shiftDate.getUTCHours(),
  212. minutes : shiftDate.getUTCMinutes(),
  213. seconds : shiftDate.getUTCSeconds(),
  214. milliseconds : shiftDate.getUTCMilliseconds()
  215. };
  216. if (this.calendar == "gregory") [result.era, result.year] = result.fullYear <= 0 ? ["ERA0",1-result.fullYear] : ["ERA1", result.fullYear]
  217. else result.year = result.fullYear;
  218. break;
  219. default : throw new RangeError ("Only iso8601 and gregory built-in calendars enable getFields method: " + this.calendar);
  220. }
  221. return result;
  222. }
  223. else
  224. return this.calendar.fieldsFromCounter (this.valueOf() - offset);
  225. }
  226. /** ISO fields at UTC, like for Temporal.PlainDate
  227. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  228. * @return {Object} Date at TZ as Isofield object: isoYear, isoMonth (range 1..12), isoDay, hours, minutes, seconds, milliseconds
  229. */
  230. getISOFields(TZ) { // Fields with same name as in Temporal.
  231. var
  232. shiftDate = new Date (this.valueOf - this.getRealTZmsOffset(TZ));
  233. return {
  234. isoYear : shiftDate.getUTCFullYear(),
  235. isoMonth : shiftDate.getUTCMonth() + 1,
  236. isoDay : shiftDate.getUTCDate(),
  237. hours : shiftDate.getUTCHours(),
  238. minutes : shiftDate.getUTCMinutes(),
  239. seconds : shiftDate.getUTCSeconds(),
  240. milliseconds : shiftDate.getUTCMilliseconds()
  241. }
  242. }
  243. /** week fields generator method from Date.valueOf(), local or UTC.
  244. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  245. * @return {Object} object with week fields for the date at TZ, { weekNumber: number (1..53) of the week. weekday : number (1..7, 1 = Monday) of the weekday,
  246. weekYearOffset : -1/0/1 shift fullYear by one to obtain the year the week belongs to, weeksInYear: number of weeks in the year the week belons to }
  247. */
  248. getWeekFields(TZ) {
  249. if (typeof this.calendar == "string")
  250. throw new RangeError ('getWeekFields method not available for built-in calendars: ' + this.calendar)
  251. else return this.calendar.weekFieldsFromCounter (this.valueOf() - this.getRealTZmsOffset(TZ))
  252. }
  253. /** setter method, from fields representing partially a date or time in the target calendar, change date and computie timestamp.
  254. * @param {Object} fields that change from presently held date, i.e. undefined fields are extracted from present date with same TZ (system (blank) or 'UTC')
  255. * @param {String} [TZ] - if "" or undefined (default value), local date and time. If 'UTC', UTC date and time. No other value possible.
  256. * @return {number} a new timestamp
  257. */
  258. setFromFields( myFields, TZ ) {
  259. if (typeof this.calendar == "string") throw new TypeError ('setFromFields does not work with built-in calendars: ' + this.calendar);
  260. var askedFields = this.calendar.solveAskedFields (myFields), // askedFields is not ambiguous.
  261. fields = this.getFields(TZ);
  262. fields = Object.assign (fields, askedFields);
  263. /* This part seems unnecessary since fields already exist, held as an example.
  264. // 3. Now field should be complete
  265. if (ExtDate.numericFields().some ( (item) => fields[item.name] == undefined ? false : !Number.isInteger(fields[item.name] ) ) )
  266. throw new TypeError
  267. (ExtDate.numericFields().map(({name, value}) => {return (name + ':' + value);}).reduce((buf, part)=> buf + " " + part, "Missing or non integer element in date fields: "));
  268. ExtDate.numericFields().forEach ( (item) => { if (fields[item.name] == undefined)
  269. fields[item.name] = startingFields[item.name] } );
  270. */
  271. // Construct an object with the date indication only, at 0 h UTC
  272. let dateFields = {}; ExtDate.numericFields().slice(0,3).forEach ( (item) => {dateFields[item.name] = fields[item.name]} );
  273. this.setTime(this.calendar.counterFromFields (dateFields));
  274. // finally set time to this date from TZ, using .setHours or .setUTCHours
  275. return this.setFullTime (TZ , fields.hours, fields.minutes, fields.seconds, fields.milliseconds)
  276. }
  277. /** setter method, from the fields representing the date in the target WEEK calendar, comput timestamp
  278. * @param {Object} week fields that change from presently held date, i.e. undefined week fields are extracted from present date with same TZ.
  279. * @param {string} [TZ] - If "" or undefined (default value), local date and time. If "UTC", UTC date and time. No other value possible.
  280. * @return {number} same as Date.setTime
  281. */
  282. setFromWeekFields( myFields, TZ ) {
  283. if (typeof this.calendar == "string") throw new TypeError ('setFromWeekFields does not work with built-in calendars: ' + this.calendar);
  284. var timeFields = this.getFields (TZ), // interesting fields are time fields.
  285. weekFields = this.getWeekFields (TZ);
  286. weekFields = Object.assign (weekFields, myFields); // add date expressed in week coordinates.
  287. let dateFields = {}; ExtDate.numericWeekFields().slice(0,3).forEach ( (item) => {dateFields[item.name] = weekFields[item.name]} );
  288. this.setTime(this.calendar.counterFromWeekFields (dateFields));
  289. // finally set time to this date from TZ, using setFullTime
  290. return this.setFullTime (TZ, timeFields.hours, timeFields.minutes, timeFields.seconds, timeFields.milliseconds);
  291. }
  292. /** is this date in a leap year of the calendar ?
  293. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  294. * @return {Boolean} whether the associated date's year is a leap year.
  295. */
  296. inLeapYear ( TZ ) {
  297. if (typeof this.calendar.inLeapYear != "function") throw new RangeError ('inLeapYear function not provided for this calendar');
  298. return this.calendar.inLeapYear( this.getFields (TZ) );
  299. }
  300. /** extract a simple string with the calendar name, then era code (if applicable), then the figures for year, month, day, and time components.
  301. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  302. * @return {string} the current date as a string
  303. */
  304. toCalString( TZ ) {
  305. if (typeof this.calendar == "string") return this.toISOString() + "[c=" + this.calendar + "]";
  306. let fn6 = Intl.NumberFormat(undefined,{minimumIntegerDigits : 6, useGrouping : false}),
  307. fn4 = Intl.NumberFormat(undefined,{minimumIntegerDigits : 4, useGrouping : false}),
  308. fn3 = Intl.NumberFormat(undefined,{minimumIntegerDigits : 3}),
  309. fn2 = Intl.NumberFormat(undefined,{minimumIntegerDigits : 2}),
  310. fzs = Intl.DateTimeFormat(undefined, {hour: "2-digit", minute: "2-digit", second:"2-digit", timeZoneName : "short"}),
  311. compound = this.getFields (TZ);
  312. return "[" + this.calendar.id + "]" + ( compound.era == undefined ? "" : "(" + compound.era + ")" )
  313. + (compound.year < 10000 && compound.year > 0 ? fn4.format(compound.year) : fn6.format(compound.year)) + "-"
  314. + fn2.format(compound.month) + "-"+fn2.format(compound.day)
  315. + "T" + (TZ == undefined || TZ == "" ? fzs.format (this)
  316. : fn2.format(compound.hours)+":"+fn2.format(compound.minutes)+":"+fn2.format(compound.seconds)+"."+fn3.format(compound.milliseconds) + "Z")
  317. }
  318. /** Get year as an unambiguous signed integer.
  319. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  320. * @return {number} year, unambiguous signed integer.
  321. */
  322. fullYear (TZ) {
  323. let fields = this.getFields(TZ);
  324. return fields.fullYear;
  325. }
  326. /** Get era code, if existing for this calendar.
  327. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  328. * @return {string} era code.
  329. */
  330. era (TZ) {
  331. let fields = this.getFields(TZ);
  332. return fields.era
  333. }
  334. /** Get year; may be ambiguous if era is not known.
  335. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  336. * @return {number} year; era may be necessary for disambiguation.
  337. */
  338. year (TZ) {
  339. let fields = this.getFields(TZ);
  340. return fields.year
  341. }
  342. /** Get month number, the first number is 1.
  343. * @param {string} [TZ] - if "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  344. * @return {number} month number, number of first month is 1.
  345. */
  346. month (TZ) {
  347. let fields = this.getFields(TZ);
  348. return fields.month
  349. }
  350. monthCode (TZ) {
  351. let fields = this.getFields(TZ);
  352. return fields.monthCode == undefined ? String (fields.month) : fields.monthCode
  353. }
  354. /** Get day number in month.
  355. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  356. * @return {number} day number, first day of month is 1.
  357. */
  358. day (TZ) {
  359. let fields = this.getFields(TZ);
  360. return fields.day
  361. }
  362. /** Get weekday number, under rules specified in weekRule.
  363. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  364. * @return {number} weekday number.
  365. */
  366. weekday (TZ) {
  367. let fields = this.getWeekFields(TZ);
  368. return fields.weekday
  369. }
  370. /** Get week number in year, under rules specified in weekRule.
  371. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  372. * @return {number} week number.
  373. */
  374. weekNumber (TZ) {
  375. let fields = this.getWeekFields(TZ);
  376. return fields.weekNumber
  377. }
  378. /** Get number of weeks in this week calendar year, under rules specified in weekRule.
  379. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  380. * @return {number} number of weeks.
  381. */
  382. weeksInYear (TZ) {
  383. let fields = this.getWeekFields(TZ);
  384. return fields.weeksInYear
  385. }
  386. /** Get year after the week calendar, under rules specified in weekRule.
  387. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  388. * @return {number} year in the week calendar, unambiguous number (fullyear).
  389. */
  390. weekYear (TZ) { // unambiguous number of the year the numbered week belongs to
  391. let fields = this.getWeekFields(TZ);
  392. return fields.weekYear
  393. }
  394. /** Get hour in the day, in TZ
  395. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  396. * @return {number} hour 0 to 23.
  397. */
  398. hours (TZ) {
  399. let fields = this.getFields(TZ);
  400. return fields.hours
  401. }
  402. /** Get minutes of the hour in the day, in TZ
  403. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  404. * @return {number} minutes 0 to 59.
  405. */
  406. minutes (TZ) {
  407. let fields = this.getFields (TZ);
  408. return fields.minutes
  409. }
  410. /** Get seconds of the hour in the day, in TZ
  411. * @param {string} [TZ] - if "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  412. * @return {number} seconds 0 to 59.
  413. */
  414. seconds (TZ) {
  415. let fields = this.getFields (TZ);
  416. return fields.seconds
  417. }
  418. /** Get milliseconds of the hour in the day, in TZ
  419. * @param {string} [TZ] - Named time zone. If "" or undefined (default value), local date and time. If "UTC", UTC date and time.
  420. * @return {number} milliseconds 0 to 999.
  421. */
  422. milliseconds (TZ) {
  423. let fields = this.getFields (TZ);
  424. return fields.milliseconds
  425. }
  426. /** Set time of the day in same day, local or UTC, using legacy setHours or setUTCHours.
  427. * @param {string} [TZ] - If "" or undefined (default value), set local time at same local date. If "UTC", set UTC time at same UTC date. No other value possible.
  428. * @param {number} hours - the hours setting
  429. * @param {number} [minutes=current value] - the minutes setting
  430. * @param {number} [seconds=current value] - the seconds setting
  431. * @param {number} [milliseconds=current value] - the milliseconds setting
  432. * @return {number} the Date.valueOf result after operation.
  433. */
  434. setFullTime (TZ, hours, minutes, seconds, milliseconds) {
  435. if (TZ == undefined) TZ = "";
  436. if (hours == undefined || isNaN (hours)) throw new TypeError ('setFullTime: at least "hours" parameter should be specified: ' + hours);
  437. if (minutes == undefined) minutes = (TZ == "" ? this.getMinutes() : this.getUTCMinutes());
  438. if (seconds == undefined) seconds = (TZ == "" ? this.getSeconds() : this.getUTCSeconds());
  439. if (milliseconds == undefined) milliseconds = (TZ == "" ? this.getMilliseconds() : this.getUTCMilliseconds());
  440. switch (TZ) {
  441. case "" : return this.setHours (hours, minutes, seconds, milliseconds);
  442. case "UTC" : return this.setUTCHours (hours, minutes, seconds, milliseconds);
  443. default : throw new RangeError ('Only "UTC" or blank value is possible for TZ parameter: ' + TZ);
  444. }
  445. }
  446. }