1/* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16package escompat; 17 18// TODO To offer protection against timing attacks and fingerprinting, the precision of `Date.getTime()`, 19// `Date.now()` might get rounded depending on browser (target) settings. 20// In Firefox, the `privacy.reduceTimerPrecision` preference is enabled by default 21// and defaults to 20µs in Firefox 59; in 60 it will be 2ms. 22 23/** Hours in a day. */ 24const hoursPerDay: int = 24; 25 26/** Minutes in an hour. */ 27const minutesPerHour: int = 60; 28 29/** Seconds in a minute. */ 30const secondsPerMinute: long = 60; 31 32/** Milliseconds in a second. */ 33const msPerSecond: long = 1000; 34 35/** msPerMinute == 60000 */ 36const msPerMinute: long = msPerSecond * secondsPerMinute; 37 38/** msPerHour == 3600000 */ 39const msPerHour: long = msPerMinute * minutesPerHour; 40 41/** msPerDay == 86400000 */ 42const msPerDay: long = msPerHour * hoursPerDay; 43 44/** Days in a year */ 45const dayCountInYear: int = 365; 46 47/** Days in a leap year */ 48const dayCountInLeapYear: int = 366; 49 50/** Months in a year */ 51const monthCountPerYear: int = 12; 52 53/** Max possible count of days in month */ 54const maxDaysInMonth = 31; 55 56/** 57 * This gives a range of 8,640,000,000,000,000 milliseconds 58 * to either side of 01 January, 1970 UTC. 59 */ 60const maxDateOffset: long = 8.64e15; 61 62/** Day names */ 63const dayNames: String[] = [ 64 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 65]; 66 67/** Month names */ 68const monthNames: String[] = [ 69 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 70]; 71 72/** First day of a month in a year */ 73const firstDayInMonthNormal: int[] = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; 74/** First day of a month in a leap year */ 75const firstDayInMonthLeap: int[] = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]; 76 77/** 78 * Returns first day with respect to year and month 79 * 80 * @param year 81 * 82 * @param month 83 * 84 * @returns first day 85 */ 86function getFirstDayInMonth(year: int, month: int): int { 87 assert (year == 0 || year == 1) && (month >= 0 && month <= 11) : "Invalid year/month pair"; 88 if (year == 0) { 89 return firstDayInMonthNormal[month]; 90 } else { 91 return firstDayInMonthLeap[month]; 92 } 93} 94 95/** 96 * Calculate the elapsed days since Unix Epoch. 97 * 98 * @returns elapsed days since Unix Epoch. 99 */ 100function ecmaDayFromTime(time: long): int { 101 if (time < 0) { 102 time -= msPerDay - 1; 103 } 104 return (time / msPerDay) as int; 105} 106 107/** 108 * @see ECMA-262, 20.4.1.3 109 * 110 * @returns number of days in the given year. 111 */ 112function ecmaDaysInYear(year: int): int { 113 if ((year % 4 != 0) || ((year % 100 == 0) && (year % 400 != 0))) { 114 return dayCountInYear; 115 } 116 117 return dayCountInLeapYear; 118} 119 120/** 121 * @see ECMA-262, 21.4.1.3 122 * 123 * @returns Year, corresponding to the given time. 124 */ 125function ecmaYearFromTime(time: long): int { 126 let approx: int = floor(time / msPerDay / 365.2425) as int + 1970 as int; 127 let yearMs: long = ecmaDayFromYear(approx) * msPerDay; 128 129 if (yearMs > time) { 130 approx--; 131 } 132 133 if ((yearMs + ecmaDaysInYear(approx) * msPerDay) <= time) { 134 approx++; 135 } 136 137 return approx; 138} 139 140/** 141 * @see ECMA-262, 21.4.1.4 142 * 143 * @returns Month number (within year). 144 */ 145function ecmaMonthFromTime(time: long): byte { 146 let year = ecmaYearFromTime(time); 147 let dayWithinYear = ecmaDayFromTime(time) - ecmaDayFromYear(year); 148 149 assert dayWithinYear >= 0 && dayWithinYear < dayCountInLeapYear; 150 151 let inLeapYear = ecmaInLeapYear(year); 152 153 for (let i = 1; i < 12; i++) { 154 if (dayWithinYear < getFirstDayInMonth(inLeapYear, i)) { 155 return (i - 1) as byte; 156 } 157 } 158 159 return 11; 160} 161 162/** 163 * @see ECMA-262, 21.4.1.5 164 * 165 * @returns Date number (within month). 166 */ 167function ecmaDateFromTime(time: long): byte { 168 let year = ecmaYearFromTime(time); 169 let dayWithinYear = ecmaDayFromTime(time) - ecmaDayFromYear(year); 170 171 assert dayWithinYear >= 0 && dayWithinYear < dayCountInLeapYear; 172 173 let inLeapYear = ecmaInLeapYear(year); 174 175 let month: byte = 11; 176 177 for (let i = 1; i < 12; i++) { 178 if (dayWithinYear < getFirstDayInMonth(inLeapYear, i)) { 179 month = (i - 1) as byte; 180 break; 181 } 182 } 183 184 return (dayWithinYear + 1 - getFirstDayInMonth(inLeapYear, month)) as byte; 185} 186 187/** 188 * @see ECMA-262, 21.4.1.5 189 * 190 * @param time 191 * 192 * @returns Week day. 193 */ 194function ecmaWeekDay(time: long): byte { 195 let day = ecmaDayFromTime (time); 196 let weekDay = ((day + 4) % 7) as byte; 197 198 return weekDay >= 0 ? weekDay : (weekDay + 7) as byte; 199} 200 201/** 202 * @see ECMA-262, 21.4.1.5 203 * 204 * @param time 205 * 206 * @returns Week day. 207 */ 208function ecmaTimeInDayFromTime(time: long): long { 209 let day = ecmaDayFromTime(time); 210 return (time - (day * msPerDay)); 211} 212 213/** 214 * @see ECMA-262, 21.4.1.13 215 * 216 * @returns Hour component of a given time. 217 */ 218function ecmaHourFromTime(time: long): byte { 219 let timeInDay = ecmaTimeInDayFromTime(time); 220 return (timeInDay / msPerHour) as byte; 221} 222 223/** 224 * @see ECMA-262, 21.4.1.13 225 * 226 * @returns Minute component of a given time. 227 */ 228function ecmaMinFromTime(time: long): byte { 229 let timeInDay = ecmaTimeInDayFromTime(time); 230 return ((timeInDay / msPerMinute) % minutesPerHour) as byte; 231} 232 233/** 234 * @see ECMA-262, 21.4.1.13 235 * 236 * @returns Seconds component of a given time. 237 */ 238function ecmaSecFromTime(time: long): byte { 239 let timeInDay = ecmaTimeInDayFromTime(time); 240 return ((timeInDay / msPerSecond) % secondsPerMinute) as byte; 241} 242 243/** 244 * @see ECMA-262, 21.4.1.13 245 * 246 * @returns Milliseconds component of a given time. 247 */ 248function ecmaMsFromTime(time: long): short { 249 let timeInDay = ecmaTimeInDayFromTime(time); 250 return (timeInDay % msPerSecond) as short; 251} 252 253/** 254 * @see ECMA-262, 21.4.1.14 255 * 256 * @param hr 257 * 258 * @param min 259 * 260 * @param sec 261 * 262 * @param ms 263 * 264 * @returns Constructed time in milliseconds. 265 */ 266function ecmaMakeTime(hr: long, min: long, sec: long, ms: long): long { 267 return hr * msPerHour + min * msPerMinute + sec * msPerSecond + ms; 268} 269 270/** 271 * @see ECMA-262, 21.4.1.14 272 * 273 * @param hr 274 * 275 * @param min 276 * 277 * @param sec 278 * 279 * @param ms 280 * 281 * @returns Constructed time in milliseconds. 282 */ 283function ecmaMakeTime(hr: double, min: double, sec: double, ms: double): long { 284 let hh = trunc(hr) as long; 285 let mm = trunc(min) as long; 286 let ss = trunc(sec) as long; 287 let mi = trunc(ms) as long; 288 289 return ecmaMakeTime(hh, mm, ss, mi); 290} 291 292 293/** 294 * @see ECMA-262, 21.4.1.15 295 * 296 * @param year 297 * 298 * @param month 299 * 300 * @param date 301 * 302 * @returns Elapsed number of days since Unix Epoch. 303 */ 304function ecmaMakeDay(year: long, month: long, date: long): long { 305 let ym = (year + floor(month as double / 12.0 as double)) as int; 306 let mn = (month % 12) as byte; 307 308 if (mn < 0) { 309 mn += 12; 310 } 311 312 let days: long = (ecmaDayFromYear(ym) as long + getFirstDayInMonth(ecmaInLeapYear(ym), mn) as long + (date as long) - 1); 313 314 return days; 315} 316 317/** 318 * @see ECMA-262, 21.4.1.15 319 * 320 * @param year 321 * 322 * @param month 323 * 324 * @param day 325 * 326 * @returns Elapsed number of days since Unix Epoch. 327 */ 328function ecmaMakeDay(year: double, month: double, day: double): long { 329 let y = trunc(year) as long; 330 let m = trunc(month) as long; 331 let d = trunc(day) as long; 332 333 return ecmaMakeDay(y, m, d); 334} 335 336/** 337 * @see ECMA-262, 21.4.1.16 338 * 339 * @returns Elapsed number of milliseconds since Unix Epoch. 340 * 341 */ 342function ecmaMakeDate(day:long, time: long): long { 343 return day * msPerDay + time; 344} 345 346/** 347 * @see ECMA-262, 21.4.1.17 348 * 349 * @returns Elapsed number of milliceconds since Unix Epoch. 350 * 351 */ 352function ecmaTimeClip(time: long): long throws { 353 if ((time > maxDateOffset) || (time < -maxDateOffset)) { 354 throw new InvalidDate(); 355 } 356 357 return time; 358} 359 360/** 361 * Returns first day of a given year since epoch. 362 * 363 * @param year 364 * 365 * @returns day from year 366 * 367 * @see ECMA-262, 21.4.1.3, DayFromYear 368 */ 369function ecmaDayFromYear(year: int): int { 370 return (365 * (year - 1970) + 371 floor((year - 1969) / 4.0) - 372 floor((year - 1901) / 100.0) + 373 floor((year - 1601) / 400.0)) as int; 374} 375 376/** 377 * Returns first day of a given year since epoch. 378 * 379 * @param year 380 * 381 * @returns day from year 382 * 383 * @see ECMA-262, 21.4.1.3, DayFromYear 384 */ 385function ecmaTimeFromYear(year: int): long { 386 return msPerDay as long * ecmaDayFromYear(year) as long; 387} 388 389/** 390 * The leap-year function is 1 for a time within a leap year and otherwise is 0. 391 * 392 * @see ECMA-262, 21.4.1.3 393 * 394 * @returns 1 - if the year is leap 395 * 0 - otherwise 396 */ 397function ecmaInLeapYear(year: int): byte { 398 return (ecmaDaysInYear(year) - dayCountInYear) as byte; 399} 400 401/** 402 * Date JS API-compatible class 403 */ 404export final class Date { 405 /** Stored value of Date, milliseconds */ 406 private ms: long; 407 private TZOffset: long; 408 409 /** 410 * The `parseDateFromString()` static method parses a string representation of a date, 411 * and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC 412 * or raises `InvalidDate` if the string is unrecognized or, in some cases, 413 * contains illegal date values (e.g. 2015-02-31). 414 * 415 * Only the @link{https://tc39.es/ecma262/#sec-date-time-string-format|ISO 8601 format} 416 * (YYYY-MM-DDTHH:mm:ss.sssZ) is explicitly specified to be supported. 417 * Other formats are implementation-defined and may not work across all browsers (targets). 418 * A library can help if many different formats are to be accommodated. 419 * 420 * @see ECMA-262, 21.4.3.2 421 * 422 * @returns A number representing the milliseconds elapsed since January 1, 1970, 00:00:00 UTC 423 * and the date obtained by parsing the given string representation of a date. 424 * If the argument doesn't represent a valid date, `InvalidDate` error is thrown. 425 */ 426 private static parseDateFromString(dateStr: String): number { 427 const dateStrLen = dateStr.length as int; 428 if (dateStrLen < 4) { 429 return 0; 430 } 431 if (dateStrLen > 35) { 432 throw new InvalidDate(); 433 } 434 435 let date = new Date(0); 436 437 let timeZone: long = 0; 438 const years = Date.parseIfContains(dateStr, 0, 4); 439 const months = Date.parseIfContains(dateStr, 5, 7); 440 const days = Date.parseIfContains(dateStr, 8, 10); 441 const hours = Date.parseIfContains(dateStr, 11, 13); 442 const minutes = Date.parseIfContains(dateStr, 14, 16); 443 const seconds = Date.parseIfContains(dateStr, 17, 19); 444 const milliseconds = Date.parseIfContains(dateStr, 20, 23); 445 446 date.setUTCFullYear(years); 447 if (months != Date.UNSUCCESSFUL_PARSING) { 448 if (months > monthCountPerYear || months <= 0) { 449 throw new InvalidDate(); 450 } 451 date.setUTCMonth((months - 1) as int); 452 } else { 453 date.setUTCMonth(0 as int); 454 } 455 if (days != Date.UNSUCCESSFUL_PARSING) { 456 if (days > maxDaysInMonth || days <= 0) { 457 throw new InvalidDate(); 458 } 459 date.setUTCDate((days) as byte); 460 } else { 461 date.setUTCDate(1 as byte); 462 } 463 if (hours != Date.UNSUCCESSFUL_PARSING) { 464 if (hours > hoursPerDay || hours < 0) { 465 throw new InvalidDate(); 466 } 467 date.setUTCHours(hours as byte); 468 } else { 469 date.setUTCHours(0 as byte); 470 } 471 if (minutes != Date.UNSUCCESSFUL_PARSING) { 472 if (minutes >= minutesPerHour || minutes < 0) { 473 throw new InvalidDate(); 474 } 475 date.setUTCMinutes(minutes as byte); 476 } else { 477 date.setUTCMinutes(0 as byte); 478 } 479 if (seconds != Date.UNSUCCESSFUL_PARSING) { 480 if (seconds >= secondsPerMinute || seconds < 0) { 481 throw new InvalidDate(); 482 } 483 date.setUTCSeconds(seconds as byte); 484 } else { 485 date.setUTCSeconds(0 as byte); 486 } 487 if (milliseconds != Date.UNSUCCESSFUL_PARSING) { 488 if (milliseconds >= msPerSecond || milliseconds < 0) { 489 throw new InvalidDate(); 490 } 491 date.setUTCMilliseconds(milliseconds as short); 492 } else { 493 date.setUTCMilliseconds(0 as short); 494 } 495 if (dateStrLen > 23) { 496 timeZone = 0; 497 let timeZoneSign = 0; 498 let timeZoneSignChar = c'+'; 499 try { 500 timeZoneSignChar = dateStr.charAt(23); 501 } catch (e) {} 502 if (timeZoneSignChar == c'-') { 503 timeZoneSign = 1; 504 } else if (timeZoneSignChar == c'Z') { 505 timeZoneSign = 0; 506 } else if (timeZoneSignChar == c'+') { 507 timeZoneSign = -1; 508 } else { 509 throw new InvalidDate(); 510 } 511 const timeZoneHours = Date.parseIfContains(dateStr, 24, 26); 512 const timeZoneMinutes = Date.parseIfContains(dateStr, 27, 29); 513 const timeZoneSeconds = Date.parseIfContains(dateStr, 30, 32); 514 const timeZoneSecondsFraction = Date.parseIfContains(dateStr, 33, min(36, dateStrLen) as int); 515 if (timeZoneHours != Date.UNSUCCESSFUL_PARSING) { 516 if (timeZoneHours < 0 || timeZoneHours >= hoursPerDay) { 517 throw new InvalidDate(); 518 } 519 timeZone += timeZoneHours * msPerHour; 520 } 521 if (timeZoneMinutes != Date.UNSUCCESSFUL_PARSING) { 522 if (timeZoneMinutes < 0 || timeZoneMinutes >= minutesPerHour) { 523 throw new InvalidDate(); 524 } 525 timeZone += timeZoneMinutes * msPerMinute; 526 } 527 if (timeZoneSeconds != Date.UNSUCCESSFUL_PARSING) { 528 if (timeZoneSeconds < 0 || timeZoneSeconds >= secondsPerMinute) { 529 throw new InvalidDate(); 530 } 531 timeZone += timeZoneSeconds * msPerSecond; 532 } 533 if (timeZoneSecondsFraction != Date.UNSUCCESSFUL_PARSING) { 534 let timeZoneMillis = timeZoneSecondsFraction; 535 if (dateStrLen == 32) { 536 timeZoneMillis *= 100; 537 } else if (dateStrLen == 33) { 538 timeZoneMillis *= 10; 539 } 540 if (timeZoneSecondsFraction < 0) { 541 throw new InvalidDate(); 542 } 543 timeZone += timeZoneSecondsFraction; 544 } 545 546 timeZone *= timeZoneSign; 547 } 548 if (dateStrLen == 23) { 549 timeZone = Date.getLocalTimezoneOffset(date.valueOf() as long) * msPerMinute; 550 } 551 return date.valueOf() + timeZone ; 552 } 553 /** 554 * Default constructor. 555 * 556 * @see ECMA-262, 21.4.2.1 557 * 558 * @description Initializes Date instance with current time. 559 */ 560 constructor() { 561 this.ms = Date.now() as long; 562 this.TZOffset = Date.getLocalTimezoneOffset(this.ms as long) 563 } 564 565 /** 566 * `Date` constructor. 567 * 568 * @param value 569 * 570 * @see ECMA-262, 21.4.2.1 571 * 572 * @description Initializes `Date` instance with `number` or `string` or another `Date` instance. 573 * NOTE: Dates before `1921-01-01T00:00:00 GMT` can be represented as UTC milliseconds in different ways then TS do. 574 */ 575 576 constructor(value: number | string | Date) { 577 578 if (value instanceof Date) { 579 this.ms = trunc((value as Date).valueOf() as number) as long 580 this.TZOffset = (value as Date).getTimezoneOffset() as long 581 } 582 else if (typeof value == "string") { 583 this.ms = (Date.parseDateFromString(value as string) as long); 584 } 585 else { 586 this.ms = trunc(value as number) as long; 587 } 588 this.TZOffset = Date.getLocalTimezoneOffset(this.ms as long); 589 } 590 591 /** 592 * `Date` constructor. 593 * 594 * @param year 595 * 596 * @param month 597 * 598 * @param day 599 * 600 * @param hours 601 * 602 * @param minutes 603 * 604 * @param seconds 605 * 606 * @param ms 607 * 608 * @see ECMA-262, 21.4.2.1 609 * 610 * @description Initialize `Date` instance with year, month, day, hours, minutes, seconds and milliseconds given. 611 * NOTE: Dates before `1921-01-01T00:00:00 GMT` can be represented as UTC milliseconds in different ways then TS do. 612 */ 613 constructor(year: number, monthIndex: number, day?: number, hours?: number, minutes?: number, seconds?: number, ms?: number) { 614 this.ms = ecmaMakeDate( 615 ecmaMakeDay( 616 year, 617 monthIndex, 618 day != undefined ? day as number: 1 619 ), 620 ecmaMakeTime( 621 hours != undefined ? hours as number : 0, 622 minutes != undefined ? minutes as number : 0, 623 seconds != undefined ? seconds as number : 0, 624 ms != undefined ? ms as number : 0 625 ) 626 ); 627 this.TZOffset = Date.getLocalTimezoneOffset(this.ms as long); 628 this.ms += this.TZOffset * msPerMinute 629 } 630 631 /** 632 * Creates a new instance of a Date as a string 633 * 634 * @returns A new Date instance as a string 635 */ 636 static invoke(): string { 637 return new Date().toString(); 638 } 639 640 /** 641 * The `isDateValid()` method checks if given date `ms` is maximum of ±100,000,000 642 * (one hundred million) days relative to January 1, 1970 UTC 643 * (that is, April 20, 271821 BCE ~ September 13, 275760 CE) can be represented 644 * by the standard `Date` object (equivalent to ±8,640,000,000,000,000 milliseconds). 645 */ 646 private isDateValid(ms: long): boolean { 647 return ms >= -maxDateOffset && ms <= maxDateOffset; 648 } 649 650 /** 651 * The `isDateValid()` method checks if constructed date is maximum of ±100,000,000 652 * (one hundred million) days relative to January 1, 1970 UTC 653 * (that is, April 20, 271821 BCE ~ September 13, 275760 CE) can be represented 654 * by the standard Date object (equivalent to ±8,640,000,000,000,000 milliseconds). 655 * 656 */ 657 public isDateValid(): boolean { 658 return this.isDateValid(this.ms); 659 } 660 661 /** 662 * The `valueOf()` method returns the primitive value of a `Date` object. 663 * 664 * @see ECMA-262, 21.4.4.44 665 * 666 * @returns The number of milliseconds between 1 January 1970 00:00:00 UTC and the given date. 667 * 668 * @throws InvalidDate - Throws if Date object is invalid (@link{isDateValid} is `false`). 669 */ 670 public valueOf(): number { 671 if (!this.isDateValid()) { 672 return NaN; 673 } 674 return this.ms as number; 675 } 676 677 /** 678 * The `now()` static method returns the number of milliseconds elapsed since the epoch, 679 * which is defined as the midnight at the beginning of January 1, 1970, UTC. 680 * 681 * @see ECMA-262, 21.4.3.1 682 * 683 * @returns A number representing the number of milliseconds elapsed since the epoch, 684 * which is defined as the midnight at the beginning of January 1, 1970, UTC. 685 */ 686 public static native now(): number; 687 688 /** 689 * Gets local time offset. 690 * 691 * @returns local time offset. 692 */ 693 public static native getLocalTimezoneOffset(ms: long): long; 694 695 /** 696 * Gets time zone name. 697 * 698 * @returns time zone name. 699 */ 700 public static native getTimezoneName(ms: long): String; 701 702 /** 703 * Gets locale string representation according to format. 704 * 705 * @param format 706 * 707 * @param locale 708 * 709 * @param ms 710 * 711 * @param isUTC 712 * 713 * @returns locale string in the specified format. 714 */ 715 public static native getLocaleString(format: String, locale: String, ms: long, isUTC: boolean): String; 716 717 /** 718 * Gets a string with a language-sensitive representation of the time portion of the date. 719 * 720 * @returns a language-sensitive representation of the time portion of the date. 721 */ 722 public toLocaleTimeString(): string { 723 return Date.getLocaleString("%EX", "", this.ms, false); 724 } 725 726 /** 727 * Gets a string with a language-sensitive representation of the time portion of the date with respect to locale. 728 * 729 * @param locale 730 * 731 * @returns a language-sensitive representation of the time portion of the date with respect to locale. 732 */ 733 public toLocaleTimeString(locale: string): string { 734 return Date.getLocaleString("%EX", locale, this.ms, false); 735 } 736 737 /** 738 * Gets a string with a language-sensitive representation of this date. 739 * 740 * @returns a language-sensitive representation of this date. 741 */ 742 public toLocaleString(): string { 743 return Date.getLocaleString("%Ex %EX", "", this.ms, false); 744 } 745 746 /** 747 * Gets a string with a language-sensitive representation of this date with respect to locale. 748 * 749 * @param locale 750 * 751 * @returns a language-sensitive representation of this date. 752 */ 753 public toLocaleString(locale: string): string { 754 return Date.getLocaleString("%Ex %EX", locale, this.ms, false); 755 } 756 757 /** 758 * Gets a string with a language-sensitive representation 759 * of the date portion of the specified date in the user agent's timezone. 760 * 761 * @returns a string with a language-sensitive representation 762 * of the date portion of the specified date in the user agent's timezone. 763 */ 764 public toLocaleDateString(): string { 765 return Date.getLocaleString("%Ex", "", this.ms, false); 766 } 767 768 /** 769 * Returns a string with a language-sensitive representation 770 * of the date portion of the specified date in the user agent's timezone. 771 * 772 * @returns a string with a language-sensitive representation 773 * of the date portion of the specified date in the user agent's timezone. 774 */ 775 public toLocaleDateString(locale: string): string { 776 return Date.getLocaleString("%Ex", locale, this.ms, false); 777 } 778 779 /** 780 * The `getDate()` method returns the day of the month for the specified date according to local time. 781 * 782 * @see ECMA-262, 21.4.4.2 783 * 784 * @returns An integer number, between 1 and 31, representing the day of the month for the given date according to local time. 785 */ 786 public getDate(): number { 787 let localTime = this.ms - this.TZOffset * 60 * msPerSecond; 788 let day: int = ecmaDayFromTime(localTime) - ecmaDayFromYear(ecmaYearFromTime(localTime)); 789 let inLeapYear = ecmaInLeapYear(this.getFullYear() as int); 790 let firstDay: int = getFirstDayInMonth(inLeapYear, ecmaMonthFromTime(localTime)); 791 return (day - firstDay + 1) as number; 792 } 793 794 /** 795 * Changes the day of the month of a given Date instance, based on local time. 796 * 797 * @param value new day. 798 */ 799 public setDate(value: byte): void { 800 let day = this.getDate(); 801 this.ms -= day * msPerDay; 802 this.ms += value * msPerDay; 803 } 804 805 /** 806 * Changes the day of the month of a given Date instance, based on local time. 807 * 808 * @param value new day. 809 */ 810 public setDate(value: number): number { 811 this.setDate(value as byte); 812 return this.ms as number; 813 } 814 815 /** 816 * Alias to @link{setDate} and left for compatibility with ECMA-262. 817 * 818 * @param value new day. 819 */ 820 public setDay(value: byte): void { 821 this.setDate(value); 822 } 823 824 /** 825 * Returns the day of the month (from 1 to 31) in the specified date according to universal time. 826 * 827 * @returns An integer number, between 1 and 31, representing the day of the month for the given date according to local time. 828 */ 829 public getUTCDate(): number { 830 let localTime = this.ms; 831 let day: int = ecmaDayFromTime(localTime) - ecmaDayFromYear(ecmaYearFromTime(localTime)); 832 let inLeapYear = ecmaInLeapYear(this.getFullYear() as int); 833 let firstDay: int = getFirstDayInMonth(inLeapYear, ecmaMonthFromTime(localTime)); 834 return (day - firstDay + 1) as number; 835 } 836 837 /** 838 * Changes the day of the month of a given Date instance, based on UTC time. 839 * 840 * @param value new day. 841 */ 842 public setUTCDate(value: byte): void { 843 let day = this.getUTCDate() as byte; 844 this.ms -= day * msPerDay; 845 this.ms += value * msPerDay; 846 } 847 848 /** 849 * Changes the day of the month of a given Date instance, based on UTC time. 850 * 851 * @param value new day. 852 */ 853 public setUTCDate(value: number): number { 854 this.setUTCDate(value as byte); 855 return this.ms as number; 856 } 857 858 /** 859 * Changes the day of the month of a given Date instance, based on UTC time. 860 * 861 * @param value new day. 862 */ 863 public setUTCDay(value: byte): void { 864 this.setUTCDate(value); 865 } 866 867 /** 868 * Changes the day of the month of a given Date instance, based on UTC time. 869 * 870 * @param value new day. 871 */ 872 public setUTCDay(value: number): number { 873 this.setUTCDate(value); 874 return this.ms as number; 875 } 876 877 /** 878 * Returns the day of the week for the specified date according to local time, 879 * where 0 represents Sunday. For the day of the month, see @link{getDayOfMonth}. 880 * 881 * @see ECMA-262, 21.4.4.3 882 * 883 * @returns An integer number, between 0 and 6, corresponding to the day of the week 884 * for the given date, according to local time: 0 for Sunday, 1 for Monday, 2 for Tuesday, and so on. 885 */ 886 public getDay(): number { 887 return ecmaWeekDay(this.ms - this.TZOffset * 60 * msPerSecond) as number; 888 } 889 890 /** 891 * Returns the day of the week in the specified date according to universal time, where 0 represents Sunday. 892 * 893 * @returns An integer number, between 0 and 6, corresponding to the day of the week 894 * for the given date, according to local time: 0 for Sunday, 1 for Monday, 2 for Tuesday, and so on. 895 */ 896 public getUTCDay(): number { 897 return ecmaWeekDay(this.ms) as number; 898 } 899 900 /** 901 * Returns the year of the specified date according to local time. 902 * 903 * @see ECMA-262, 21.4.4.4 904 * deprecated 905 * @note This function is an alias to @link{getFullYear} and left for compatibility with ECMA-262. 906 * 907 * @returns year 908 */ 909 public getYear(): int { 910 return this.getFullYear() as int; 911 } 912 913 /** 914 * Returns the year of the specified date according to local time. 915 * 916 * @returns A year of the specified date according to local time. 917 * 918 * @description The value returned by `getUTCFullYear()` is an absolute number. 919 * For dates between the years 1000 and 9999, `getUTCFullYear()` returns a four-digit number, 920 * for example, 1995. Use this function to make sure a year is compliant with years after 2000. 921 * 922 * @returns year 923 */ 924 public getUTCFullYear(): number { 925 return ecmaYearFromTime(this.ms) as number; 926 } 927 928 /** 929 * Returns the year of the specified date according to local time. 930 * 931 * @see ECMA-262, 21.4.4.4 932 * 933 * @returns A number corresponding to the year of the given date, according to local time. 934 * 935 * @description The value returned by `getFullYear()` is an absolute number. 936 * For dates between the years 1000 and 9999, `getFullYear()` returns a four-digit number, 937 * for example, 1995. Use this function to make sure a year is compliant with years after 2000. 938 * 939 * @example 940 * ```sts 941 * const today = new Date(); 942 * const year = today.getYearFull(); 943 * ``` 944 */ 945 public getFullYear(): number { 946 let localTime = this.ms - this.TZOffset * 60 * msPerSecond; 947 return ecmaYearFromTime(localTime) as number; 948 } 949 950 /** 951 * Sets the full year for a specified date according to universal time. 952 * 953 * @param value new year 954 */ 955 public setUTCFullYear(value: number, month?: number, date?: number): number { 956 this.setUTCFullYear(value as int); 957 if (month !== undefined) { 958 this.setUTCMonth(month.intValue()); 959 } 960 if (date !== undefined) { 961 this.setUTCDate(date.byteValue()); 962 } 963 return this.ms as number; 964 } 965 966 /** 967 * Sets the full year for a specified date according to universal time. 968 * 969 * @param value new year 970 */ 971 public setUTCFullYear(value: int): void { 972 let year = ecmaYearFromTime(this.ms); 973 this.ms -= ecmaDayFromYear(year) * msPerDay as long; 974 this.ms += ecmaDayFromYear(value) * msPerDay as long; 975 } 976 977 /** 978 * This function is an alias to @link{setFullYear} and left for compatibility with ECMA-262. 979 * 980 * @param value new year 981 */ 982 public setYear(value: number): void { 983 this.setYear(value as int) 984 } 985 986 /** 987 * This function is an alias to @link{setFullYear} and left for compatibility with ECMA-262. 988 * 989 * @param value new year 990 */ 991 public setYear(value: int): void { 992 this.setFullYear(value); 993 } 994 995 /** 996 * Sets the full year for a specified date according to local time. 997 * 998 * @param value new year 999 */ 1000 public setFullYear(value: number, month?: Number, date?: Number): number { 1001 this.setFullYear(value as int); 1002 if (month !== undefined) { 1003 this.setMonth(month.intValue()); 1004 } 1005 if (date !== undefined) { 1006 this.setDate(date.byteValue()); 1007 } 1008 return this.ms as number; 1009 } 1010 1011 /** 1012 * Sets the full year for a specified date according to local time. 1013 * 1014 * @param value new year 1015 */ 1016 public setFullYear(value: int): void { 1017 let year = ecmaYearFromTime(this.ms - this.TZOffset * 60 * msPerSecond); 1018 this.ms -= ecmaDayFromYear(year) * msPerDay as long; 1019 this.ms += ecmaDayFromYear(value) * msPerDay as long; 1020 } 1021 1022 /** 1023 * Returns the hour for the specified date, according to local time. 1024 * 1025 * @see ECMA-262, 21.4.4.5 1026 * 1027 * @returns An integer number, between 0 and 23, representing the hour for the given date according to local time. 1028 * 1029 * @example 1030 * ```sts 1031 * const today = new Date(); 1032 * const hours = today.getHour(); 1033 * ``` 1034 */ 1035 public getHours(): number { 1036 let localTime = this.ms - this.TZOffset * 60 * msPerSecond; 1037 return ecmaHourFromTime(localTime) as number; 1038 } 1039 1040 /** 1041 * Returns the hours in the specified date according to universal time. 1042 * 1043 * @returns An integer number, between 0 and 23, representing the hour for the given date according to UTC time. 1044 */ 1045 public getUTCHours(): number { 1046 return ecmaHourFromTime(this.ms) as number; 1047 } 1048 1049 /** 1050 * Sets the hours for a specified date according to local time. 1051 * 1052 * @param value new hours 1053 */ 1054 public setHours(value: byte): void { 1055 assert value >= 0 && value <= 23; 1056 let hours = ecmaHourFromTime(this.ms - this.TZOffset * 60 * msPerSecond); 1057 this.ms -= msPerHour * hours; 1058 this.ms += msPerHour * value; 1059 } 1060 1061 /** 1062 * Sets the hours for a specified date according to local time. 1063 * 1064 * @param value new hours 1065 */ 1066 public setHours(value: number, min?: number, sec?: number, ms?: number): number { 1067 this.setHours(value as byte); 1068 if (min !== undefined) { 1069 this.setMinutes(min.byteValue()); 1070 } 1071 if (sec !== undefined) { 1072 this.setSeconds(sec.byteValue()); 1073 } 1074 if (ms !== undefined) { 1075 this.setMilliseconds(ms.shortValue()); 1076 } 1077 return this.ms as number; 1078 } 1079 1080 /** 1081 * Sets the hour for a specified date according to universal time. 1082 * 1083 * @param value new hours 1084 */ 1085 public setUTCHours(value: byte): void { 1086 assert value >= 0 && value <= 23; 1087 let hours = ecmaHourFromTime(this.ms); 1088 this.ms -= msPerHour * hours; 1089 this.ms += msPerHour * value; 1090 } 1091 1092 /** 1093 * Sets the hour for a specified date according to universal time. 1094 * 1095 * @param value new hours 1096 */ 1097 public setUTCHours(value: number, min?: number, sec?: number, ms?: number): number { 1098 this.setUTCHours(value as byte); 1099 if (min !== undefined) { 1100 this.setUTCMinutes(min.byteValue()); 1101 } 1102 if (sec !== undefined) { 1103 this.setUTCSeconds(sec.byteValue()); 1104 } 1105 if (ms !== undefined) { 1106 this.setUTCMilliseconds(ms.shortValue()); 1107 } 1108 return this.ms as number; 1109 } 1110 1111 /** 1112 * Returns the milliseconds in the specified date according to local time. 1113 * 1114 * @see ECMA-262, 21.4.4.6 1115 * 1116 * @returns A number between 0 and 999 representing the milliseconds for the given date according to local time. 1117 * 1118 * @example 1119 * ```sts 1120 * const today = new Date(); 1121 * const milliseconds = today.getMilliseconds(); 1122 * ``` 1123 */ 1124 public getMilliseconds(): number { 1125 let localTime = this.ms - this.TZOffset * 60 * msPerSecond; 1126 return ecmaMsFromTime(localTime) as number; 1127 } 1128 1129 /** 1130 * Returns the number of milliseconds elapsed since the epoch, 1131 * which is defined as the midnight at the beginning of January 1, 1970, UTC. 1132 * 1133 * @param d to be converted to milliseconds. 1134 * 1135 * @see ECMA-262, 21.4.3.1 1136 * 1137 * @returns A number representing the number of milliseconds elapsed since the epoch, 1138 * which is defined as the midnight at the beginning of January 1, 1970, UTC. 1139 */ 1140 public static UTC(d: Date): long { 1141 return d.valueOf() as long; 1142 } 1143 1144 /** 1145 * Returns the number of milliseconds elapsed since the epoch, 1146 * which is defined as the midnight at the beginning of January 1, 1970, UTC. 1147 * 1148 * @param year to be converted to milliseconds. 1149 * 1150 * @returns A number representing the number of milliseconds elapsed since the epoch, 1151 * which is defined as the midnight at the beginning of January 1, 1970, UTC. 1152 */ 1153 public static UTC(year: number): number { 1154 return ecmaMakeDate(ecmaMakeDay(year, 0.0, 1.0), ecmaMakeTime(0.0, 0.0, 0.0, 0.0)) as number 1155 } 1156 1157 /** 1158 * Returns the number of milliseconds elapsed since the epoch, 1159 * which is defined as the midnight at the beginning of January 1, 1970, UTC. 1160 * 1161 * @param year to be converted to milliseconds. 1162 * 1163 * @param month to be converted to milliseconds. 1164 * 1165 * @param day to be converted to milliseconds. 1166 * 1167 * @param hours to be converted to milliseconds. 1168 * 1169 * @param minutes to be converted to milliseconds. 1170 * 1171 * @param seconds to be converted to milliseconds. 1172 * 1173 * @param ms to be converted to milliseconds. 1174 * 1175 * @returns A number representing the number of milliseconds elapsed since the epoch, 1176 * which is defined as the midnight at the beginning of January 1, 1970, UTC. 1177 */ 1178 1179 public static UTC(year: number, month: number, day?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): number { 1180 return ecmaMakeDate( 1181 ecmaMakeDay( 1182 year, 1183 month, 1184 day != undefined ? day as number: 1.0 1185 ), 1186 ecmaMakeTime( 1187 hours != undefined ? hours as number : 0, 1188 minutes != undefined ? minutes as number : 0, 1189 seconds != undefined ? seconds as number : 0, 1190 ms != undefined ? ms as number : 0 1191 ) 1192 ) as number; 1193 } 1194 1195 /** 1196 * Returns the milliseconds portion of the time object's value according to universal time. 1197 * 1198 * @returns the milliseconds portion of the time object's value according to universal time. 1199 */ 1200 public getUTCMilliseconds(): number { 1201 let localTime = this.ms; 1202 return ecmaMsFromTime(localTime) as number; 1203 } 1204 1205 /** 1206 * Sets the milliseconds for a specified date according to local time. 1207 * 1208 * @param value new ms 1209 */ 1210 public setMilliseconds(value: short): void { 1211 let ms = ecmaMsFromTime(this.ms - this.TZOffset * 60 * msPerSecond); 1212 this.ms -= ms; 1213 this.ms += value; 1214 } 1215 1216 /** 1217 * Sets the milliseconds for a specified date according to local time. 1218 * 1219 * @param value new ms 1220 */ 1221 public setMilliseconds(value: number): number { 1222 this.setMilliseconds(value as short); 1223 return this.ms as number; 1224 } 1225 1226 /** 1227 * Sets the milliseconds for a specified date according to universal time. 1228 * 1229 * @param value new ms 1230 */ 1231 public setUTCMilliseconds(value: short): void { 1232 let ms = ecmaMsFromTime(this.ms); 1233 this.ms -= ms; 1234 this.ms += value; 1235 } 1236 1237 /** 1238 * Sets the milliseconds for a specified date according to universal time. 1239 * 1240 * @param value new ms 1241 */ 1242 public setUTCMilliseconds(value: number): number { 1243 this.setUTCMilliseconds(value as short); 1244 return this.ms as number; 1245 } 1246 1247 /** 1248 * Returns the seconds in the specified date according to local time. 1249 * 1250 * @see ECMA-262, 21.4.4.9 1251 * 1252 * @returns An integer number, between 0 and 59, representing the seconds in the given date according to local time. 1253 * 1254 * @example 1255 * ```sts 1256 * const today = new Date(); 1257 * const seconds = today.getSeconds(); 1258 * ``` 1259 */ 1260 public getSeconds(): number { 1261 let localTime = this.ms - this.TZOffset * 60 * msPerSecond; 1262 return ecmaSecFromTime(localTime) as number; 1263 } 1264 1265 /** 1266 * Returns the seconds in the specified date according to universal time. 1267 * 1268 * @returns the seconds in the specified date according to universal time. 1269 */ 1270 public getUTCSeconds(): number { 1271 return ecmaSecFromTime(this.ms) as number; 1272 } 1273 1274 /** 1275 * Sets the seconds for a specified date according to local time. 1276 * 1277 * @param value new seconds 1278 */ 1279 public setSeconds(value: number, ms?: number): number { 1280 this.setSeconds(value as byte); 1281 if (ms !== undefined) { 1282 this.setMilliseconds(ms.shortValue()); 1283 } 1284 return this.ms as number; 1285 } 1286 1287 /** 1288 * Sets the seconds for a specified date according to local time. 1289 * 1290 * @param value new seconds 1291 */ 1292 public setSeconds(value: byte): void { 1293 assert value >= 0 && value < 60; 1294 let sec = ecmaSecFromTime(this.ms - this.TZOffset * 60 * msPerSecond); 1295 this.ms -= sec * msPerSecond; 1296 this.ms += value * msPerSecond; 1297 } 1298 1299 /** 1300 * Sets the seconds for a specified date according to universal time. 1301 * 1302 * @param value new seconds 1303 */ 1304 public setUTCSeconds(value: byte): void { 1305 assert value >= 0 && value < 60; 1306 let sec = ecmaSecFromTime(this.ms); 1307 this.ms -= sec * msPerSecond; 1308 this.ms += value * msPerSecond; 1309 } 1310 1311 /** 1312 * Sets the seconds for a specified date according to universal time. 1313 * 1314 * @param value new seconds 1315 */ 1316 public setUTCSeconds(value: number, ms?: number): number { 1317 this.setUTCSeconds(value as byte); 1318 if (ms !== undefined) { 1319 this.setUTCMilliseconds(ms.shortValue()); 1320 } 1321 return this.ms as number; 1322 } 1323 1324 /** 1325 * Returns the minutes in the specified date according to local time. 1326 * 1327 * @see ECMA-262, 21.4.4.7 1328 * 1329 * @returns An integer number, between 0 and 59, representing the minutes in the given date according to local time. 1330 * 1331 * @example 1332 * ```sts 1333 * const today = new Date(); 1334 * const minutes = today.getMinutes(); 1335 * ``` 1336 */ 1337 public getMinutes(): number { 1338 let localTime = this.ms - this.TZOffset * 60 * msPerSecond; 1339 return ecmaMinFromTime(localTime) as number; 1340 } 1341 1342 /** 1343 * Sets the minutes for a specified date according to universal time. 1344 * 1345 * @param value new minutes 1346 */ 1347 public setUTCMinutes(value: byte): void { 1348 assert value >= 0 && value < 60; 1349 let min = ecmaMinFromTime(this.ms); 1350 this.ms -= min * msPerMinute; 1351 this.ms += value * msPerMinute; 1352 } 1353 1354 /** 1355 * Sets the minutes for a specified date according to universal time. 1356 * 1357 * @param value new minutes 1358 */ 1359 public setUTCMinutes(value: number, sec?: Number, ms?: Number): number { 1360 this.setUTCMinutes(value as byte); 1361 if (sec !== undefined) { 1362 this.setUTCSeconds(sec.byteValue()); 1363 } 1364 if (ms !== undefined) { 1365 this.setUTCMilliseconds(ms.shortValue()); 1366 } 1367 return this.ms as number; 1368 } 1369 1370 /** 1371 * Returns the minutes in the specified date according to universal time. 1372 * 1373 * @returns the minutes in the specified date according to universal time. 1374 */ 1375 public getUTCMinutes(): number { 1376 return ecmaMinFromTime(this.ms) as number; 1377 } 1378 1379 /** 1380 * Sets the minutes for a specified date according to local time. 1381 * 1382 * @param value new minutes 1383 */ 1384 public setMinutes(value: byte): void { 1385 assert value >= 0 && value < 60; 1386 let min = ecmaMinFromTime(this.ms - this.TZOffset * 60 * msPerSecond); 1387 this.ms -= min * msPerMinute; 1388 this.ms += value * msPerMinute; 1389 } 1390 1391 /** 1392 * Sets the minutes for a specified date according to local time. 1393 * 1394 * @param value new minutes 1395 */ 1396 public setMinutes(value: number, sec?: number, ms?: number): number { 1397 this.setMinutes(value as byte); 1398 if (sec !== undefined) { 1399 this.setSeconds(sec.byteValue()); 1400 } 1401 if (ms !== undefined) { 1402 this.setMilliseconds(ms.shortValue()); 1403 } 1404 return this.ms as number; 1405 } 1406 1407 /** 1408 * Returns the month in the specified date according to local time, 1409 * as a zero-based value (where zero indicates the first month of the year). 1410 * 1411 * @see ECMA-262, 21.4.4.8 1412 * 1413 * @returns An integer number, between 0 and 11, representing the month in the given date according to local time. 1414 * 0 corresponds to January, 1 to February, and so on. 1415 * 1416 * @example 1417 * ```sts 1418 * const today = new Date(); 1419 * const month = today.getMonth(); 1420 * ``` 1421 */ 1422 public getMonth(): number { 1423 let localTime = this.ms - this.TZOffset * 60 * msPerSecond; 1424 return ecmaMonthFromTime(localTime) as number; 1425 } 1426 1427 /** 1428 * Returns the month of the specified date according to universal time, as a zero-based value (where zero indicates the first month of the year). 1429 * 1430 * @returns An integer number, between 0 and 11, representing the month in the given date according to UTC time. 1431 * 0 corresponds to January, 1 to February, and so on. 1432 */ 1433 public getUTCMonth(): number { 1434 return ecmaMonthFromTime(this.ms) as number; 1435 } 1436 1437 /** 1438 * Sets the month for a specified date according to the currently set year. 1439 * 1440 * @param month new month 1441 */ 1442 public setMonth(month: number, date?: number): number { 1443 this.setMonth(month as int); 1444 if (date !== undefined) { 1445 this.setDate(date.byteValue()); 1446 } 1447 return this.ms as number; 1448 } 1449 1450 /** 1451 * Sets the month for a specified date according to the currently set year. 1452 * 1453 * @param month new month 1454 */ 1455 public setMonth(month: int): void { 1456 let inLeapYear = ecmaInLeapYear(this.getFullYear() as int); 1457 let daysNow: int = getFirstDayInMonth(inLeapYear, ecmaMonthFromTime(this.ms - this.TZOffset * 60 * msPerSecond)); 1458 let daysNew: int = getFirstDayInMonth(inLeapYear, month); 1459 this.ms -= daysNow * msPerDay; 1460 this.ms += daysNew * msPerDay; 1461 } 1462 1463 /** 1464 * Sets the month for a specified date according to universal time. 1465 * 1466 * @param month new month 1467 */ 1468 public setUTCMonth(month: number, date?: number): number { 1469 this.setUTCMonth(month as int); 1470 if (date !== undefined) { 1471 this.setUTCDate(date.byteValue()); 1472 } 1473 return this.ms as number; 1474 } 1475 1476 /** 1477 * Sets the month for a specified date according to universal time. 1478 * 1479 * @param month new month 1480 */ 1481 public setUTCMonth(month: int): void { 1482 let inLeapYear = ecmaInLeapYear(this.getFullYear() as int); 1483 let daysNow: int = getFirstDayInMonth(inLeapYear, ecmaMonthFromTime(this.ms)); 1484 let daysNew: int = getFirstDayInMonth(inLeapYear, month); 1485 this.ms -= daysNow * msPerDay; 1486 this.ms += daysNew * msPerDay; 1487 } 1488 1489 /** 1490 * Returns the number of milliseconds since the epoch, 1491 * which is defined as the midnight at the beginning of January 1, 1970, UTC. 1492 * 1493 * @see ECMA-262, 21.4.4.10 1494 * 1495 * @returns A number representing the milliseconds elapsed between 1 January 1970 00:00:00 UTC and the given date. 1496 */ 1497 public getTime(): number { 1498 return this.valueOf(); 1499 } 1500 1501 /** 1502 * Sets the number of milliseconds since the epoch, 1503 * which is defined as the midnight at the beginning of January 1, 1970, UTC. 1504 * 1505 * @param value new ms 1506 * 1507 * @see ECMA-262, 21.4.4.10 1508 * 1509 * @returns A number representing the milliseconds elapsed between 1 January 1970 00:00:00 UTC and the given date. 1510 */ 1511 public setTime(value: long): void { 1512 this.ms = value; 1513 } 1514 1515 /** 1516 * Sets the number of milliseconds since the epoch, 1517 * which is defined as the midnight at the beginning of January 1, 1970, UTC. 1518 * 1519 * @param value new ms 1520 * 1521 * @see ECMA-262, 21.4.4.10 1522 * 1523 * @returns A number representing the milliseconds elapsed between 1 January 1970 00:00:00 UTC and the given date. 1524 */ 1525 public setTime(value: number): number { 1526 this.setTime(value as long); 1527 return this.ms as number; 1528 } 1529 1530 /** 1531 * Parses a string representation of a date, 1532 * and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC 1533 * or raises `InvalidDate` if the string is unrecognized or, in some cases, 1534 * contains illegal date values (e.g. 2015-02-31). 1535 * 1536 * Only the @link{https://tc39.es/ecma262/#sec-date-time-string-format|ISO 8601 format} 1537 * (YYYY-MM-DDTHH:mm:ss.sssZ) is explicitly specified to be supported. 1538 * Other formats are implementation-defined and may not work across all browsers (targets). 1539 * A library can help if many different formats are to be accommodated. 1540 * 1541 * @param dateStr to be parsed 1542 * 1543 * @see ECMA-262, 21.4.3.2 1544 * 1545 * @returns A number representing the milliseconds elapsed since January 1, 1970, 00:00:00 UTC 1546 * and the date obtained by parsing the given string representation of a date. 1547 * If the argument doesn't represent a valid date, `InvalidDate` exception is thrown. 1548 */ 1549 public static parse(dateStr: string): number { 1550 return Date.parseDateFromString(dateStr) as number; 1551 } 1552 1553 /** 1554 * Returns the difference, in minutes, between a date as 1555 * evaluated in the UTC time zone, and the same date as evaluated in the local time zone. 1556 * 1557 * @returns the difference, in minutes, between a date as 1558 * evaluated in the UTC time zone, and the same date as evaluated in the local time zone. 1559 */ 1560 public getTimezoneOffset(): number { 1561 return this.TZOffset as number; 1562 } 1563 1564 /** 1565 * Sets the difference, in minutes, between a date as 1566 * evaluated in the UTC time zone, and the same date as evaluated in the local time zone. 1567 * 1568 * @param value new timezone offset 1569 */ 1570 public setTimezoneOffset(value: number): number { 1571 return this.setTimezoneOffset(value as int) as number 1572 } 1573 1574 /** 1575 * Sets the difference, in minutes, between a date as 1576 * evaluated in the UTC time zone, and the same date as evaluated in the local time zone. 1577 * 1578 * @param value new timezone offset 1579 */ 1580 public setTimezoneOffset(value: int): long { 1581 this.TZOffset = value; 1582 } 1583 1584 /** 1585 * Returns a string in simplified extended ISO format (ISO 8601), 1586 * which is always 24 or 27 characters long (YYYY-MM-DDTHH:mm:ss.sssZ or 1587 * ±YYYYYY-MM-DDTHH:mm:ss.sssZ, respectively). The timezone is always zero UTC offset, 1588 * as denoted by the suffix Z. 1589 * 1590 * @see ECMA-262, 21.4.4.36 1591 * 1592 * @returns A string representing the given date in the ISO 8601 format according to universal time. 1593 * It's the same format as the one required to be recognized by @link{parse()}. 1594 * 1595 * @example 1596 * ```sts 1597 * const today = new Date(); 1598 * console.println(today.toISOString()); // Returns 2023-02-05T14:48:00.000Z 1599 * ``` 1600 */ 1601 public toISOString(): string { 1602 let sb = new StringBuilder(); 1603 let y = this.getUTCFullYear(); 1604 if (y < 0) { 1605 sb.append("-"); 1606 } 1607 if (abs(y) < 1000) { 1608 sb.append("0"); 1609 } 1610 if (abs(y) < 100) { 1611 sb.append("0"); 1612 } 1613 if (abs(y) < 10) { 1614 sb.append("0"); 1615 } 1616 sb.append(abs(y) as long); 1617 sb.append("-"); 1618 let month = this.getUTCMonth() + 1; 1619 if(month < 10){ 1620 sb.append("0"); 1621 } 1622 sb.append(month); 1623 sb.append("-"); 1624 let day = this.getUTCDate(); 1625 if(day < 10){ 1626 sb.append("0"); 1627 } 1628 sb.append(day); 1629 sb.append("T"); 1630 let h = this.getUTCHours(); 1631 if(h < 10) { 1632 sb.append("0"); 1633 } 1634 sb.append(h); 1635 sb.append(":"); 1636 let m = this.getUTCMinutes(); 1637 if(m < 10) { 1638 sb.append("0"); 1639 } 1640 sb.append(m); 1641 sb.append(":"); 1642 let s = this.getUTCSeconds(); 1643 if(s < 10) { 1644 sb.append("0"); 1645 } 1646 sb.append(s); 1647 sb.append("."); 1648 let ms = this.getUTCMilliseconds(); 1649 if (ms < 10) { 1650 sb.append("00") 1651 } 1652 else if (ms < 100) { 1653 sb.append("0") 1654 } 1655 // sb.append(ms / 100); 1656 // sb.append((ms / 10) % 10); 1657 // sb.append(ms % 10); 1658 sb.append(trunc(ms)) 1659 sb.append("Z"); 1660 return sb.toString(); 1661 } 1662 1663 /** 1664 * Returns a string representation of the Date object. 1665 * 1666 * @returns JSON representation of the current instance 1667 */ 1668 public toJSON(): string { 1669 return this.toISOString(); 1670 } 1671 1672 /** 1673 * Returns the time portion of a `Date` object interpreted in the local timezone in English. 1674 * 1675 * @see ECMA-262, 21.4.4.42 1676 * 1677 * @returns A string representing the time portion of the given date in human-readable form in English. 1678 * 1679 * @example 1680 * ``` 1681 * let d = new Date(1979.0, 9.0, 27.0, 13.0, 12.8, 57.0, 444.1); 1682 * console.println(d.toTimeString()); // 13:12:57 GMT 1683 * ``` 1684 */ 1685 public toTimeString(): string { 1686 return this.timeString() + " " + this.timeZoneString(); 1687 } 1688 1689 /** 1690 * Returns string representation 1691 */ 1692 private timeString(): String { 1693 if (!this.isDateValid()) { 1694 throw new Error("Invalid Date"); 1695 } 1696 1697 let sb = new StringBuilder(); 1698 let h = this.getHours(); 1699 if (h < 10) { 1700 sb.append("0"); 1701 } 1702 sb.append(h); 1703 sb.append(":"); 1704 let m = this.getMinutes(); 1705 if (m < 10) { 1706 sb.append("0"); 1707 } 1708 sb.append(m); 1709 sb.append(":"); 1710 let s = this.getSeconds(); 1711 if (s < 10) { 1712 sb.append("0"); 1713 } 1714 sb.append(s); 1715 return sb.toString(); 1716 } 1717 1718 /** 1719 * Returns the date portion of a `Date` object interpreted in the local timezone in English. 1720 * 1721 * @see ECMA-262, 21.4.4.35 1722 * 1723 * @returns A string representing the date portion of the given Date object in human-readable form in English. 1724 * 1725 * @example 1726 * ``` 1727 * let d = new Date(1979.0, 9.0, 27.0, 13.0, 12.8, 57.0, 444.1); 1728 * console.println(d.toDateString()); // Sat Oct 27 1979 1729 * ``` 1730 */ 1731 public toDateString(): string { 1732 return this.dateString(); 1733 } 1734 1735 /** 1736 * Returns a string representation 1737 */ 1738 private dateString(): String { 1739 if (!this.isDateValid()) { 1740 throw new Error("Invalid Date"); 1741 } 1742 1743 let sb = new StringBuilder(); 1744 sb.append(dayNames[this.getDay() as int]); 1745 sb.append(" "); 1746 sb.append(monthNames[this.getMonth() as int]); 1747 sb.append(" "); 1748 let d = this.getDate(); 1749 if (d < 10) { 1750 sb.append("0"); 1751 } 1752 sb.append(d); 1753 sb.append(" "); 1754 let y = this.getFullYear(); 1755 if (y < 0) { 1756 sb.append("-"); 1757 } 1758 if (abs(y) < 1000) { 1759 sb.append("0"); 1760 } 1761 if (abs(y) < 100) { 1762 sb.append("0"); 1763 } 1764 if (abs(y) < 10) { 1765 sb.append("0"); 1766 } 1767 sb.append(abs(y) as long); 1768 return sb.toString(); 1769 } 1770 1771 /** 1772 * TODO Until TZ support implemented, the time is calculated in UTC+0 and TZ string is hardcoded 1773 */ 1774 private timeZoneString(): String { 1775 let sb = new StringBuilder(); 1776 sb.append("GMT"); 1777 let offset = -this.TZOffset; 1778 let hours = offset / 60; 1779 if(hours < 0) { 1780 sb.append("-"); 1781 } else { 1782 sb.append("+") 1783 } 1784 if (abs(hours) < 10) { 1785 sb.append("0"); 1786 } 1787 sb.append(abs(hours)); 1788 let minutes = abs(offset % 60); 1789 if (minutes < 10) { 1790 sb.append("0"); 1791 } 1792 sb.append(minutes); 1793 sb.append(" ("); 1794 sb.append(Date.getTimezoneName(this.ms)); 1795 sb.append(")"); 1796 1797 return sb.toString(); 1798 } 1799 /** 1800 * Returns a string representing the specified `Date` object interpreted in the local timezone. 1801 * 1802 * @see ECMA-262, 21.4.4.41 1803 * 1804 * @returns A string representing the given date. 1805 * 1806 * @example 1807 * ``` 1808 * let d = new Date(1979.0, 9.0, 27.0, 13.0, 12.8, 57.0, 444.1); 1809 * console.println(d.toString()); // Sat Oct 27 1979 13:12:57 GMT 1810 * ``` 1811 */ 1812 public override toString(): string { 1813 let res: String = "Invalid date"; 1814 try { 1815 res = this.toDateString() + " " + this.toTimeString(); 1816 } 1817 catch (e) {} 1818 return res; 1819 } 1820 1821 /** 1822 * Returns a string representing the specified `Date` object interpreted in UTC. 1823 * 1824 * @see ECMA-262, 21.4.4.41 1825 * 1826 * @returns A string representing the given date. 1827 * 1828 * @example 1829 * ``` 1830 * let d = new Date(1979.0, 9.0, 27.0, 13.0, 12.8, 57.0, 444.1); 1831 * console.println(d.toUTCString()); // Sat Oct 27 1979 13:12:57 GMT 1832 * ``` 1833 */ 1834 public toUTCString(): string { 1835 if (!this.isDateValid()) { 1836 throw new Error("Invalid Date"); 1837 } 1838 let s: String = this.toUTCDateString() + " " + this.toUTCTimeString(); 1839 return s; 1840 } 1841 1842 private toUTCDateString(): string { 1843 let sb = new StringBuilder(); 1844 sb.append(dayNames[this.getUTCDay() as int]); 1845 sb.append(", "); 1846 let d = this.getUTCDate(); 1847 if (d < 10) { 1848 sb.append("0"); 1849 } 1850 sb.append(d); 1851 sb.append(" "); 1852 sb.append(monthNames[this.getUTCMonth() as int]); 1853 sb.append(" "); 1854 let y = this.getUTCFullYear(); 1855 if (y < 0) { 1856 sb.append("-"); 1857 } 1858 y = abs(y); 1859 if (y < 1000) { 1860 sb.append("0"); 1861 } 1862 if (y < 100) { 1863 sb.append("0"); 1864 } 1865 if (y < 10) { 1866 sb.append("0"); 1867 } 1868 sb.append(y as long); 1869 return sb.toString(); 1870 } 1871 1872 private toUTCTimeString(): string { 1873 let sb = new StringBuilder(); 1874 let h = this.getUTCHours(); 1875 if (h < 10) { 1876 sb.append("0"); 1877 } 1878 sb.append(h); 1879 sb.append(":"); 1880 let m = this.getUTCMinutes(); 1881 if (m < 10) { 1882 sb.append("0"); 1883 } 1884 sb.append(m); 1885 sb.append(":"); 1886 let s = this.getUTCSeconds(); 1887 if (s < 10) { 1888 sb.append("0"); 1889 } 1890 sb.append(s); 1891 sb.append(" GMT") 1892 return sb.toString(); 1893 } 1894 1895 /** 1896 * Parses int from substring if indexes are in string 1897 */ 1898 private static parseIfContains(dateStr: String, begin: int, end: int): int { 1899 if (dateStr.length >= end && begin < end) { 1900 return Double.parseInt(dateStr.substring(begin, end)) as int; 1901 } 1902 return Date.UNSUCCESSFUL_PARSING; 1903 } 1904 1905 private static readonly UNSUCCESSFUL_PARSING: int = -1; 1906} 1907