vendor: 6,345 bytes, lines 1-394
1// these aren't really private, but nor are they really useful to document 2 3/** 4 * @private 5 */ 6class LuxonError extends Error {} 7 8/** 9 * @private 10 */ 11class InvalidDateTimeError extends LuxonError { 12 constructor(reason) { 13 super(`Invalid DateTime: ${reason.toMessage()}`); 14 } 15} 16 17/** 18 * @private 19 */ 20class InvalidIntervalError extends LuxonError { 21 constructor(reason) { 22 super(`Invalid Interval: ${reason.toMessage()}`); 23 } 24} 25 26/** 27 * @private 28 */ 29class InvalidDurationError extends LuxonError { 30 constructor(reason) { 31 super(`Invalid Duration: ${reason.toMessage()}`); 32 } 33} 34 35/** 36 * @private 37 */ 38class ConflictingSpecificationError extends LuxonError {} 39 40/** 41 * @private 42 */ 43class InvalidUnitError extends LuxonError { 44 constructor(unit) { 45 super(`Invalid unit ${unit}`); 46 } 47} 48 49/** 50 * @private 51 */ 52class InvalidArgumentError extends LuxonError {} 53 54/** 55 * @private 56 */ 57class ZoneIsAbstractError extends LuxonError { 58 constructor() { 59 super("Zone is an abstract class"); 60 } 61} 62 63/** 64 * @private 65 */ 66 67const n = "numeric", 68 s = "short", 69 l = "long"; 70 71const DATE_SHORT = { 72 year: n, 73 month: n, 74 day: n, 75}; 76 77const DATE_MED = { 78 year: n, 79 month: s, 80 day: n, 81}; 82 83const DATE_MED_WITH_WEEKDAY = { 84 year: n, 85 month: s, 86 day: n, 87 weekday: s, 88}; 89 90const DATE_FULL = { 91 year: n, 92 month: l, 93 day: n, 94}; 95 96const DATE_HUGE = { 97 year: n, 98 month: l, 99 day: n, 100 weekday: l, 101}; 102 103const TIME_SIMPLE = { 104 hour: n, 105 minute: n, 106}; 107 108const TIME_WITH_SECONDS = { 109 hour: n, 110 minute: n, 111 second: n, 112}; 113 114const TIME_WITH_SHORT_OFFSET = { 115 hour: n, 116 minute: n, 117 second: n, 118 timeZoneName: s, 119}; 120 121const TIME_WITH_LONG_OFFSET = { 122 hour: n, 123 minute: n, 124 second: n, 125 timeZoneName: l, 126}; 127 128const TIME_24_SIMPLE = { 129 hour: n, 130 minute: n, 131 hourCycle: "h23", 132}; 133 134const TIME_24_WITH_SECONDS = { 135 hour: n, 136 minute: n, 137 second: n, 138 hourCycle: "h23", 139}; 140 141const TIME_24_WITH_SHORT_OFFSET = { 142 hour: n, 143 minute: n, 144 second: n, 145 hourCycle: "h23", 146 timeZoneName: s, 147}; 148 149const TIME_24_WITH_LONG_OFFSET = { 150 hour: n, 151 minute: n, 152 second: n, 153 hourCycle: "h23", 154 timeZoneName: l, 155}; 156 157const DATETIME_SHORT = { 158 year: n, 159 month: n, 160 day: n, 161 hour: n, 162 minute: n, 163}; 164 165const DATETIME_SHORT_WITH_SECONDS = { 166 year: n, 167 month: n, 168 day: n, 169 hour: n, 170 minute: n, 171 second: n, 172}; 173 174const DATETIME_MED = { 175 year: n, 176 month: s, 177 day: n, 178 hour: n, 179 minute: n, 180}; 181 182const DATETIME_MED_WITH_SECONDS = { 183 year: n, 184 month: s, 185 day: n, 186 hour: n, 187 minute: n, 188 second: n, 189}; 190 191const DATETIME_MED_WITH_WEEKDAY = { 192 year: n, 193 month: s, 194 day: n, 195 weekday: s, 196 hour: n, 197 minute: n, 198}; 199 200const DATETIME_FULL = { 201 year: n, 202 month: l, 203 day: n, 204 hour: n, 205 minute: n, 206 timeZoneName: s, 207}; 208 209const DATETIME_FULL_WITH_SECONDS = { 210 year: n, 211 month: l, 212 day: n, 213 hour: n, 214 minute: n, 215 second: n, 216 timeZoneName: s, 217}; 218 219const DATETIME_HUGE = { 220 year: n, 221 month: l, 222 day: n, 223 weekday: l, 224 hour: n, 225 minute: n, 226 timeZoneName: l, 227}; 228 229const DATETIME_HUGE_WITH_SECONDS = { 230 year: n, 231 month: l, 232 day: n, 233 weekday: l, 234 hour: n, 235 minute: n, 236 second: n, 237 timeZoneName: l, 238}; 239 240/** 241 * @interface 242 */ 243class Zone { 244 /** 245 * The type of zone 246 * @abstract 247 * @type {string} 248 */ 249 get type() { 250 throw new ZoneIsAbstractError(); 251 } 252 253 /** 254 * The name of this zone. 255 * @abstract 256 * @type {string} 257 */ 258 get name() { 259 throw new ZoneIsAbstractError(); 260 } 261 262 /** 263 * The IANA name of this zone. 264 * Defaults to `name` if not overwritten by a subclass. 265 * @abstract 266 * @type {string} 267 */ 268 get ianaName() { 269 return this.name; 270 } 271 272 /** 273 * Returns whether the offset is known to be fixed for the whole year. 274 * @abstract 275 * @type {boolean} 276 */ 277 get isUniversal() { 278 throw new ZoneIsAbstractError(); 279 } 280 281 /** 282 * Returns the offset's common name (such as EST) at the specified timestamp 283 * @abstract 284 * @param {number} ts - Epoch milliseconds for which to get the name 285 * @param {Object} opts - Options to affect the format 286 * @param {string} opts.format - What style of offset to return. Accepts 'long' or 'short'. 287 * @param {string} opts.locale - What locale to return the offset name in. 288 * @return {string} 289 */ 290 offsetName(ts, opts) { 291 throw new ZoneIsAbstractError(); 292 } 293 294 /** 295 * Returns the offset's value as a string 296 * @abstract 297 * @param {number} ts - Epoch milliseconds for which to get the offset 298 * @param {string} format - What style of offset to return. 299 * Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively 300 * @return {string} 301 */ 302 formatOffset(ts, format) { 303 throw new ZoneIsAbstractError(); 304 } 305 306 /** 307 * Return the offset in minutes for this zone at the specified timestamp. 308 * @abstract 309 * @param {number} ts - Epoch milliseconds for which to compute the offset 310 * @return {number} 311 */ 312 offset(ts) { 313 throw new ZoneIsAbstractError(); 314 } 315 316 /** 317 * Return whether this Zone is equal to another zone 318 * @abstract 319 * @param {Zone} otherZone - the zone to compare 320 * @return {boolean} 321 */ 322 equals(otherZone) { 323 throw new ZoneIsAbstractError(); 324 } 325 326 /** 327 * Return whether this Zone is valid. 328 * @abstract 329 * @type {boolean} 330 */ 331 get isValid() { 332 throw new ZoneIsAbstractError(); 333 } 334} 335 336let singleton$1 = null; 337 338/** 339 * Represents the local zone for this JavaScript environment. 340 * @implements {Zone} 341 */ 342class SystemZone extends Zone { 343 /** 344 * Get a singleton instance of the local zone 345 * @return {SystemZone} 346 */ 347 static get instance() { 348 if (singleton$1 === null) { 349 singleton$1 = new SystemZone(); 350 } 351 return singleton$1; 352 } 353 354 /** @override **/ 355 get type() { 356 return "system"; 357 } 358 359 /** @override **/ 360 get name() { 361 return new Intl.DateTimeFormat().resolvedOptions().timeZone; 362 } 363 364 /** @override **/ 365 get isUniversal() { 366 return false; 367 } 368 369 /** @override **/ 370 offsetName(ts, { format, locale }) { 371 return parseZoneInfo(ts, format, locale); 372 } 373 374 /** @override **/ 375 formatOffset(ts, format) { 376 return formatOffset(this.offset(ts), format); 377 } 378 379 /** @override **/ 380 offset(ts) { 381 return -new Date(ts).getTimezoneOffset(); 382 } 383 384 /** @override **/ 385 equals(otherZone) { 386 return otherZone.type === "system"; 387 } 388 389 /** @override **/ 390 get isValid() { 391 return true; 392 } 393} 394
vendor: 23,084 bytes, lines 395-1242
395let dtfCache = {}; 396function makeDTF(zone) { 397 if (!dtfCache[zone]) { 398 dtfCache[zone] = new Intl.DateTimeFormat("en-US", { 399 hour12: false, 400 timeZone: zone, 401 year: "numeric", 402 month: "2-digit", 403 day: "2-digit", 404 hour: "2-digit", 405 minute: "2-digit", 406 second: "2-digit", 407 era: "short", 408 }); 409 } 410 return dtfCache[zone]; 411} 412 413const typeToPos = { 414 year: 0, 415 month: 1, 416 day: 2, 417 era: 3, 418 hour: 4, 419 minute: 5, 420 second: 6, 421}; 422 423function hackyOffset(dtf, date) { 424 const formatted = dtf.format(date).replace(/\u200E/g, ""), 425 parsed = /(\d+)\/(\d+)\/(\d+) (AD|BC),? (\d+):(\d+):(\d+)/.exec(formatted), 426 [, fMonth, fDay, fYear, fadOrBc, fHour, fMinute, fSecond] = parsed; 427 return [fYear, fMonth, fDay, fadOrBc, fHour, fMinute, fSecond]; 428} 429 430function partsOffset(dtf, date) { 431 const formatted = dtf.formatToParts(date); 432 const filled = []; 433 for (let i = 0; i < formatted.length; i++) { 434 const { type, value } = formatted[i]; 435 const pos = typeToPos[type]; 436 437 if (type === "era") { 438 filled[pos] = value; 439 } else if (!isUndefined(pos)) { 440 filled[pos] = parseInt(value, 10); 441 } 442 } 443 return filled; 444} 445 446let ianaZoneCache = {}; 447/** 448 * A zone identified by an IANA identifier, like America/New_York 449 * @implements {Zone} 450 */ 451class IANAZone extends Zone { 452 /** 453 * @param {string} name - Zone name 454 * @return {IANAZone} 455 */ 456 static create(name) { 457 if (!ianaZoneCache[name]) { 458 ianaZoneCache[name] = new IANAZone(name); 459 } 460 return ianaZoneCache[name]; 461 } 462 463 /** 464 * Reset local caches. Should only be necessary in testing scenarios. 465 * @return {void} 466 */ 467 static resetCache() { 468 ianaZoneCache = {}; 469 dtfCache = {}; 470 } 471 472 /** 473 * Returns whether the provided string is a valid specifier. This only checks the string's format, not that the specifier identifies a known zone; see isValidZone for that. 474 * @param {string} s - The string to check validity on 475 * @example IANAZone.isValidSpecifier("America/New_York") //=> true 476 * @example IANAZone.isValidSpecifier("Sport~~blorp") //=> false 477 * @deprecated For backward compatibility, this forwards to isValidZone, better use `isValidZone()` directly instead. 478 * @return {boolean} 479 */ 480 static isValidSpecifier(s) { 481 return this.isValidZone(s); 482 } 483 484 /** 485 * Returns whether the provided string identifies a real zone 486 * @param {string} zone - The string to check 487 * @example IANAZone.isValidZone("America/New_York") //=> true 488 * @example IANAZone.isValidZone("Fantasia/Castle") //=> false 489 * @example IANAZone.isValidZone("Sport~~blorp") //=> false 490 * @return {boolean} 491 */ 492 static isValidZone(zone) { 493 if (!zone) { 494 return false; 495 } 496 try { 497 new Intl.DateTimeFormat("en-US", { timeZone: zone }).format(); 498 return true; 499 } catch (e) { 500 return false; 501 } 502 } 503 504 constructor(name) { 505 super(); 506 /** @private **/ 507 this.zoneName = name; 508 /** @private **/ 509 this.valid = IANAZone.isValidZone(name); 510 } 511 512 /** 513 * The type of zone. `iana` for all instances of `IANAZone`. 514 * @override 515 * @type {string} 516 */ 517 get type() { 518 return "iana"; 519 } 520 521 /** 522 * The name of this zone (i.e. the IANA zone name). 523 * @override 524 * @type {string} 525 */ 526 get name() { 527 return this.zoneName; 528 } 529 530 /** 531 * Returns whether the offset is known to be fixed for the whole year: 532 * Always returns false for all IANA zones. 533 * @override 534 * @type {boolean} 535 */ 536 get isUniversal() { 537 return false; 538 } 539 540 /** 541 * Returns the offset's common name (such as EST) at the specified timestamp 542 * @override 543 * @param {number} ts - Epoch milliseconds for which to get the name 544 * @param {Object} opts - Options to affect the format 545 * @param {string} opts.format - What style of offset to return. Accepts 'long' or 'short'. 546 * @param {string} opts.locale - What locale to return the offset name in. 547 * @return {string} 548 */ 549 offsetName(ts, { format, locale }) { 550 return parseZoneInfo(ts, format, locale, this.name); 551 } 552 553 /** 554 * Returns the offset's value as a string 555 * @override 556 * @param {number} ts - Epoch milliseconds for which to get the offset 557 * @param {string} format - What style of offset to return. 558 * Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively 559 * @return {string} 560 */ 561 formatOffset(ts, format) { 562 return formatOffset(this.offset(ts), format); 563 } 564 565 /** 566 * Return the offset in minutes for this zone at the specified timestamp. 567 * @override 568 * @param {number} ts - Epoch milliseconds for which to compute the offset 569 * @return {number} 570 */ 571 offset(ts) { 572 const date = new Date(ts); 573 574 if (isNaN(date)) return NaN; 575 576 const dtf = makeDTF(this.name); 577 let [year, month, day, adOrBc, hour, minute, second] = dtf.formatToParts 578 ? partsOffset(dtf, date) 579 : hackyOffset(dtf, date); 580 581 if (adOrBc === "BC") { 582 year = -Math.abs(year) + 1; 583 } 584 585 // because we're using hour12 and https://bugs.chromium.org/p/chromium/issues/detail?id=1025564&can=2&q=%2224%3A00%22%20datetimeformat 586 const adjustedHour = hour === 24 ? 0 : hour; 587 588 const asUTC = objToLocalTS({ 589 year, 590 month, 591 day, 592 hour: adjustedHour, 593 minute, 594 second, 595 millisecond: 0, 596 }); 597 598 let asTS = +date; 599 const over = asTS % 1000; 600 asTS -= over >= 0 ? over : 1000 + over; 601 return (asUTC - asTS) / (60 * 1000); 602 } 603 604 /** 605 * Return whether this Zone is equal to another zone 606 * @override 607 * @param {Zone} otherZone - the zone to compare 608 * @return {boolean} 609 */ 610 equals(otherZone) { 611 return otherZone.type === "iana" && otherZone.name === this.name; 612 } 613 614 /** 615 * Return whether this Zone is valid. 616 * @override 617 * @type {boolean} 618 */ 619 get isValid() { 620 return this.valid; 621 } 622} 623 624// todo - remap caching 625 626let intlLFCache = {}; 627function getCachedLF(locString, opts = {}) { 628 const key = JSON.stringify([locString, opts]); 629 let dtf = intlLFCache[key]; 630 if (!dtf) { 631 dtf = new Intl.ListFormat(locString, opts); 632 intlLFCache[key] = dtf; 633 } 634 return dtf; 635} 636 637let intlDTCache = {}; 638function getCachedDTF(locString, opts = {}) { 639 const key = JSON.stringify([locString, opts]); 640 let dtf = intlDTCache[key]; 641 if (!dtf) { 642 dtf = new Intl.DateTimeFormat(locString, opts); 643 intlDTCache[key] = dtf; 644 } 645 return dtf; 646} 647 648let intlNumCache = {}; 649function getCachedINF(locString, opts = {}) { 650 const key = JSON.stringify([locString, opts]); 651 let inf = intlNumCache[key]; 652 if (!inf) { 653 inf = new Intl.NumberFormat(locString, opts); 654 intlNumCache[key] = inf; 655 } 656 return inf; 657} 658 659let intlRelCache = {}; 660function getCachedRTF(locString, opts = {}) { 661 const { base, ...cacheKeyOpts } = opts; // exclude `base` from the options 662 const key = JSON.stringify([locString, cacheKeyOpts]); 663 let inf = intlRelCache[key]; 664 if (!inf) { 665 inf = new Intl.RelativeTimeFormat(locString, opts); 666 intlRelCache[key] = inf; 667 } 668 return inf; 669} 670 671let sysLocaleCache = null; 672function systemLocale() { 673 if (sysLocaleCache) { 674 return sysLocaleCache; 675 } else { 676 sysLocaleCache = new Intl.DateTimeFormat().resolvedOptions().locale; 677 return sysLocaleCache; 678 } 679} 680 681let weekInfoCache = {}; 682function getCachedWeekInfo(locString) { 683 let data = weekInfoCache[locString]; 684 if (!data) { 685 const locale = new Intl.Locale(locString); 686 // browsers currently implement this as a property, but spec says it should be a getter function 687 data = "getWeekInfo" in locale ? locale.getWeekInfo() : locale.weekInfo; 688 weekInfoCache[locString] = data; 689 } 690 return data; 691} 692 693function parseLocaleString(localeStr) { 694 // I really want to avoid writing a BCP 47 parser 695 // see, e.g. https://github.com/wooorm/bcp-47 696 // Instead, we'll do this: 697 698 // a) if the string has no -u extensions, just leave it alone 699 // b) if it does, use Intl to resolve everything 700 // c) if Intl fails, try again without the -u 701 702 // private subtags and unicode subtags have ordering requirements, 703 // and we're not properly parsing this, so just strip out the 704 // private ones if they exist. 705 const xIndex = localeStr.indexOf("-x-"); 706 if (xIndex !== -1) { 707 localeStr = localeStr.substring(0, xIndex); 708 } 709 710 const uIndex = localeStr.indexOf("-u-"); 711 if (uIndex === -1) { 712 return [localeStr]; 713 } else { 714 let options; 715 let selectedStr; 716 try { 717 options = getCachedDTF(localeStr).resolvedOptions(); 718 selectedStr = localeStr; 719 } catch (e) { 720 const smaller = localeStr.substring(0, uIndex); 721 options = getCachedDTF(smaller).resolvedOptions(); 722 selectedStr = smaller; 723 } 724 725 const { numberingSystem, calendar } = options; 726 return [selectedStr, numberingSystem, calendar]; 727 } 728} 729 730function intlConfigString(localeStr, numberingSystem, outputCalendar) { 731 if (outputCalendar || numberingSystem) { 732 if (!localeStr.includes("-u-")) { 733 localeStr += "-u"; 734 } 735 736 if (outputCalendar) { 737 localeStr += `-ca-${outputCalendar}`; 738 } 739 740 if (numberingSystem) { 741 localeStr += `-nu-${numberingSystem}`; 742 } 743 return localeStr; 744 } else { 745 return localeStr; 746 } 747} 748 749function mapMonths(f) { 750 const ms = []; 751 for (let i = 1; i <= 12; i++) { 752 const dt = DateTime.utc(2009, i, 1); 753 ms.push(f(dt)); 754 } 755 return ms; 756} 757 758function mapWeekdays(f) { 759 const ms = []; 760 for (let i = 1; i <= 7; i++) { 761 const dt = DateTime.utc(2016, 11, 13 + i); 762 ms.push(f(dt)); 763 } 764 return ms; 765} 766 767function listStuff(loc, length, englishFn, intlFn) { 768 const mode = loc.listingMode(); 769 770 if (mode === "error") { 771 return null; 772 } else if (mode === "en") { 773 return englishFn(length); 774 } else { 775 return intlFn(length); 776 } 777} 778 779function supportsFastNumbers(loc) { 780 if (loc.numberingSystem && loc.numberingSystem !== "latn") { 781 return false; 782 } else { 783 return ( 784 loc.numberingSystem === "latn" || 785 !loc.locale || 786 loc.locale.startsWith("en") || 787 new Intl.DateTimeFormat(loc.intl).resolvedOptions().numberingSystem === "latn" 788 ); 789 } 790} 791 792/** 793 * @private 794 */ 795 796class PolyNumberFormatter { 797 constructor(intl, forceSimple, opts) { 798 this.padTo = opts.padTo || 0; 799 this.floor = opts.floor || false; 800 801 const { padTo, floor, ...otherOpts } = opts; 802 803 if (!forceSimple || Object.keys(otherOpts).length > 0) { 804 const intlOpts = { useGrouping: false, ...opts }; 805 if (opts.padTo > 0) intlOpts.minimumIntegerDigits = opts.padTo; 806 this.inf = getCachedINF(intl, intlOpts); 807 } 808 } 809 810 format(i) { 811 if (this.inf) { 812 const fixed = this.floor ? Math.floor(i) : i; 813 return this.inf.format(fixed); 814 } else { 815 // to match the browser's numberformatter defaults 816 const fixed = this.floor ? Math.floor(i) : roundTo(i, 3); 817 return padStart(fixed, this.padTo); 818 } 819 } 820} 821 822/** 823 * @private 824 */ 825 826class PolyDateFormatter { 827 constructor(dt, intl, opts) { 828 this.opts = opts; 829 this.originalZone = undefined; 830 831 let z = undefined; 832 if (this.opts.timeZone) { 833 // Don't apply any workarounds if a timeZone is explicitly provided in opts 834 this.dt = dt; 835 } else if (dt.zone.type === "fixed") { 836 // UTC-8 or Etc/UTC-8 are not part of tzdata, only Etc/GMT+8 and the like. 837 // That is why fixed-offset TZ is set to that unless it is: 838 // 1. Representing offset 0 when UTC is used to maintain previous behavior and does not become GMT. 839 // 2. Unsupported by the browser: 840 // - some do not support Etc/ 841 // - < Etc/GMT-14, > Etc/GMT+12, and 30-minute or 45-minute offsets are not part of tzdata 842 const gmtOffset = -1 * (dt.offset / 60); 843 const offsetZ = gmtOffset >= 0 ? `Etc/GMT+${gmtOffset}` : `Etc/GMT${gmtOffset}`; 844 if (dt.offset !== 0 && IANAZone.create(offsetZ).valid) { 845 z = offsetZ; 846 this.dt = dt; 847 } else { 848 // Not all fixed-offset zones like Etc/+4:30 are present in tzdata so 849 // we manually apply the offset and substitute the zone as needed. 850 z = "UTC"; 851 this.dt = dt.offset === 0 ? dt : dt.setZone("UTC").plus({ minutes: dt.offset }); 852 this.originalZone = dt.zone; 853 } 854 } else if (dt.zone.type === "system") { 855 this.dt = dt; 856 } else if (dt.zone.type === "iana") { 857 this.dt = dt; 858 z = dt.zone.name; 859 } else { 860 // Custom zones can have any offset / offsetName so we just manually 861 // apply the offset and substitute the zone as needed. 862 z = "UTC"; 863 this.dt = dt.setZone("UTC").plus({ minutes: dt.offset }); 864 this.originalZone = dt.zone; 865 } 866 867 const intlOpts = { ...this.opts }; 868 intlOpts.timeZone = intlOpts.timeZone || z; 869 this.dtf = getCachedDTF(intl, intlOpts); 870 } 871 872 format() { 873 if (this.originalZone) { 874 // If we have to substitute in the actual zone name, we have to use 875 // formatToParts so that the timezone can be replaced. 876 return this.formatToParts() 877 .map(({ value }) => value) 878 .join(""); 879 } 880 return this.dtf.format(this.dt.toJSDate()); 881 } 882 883 formatToParts() { 884 const parts = this.dtf.formatToParts(this.dt.toJSDate()); 885 if (this.originalZone) { 886 return parts.map((part) => { 887 if (part.type === "timeZoneName") { 888 const offsetName = this.originalZone.offsetName(this.dt.ts, { 889 locale: this.dt.locale, 890 format: this.opts.timeZoneName, 891 }); 892 return { 893 ...part, 894 value: offsetName, 895 }; 896 } else { 897 return part; 898 } 899 }); 900 } 901 return parts; 902 } 903 904 resolvedOptions() { 905 return this.dtf.resolvedOptions(); 906 } 907} 908 909/** 910 * @private 911 */ 912class PolyRelFormatter { 913 constructor(intl, isEnglish, opts) { 914 this.opts = { style: "long", ...opts }; 915 if (!isEnglish && hasRelative()) { 916 this.rtf = getCachedRTF(intl, opts); 917 } 918 } 919 920 format(count, unit) { 921 if (this.rtf) { 922 return this.rtf.format(count, unit); 923 } else { 924 return formatRelativeTime(unit, count, this.opts.numeric, this.opts.style !== "long"); 925 } 926 } 927 928 formatToParts(count, unit) { 929 if (this.rtf) { 930 return this.rtf.formatToParts(count, unit); 931 } else { 932 return []; 933 } 934 } 935} 936 937const fallbackWeekSettings = { 938 firstDay: 1, 939 minimalDays: 4, 940 weekend: [6, 7], 941}; 942 943/** 944 * @private 945 */ 946 947class Locale { 948 static fromOpts(opts) { 949 return Locale.create( 950 opts.locale, 951 opts.numberingSystem, 952 opts.outputCalendar, 953 opts.weekSettings, 954 opts.defaultToEN 955 ); 956 } 957 958 static create(locale, numberingSystem, outputCalendar, weekSettings, defaultToEN = false) { 959 const specifiedLocale = locale || Settings.defaultLocale; 960 // the system locale is useful for human-readable strings but annoying for parsing/formatting known formats 961 const localeR = specifiedLocale || (defaultToEN ? "en-US" : systemLocale()); 962 const numberingSystemR = numberingSystem || Settings.defaultNumberingSystem; 963 const outputCalendarR = outputCalendar || Settings.defaultOutputCalendar; 964 const weekSettingsR = validateWeekSettings(weekSettings) || Settings.defaultWeekSettings; 965 return new Locale(localeR, numberingSystemR, outputCalendarR, weekSettingsR, specifiedLocale); 966 } 967 968 static resetCache() { 969 sysLocaleCache = null; 970 intlDTCache = {}; 971 intlNumCache = {}; 972 intlRelCache = {}; 973 } 974 975 static fromObject({ locale, numberingSystem, outputCalendar, weekSettings } = {}) { 976 return Locale.create(locale, numberingSystem, outputCalendar, weekSettings); 977 } 978 979 constructor(locale, numbering, outputCalendar, weekSettings, specifiedLocale) { 980 const [parsedLocale, parsedNumberingSystem, parsedOutputCalendar] = parseLocaleString(locale); 981 982 this.locale = parsedLocale; 983 this.numberingSystem = numbering || parsedNumberingSystem || null; 984 this.outputCalendar = outputCalendar || parsedOutputCalendar || null; 985 this.weekSettings = weekSettings; 986 this.intl = intlConfigString(this.locale, this.numberingSystem, this.outputCalendar); 987 988 this.weekdaysCache = { format: {}, standalone: {} }; 989 this.monthsCache = { format: {}, standalone: {} }; 990 this.meridiemCache = null; 991 this.eraCache = {}; 992 993 this.specifiedLocale = specifiedLocale; 994 this.fastNumbersCached = null; 995 } 996 997 get fastNumbers() { 998 if (this.fastNumbersCached == null) { 999 this.fastNumbersCached = supportsFastNumbers(this); 1000 } 1001 1002 return this.fastNumbersCached; 1003 } 1004 1005 listingMode() { 1006 const isActuallyEn = this.isEnglish(); 1007 const hasNoWeirdness = 1008 (this.numberingSystem === null || this.numberingSystem === "latn") && 1009 (this.outputCalendar === null || this.outputCalendar === "gregory"); 1010 return isActuallyEn && hasNoWeirdness ? "en" : "intl"; 1011 } 1012 1013 clone(alts) { 1014 if (!alts || Object.getOwnPropertyNames(alts).length === 0) { 1015 return this; 1016 } else { 1017 return Locale.create( 1018 alts.locale || this.specifiedLocale, 1019 alts.numberingSystem || this.numberingSystem, 1020 alts.outputCalendar || this.outputCalendar, 1021 validateWeekSettings(alts.weekSettings) || this.weekSettings, 1022 alts.defaultToEN || false 1023 ); 1024 } 1025 } 1026 1027 redefaultToEN(alts = {}) { 1028 return this.clone({ ...alts, defaultToEN: true }); 1029 } 1030 1031 redefaultToSystem(alts = {}) { 1032 return this.clone({ ...alts, defaultToEN: false }); 1033 } 1034 1035 months(length, format = false) { 1036 return listStuff(this, length, months, () => { 1037 const intl = format ? { month: length, day: "numeric" } : { month: length }, 1038 formatStr = format ? "format" : "standalone"; 1039 if (!this.monthsCache[formatStr][length]) { 1040 this.monthsCache[formatStr][length] = mapMonths((dt) => this.extract(dt, intl, "month")); 1041 } 1042 return this.monthsCache[formatStr][length]; 1043 }); 1044 } 1045 1046 weekdays(length, format = false) { 1047 return listStuff(this, length, weekdays, () => { 1048 const intl = format 1049 ? { weekday: length, year: "numeric", month: "long", day: "numeric" } 1050 : { weekday: length }, 1051 formatStr = format ? "format" : "standalone"; 1052 if (!this.weekdaysCache[formatStr][length]) { 1053 this.weekdaysCache[formatStr][length] = mapWeekdays((dt) => 1054 this.extract(dt, intl, "weekday") 1055 ); 1056 } 1057 return this.weekdaysCache[formatStr][length]; 1058 }); 1059 } 1060 1061 meridiems() { 1062 return listStuff( 1063 this, 1064 undefined, 1065 () => meridiems, 1066 () => { 1067 // In theory there could be aribitrary day periods. We're gonna assume there are exactly two 1068 // for AM and PM. This is probably wrong, but it's makes parsing way easier. 1069 if (!this.meridiemCache) { 1070 const intl = { hour: "numeric", hourCycle: "h12" }; 1071 this.meridiemCache = [DateTime.utc(2016, 11, 13, 9), DateTime.utc(2016, 11, 13, 19)].map( 1072 (dt) => this.extract(dt, intl, "dayperiod") 1073 ); 1074 } 1075 1076 return this.meridiemCache; 1077 } 1078 ); 1079 } 1080 1081 eras(length) { 1082 return listStuff(this, length, eras, () => { 1083 const intl = { era: length }; 1084 1085 // This is problematic. Different calendars are going to define eras totally differently. What I need is the minimum set of dates 1086 // to definitely enumerate them. 1087 if (!this.eraCache[length]) { 1088 this.eraCache[length] = [DateTime.utc(-40, 1, 1), DateTime.utc(2017, 1, 1)].map((dt) => 1089 this.extract(dt, intl, "era") 1090 ); 1091 } 1092 1093 return this.eraCache[length]; 1094 }); 1095 } 1096 1097 extract(dt, intlOpts, field) { 1098 const df = this.dtFormatter(dt, intlOpts), 1099 results = df.formatToParts(), 1100 matching = results.find((m) => m.type.toLowerCase() === field); 1101 return matching ? matching.value : null; 1102 } 1103 1104 numberFormatter(opts = {}) { 1105 // this forcesimple option is never used (the only caller short-circuits on it, but it seems safer to leave) 1106 // (in contrast, the rest of the condition is used heavily) 1107 return new PolyNumberFormatter(this.intl, opts.forceSimple || this.fastNumbers, opts); 1108 } 1109 1110 dtFormatter(dt, intlOpts = {}) { 1111 return new PolyDateFormatter(dt, this.intl, intlOpts); 1112 } 1113 1114 relFormatter(opts = {}) { 1115 return new PolyRelFormatter(this.intl, this.isEnglish(), opts); 1116 } 1117 1118 listFormatter(opts = {}) { 1119 return getCachedLF(this.intl, opts); 1120 } 1121 1122 isEnglish() { 1123 return ( 1124 this.locale === "en" || 1125 this.locale.toLowerCase() === "en-us" || 1126 new Intl.DateTimeFormat(this.intl).resolvedOptions().locale.startsWith("en-us") 1127 ); 1128 } 1129 1130 getWeekSettings() { 1131 if (this.weekSettings) { 1132 return this.weekSettings; 1133 } else if (!hasLocaleWeekInfo()) { 1134 return fallbackWeekSettings; 1135 } else { 1136 return getCachedWeekInfo(this.locale); 1137 } 1138 } 1139 1140 getStartOfWeek() { 1141 return this.getWeekSettings().firstDay; 1142 } 1143 1144 getMinDaysInFirstWeek() { 1145 return this.getWeekSettings().minimalDays; 1146 } 1147 1148 getWeekendDays() { 1149 return this.getWeekSettings().weekend; 1150 } 1151 1152 equals(other) { 1153 return ( 1154 this.locale === other.locale && 1155 this.numberingSystem === other.numberingSystem && 1156 this.outputCalendar === other.outputCalendar 1157 ); 1158 } 1159 1160 toString() { 1161 return `Locale(${this.locale}, ${this.numberingSystem}, ${this.outputCalendar})`; 1162 } 1163} 1164 1165let singleton = null; 1166 1167/** 1168 * A zone with a fixed offset (meaning no DST) 1169 * @implements {Zone} 1170 */ 1171class FixedOffsetZone extends Zone { 1172 /** 1173 * Get a singleton instance of UTC 1174 * @return {FixedOffsetZone} 1175 */ 1176 static get utcInstance() { 1177 if (singleton === null) { 1178 singleton = new FixedOffsetZone(0); 1179 } 1180 return singleton; 1181 } 1182 1183 /** 1184 * Get an instance with a specified offset 1185 * @param {number} offset - The offset in minutes 1186 * @return {FixedOffsetZone} 1187 */ 1188 static instance(offset) { 1189 return offset === 0 ? FixedOffsetZone.utcInstance : new FixedOffsetZone(offset); 1190 } 1191 1192 /** 1193 * Get an instance of FixedOffsetZone from a UTC offset string, like "UTC+6" 1194 * @param {string} s - The offset string to parse 1195 * @example FixedOffsetZone.parseSpecifier("UTC+6") 1196 * @example FixedOffsetZone.parseSpecifier("UTC+06") 1197 * @example FixedOffsetZone.parseSpecifier("UTC-6:00") 1198 * @return {FixedOffsetZone} 1199 */ 1200 static parseSpecifier(s) { 1201 if (s) { 1202 const r = s.match(/^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$/i); 1203 if (r) { 1204 return new FixedOffsetZone(signedOffset(r[1], r[2])); 1205 } 1206 } 1207 return null; 1208 } 1209 1210 constructor(offset) { 1211 super(); 1212 /** @private **/ 1213 this.fixed = offset; 1214 } 1215 1216 /** 1217 * The type of zone. `fixed` for all instances of `FixedOffsetZone`. 1218 * @override 1219 * @type {string} 1220 */ 1221 get type() { 1222 return "fixed"; 1223 } 1224 1225 /** 1226 * The name of this zone. 1227 * All fixed zones' names always start with "UTC" (plus optional offset) 1228 * @override 1229 * @type {string} 1230 */ 1231 get name() { 1232 return this.fixed === 0 ? "UTC" : `UTC${formatOffset(this.fixed, "narrow")}`; 1233 } 1234 1235 /** 1236 * The IANA name of this zone, i.e. `Etc/UTC` or `Etc/GMT+/-nn` 1237 * 1238 * @override 1239 * @type {string} 1240 */ 1241 get ianaName() { 1242 if (this.fixed === 0) {
vendor: 5,540 bytes, lines 1243-1479
1243 return "Etc/UTC"; 1244 } else { 1245 return `Etc/GMT${formatOffset(-this.fixed, "narrow")}`; 1246 } 1247 } 1248 1249 /** 1250 * Returns the offset's common name at the specified timestamp. 1251 * 1252 * For fixed offset zones this equals to the zone name. 1253 * @override 1254 */ 1255 offsetName() { 1256 return this.name; 1257 } 1258 1259 /** 1260 * Returns the offset's value as a string 1261 * @override 1262 * @param {number} ts - Epoch milliseconds for which to get the offset 1263 * @param {string} format - What style of offset to return. 1264 * Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively 1265 * @return {string} 1266 */ 1267 formatOffset(ts, format) { 1268 return formatOffset(this.fixed, format); 1269 } 1270 1271 /** 1272 * Returns whether the offset is known to be fixed for the whole year: 1273 * Always returns true for all fixed offset zones. 1274 * @override 1275 * @type {boolean} 1276 */ 1277 get isUniversal() { 1278 return true; 1279 } 1280 1281 /** 1282 * Return the offset in minutes for this zone at the specified timestamp. 1283 * 1284 * For fixed offset zones, this is constant and does not depend on a timestamp. 1285 * @override 1286 * @return {number} 1287 */ 1288 offset() { 1289 return this.fixed; 1290 } 1291 1292 /** 1293 * Return whether this Zone is equal to another zone (i.e. also fixed and same offset) 1294 * @override 1295 * @param {Zone} otherZone - the zone to compare 1296 * @return {boolean} 1297 */ 1298 equals(otherZone) { 1299 return otherZone.type === "fixed" && otherZone.fixed === this.fixed; 1300 } 1301 1302 /** 1303 * Return whether this Zone is valid: 1304 * All fixed offset zones are valid. 1305 * @override 1306 * @type {boolean} 1307 */ 1308 get isValid() { 1309 return true; 1310 } 1311} 1312 1313/** 1314 * A zone that failed to parse. You should never need to instantiate this. 1315 * @implements {Zone} 1316 */ 1317class InvalidZone extends Zone { 1318 constructor(zoneName) { 1319 super(); 1320 /** @private */ 1321 this.zoneName = zoneName; 1322 } 1323 1324 /** @override **/ 1325 get type() { 1326 return "invalid"; 1327 } 1328 1329 /** @override **/ 1330 get name() { 1331 return this.zoneName; 1332 } 1333 1334 /** @override **/ 1335 get isUniversal() { 1336 return false; 1337 } 1338 1339 /** @override **/ 1340 offsetName() { 1341 return null; 1342 } 1343 1344 /** @override **/ 1345 formatOffset() { 1346 return ""; 1347 } 1348 1349 /** @override **/ 1350 offset() { 1351 return NaN; 1352 } 1353 1354 /** @override **/ 1355 equals() { 1356 return false; 1357 } 1358 1359 /** @override **/ 1360 get isValid() { 1361 return false; 1362 } 1363} 1364 1365/** 1366 * @private 1367 */ 1368 1369function normalizeZone(input, defaultZone) { 1370 if (isUndefined(input) || input === null) { 1371 return defaultZone; 1372 } else if (input instanceof Zone) { 1373 return input; 1374 } else if (isString(input)) { 1375 const lowered = input.toLowerCase(); 1376 if (lowered === "default") return defaultZone; 1377 else if (lowered === "local" || lowered === "system") return SystemZone.instance; 1378 else if (lowered === "utc" || lowered === "gmt") return FixedOffsetZone.utcInstance; 1379 else return FixedOffsetZone.parseSpecifier(lowered) || IANAZone.create(input); 1380 } else if (isNumber(input)) { 1381 return FixedOffsetZone.instance(input); 1382 } else if (typeof input === "object" && "offset" in input && typeof input.offset === "function") { 1383 // This is dumb, but the instanceof check above doesn't seem to really work 1384 // so we're duck checking it 1385 return input; 1386 } else { 1387 return new InvalidZone(input); 1388 } 1389} 1390 1391const numberingSystems = { 1392 arab: "[\u0660-\u0669]", 1393 arabext: "[\u06F0-\u06F9]", 1394 bali: "[\u1B50-\u1B59]", 1395 beng: "[\u09E6-\u09EF]", 1396 deva: "[\u0966-\u096F]", 1397 fullwide: "[\uFF10-\uFF19]", 1398 gujr: "[\u0AE6-\u0AEF]", 1399 hanidec: "[ã|ä¸|äº|ä¸|å|äº|å |ä¸|å «|ä¹]", 1400 khmr: "[\u17E0-\u17E9]", 1401 knda: "[\u0CE6-\u0CEF]", 1402 laoo: "[\u0ED0-\u0ED9]", 1403 limb: "[\u1946-\u194F]", 1404 mlym: "[\u0D66-\u0D6F]", 1405 mong: "[\u1810-\u1819]", 1406 mymr: "[\u1040-\u1049]", 1407 orya: "[\u0B66-\u0B6F]", 1408 tamldec: "[\u0BE6-\u0BEF]", 1409 telu: "[\u0C66-\u0C6F]", 1410 thai: "[\u0E50-\u0E59]", 1411 tibt: "[\u0F20-\u0F29]", 1412 latn: "\\d", 1413}; 1414 1415const numberingSystemsUTF16 = { 1416 arab: [1632, 1641], 1417 arabext: [1776, 1785], 1418 bali: [6992, 7001], 1419 beng: [2534, 2543], 1420 deva: [2406, 2415], 1421 fullwide: [65296, 65303], 1422 gujr: [2790, 2799], 1423 khmr: [6112, 6121], 1424 knda: [3302, 3311], 1425 laoo: [3792, 3801], 1426 limb: [6470, 6479], 1427 mlym: [3430, 3439], 1428 mong: [6160, 6169], 1429 mymr: [4160, 4169], 1430 orya: [2918, 2927], 1431 tamldec: [3046, 3055], 1432 telu: [3174, 3183], 1433 thai: [3664, 3673], 1434 tibt: [3872, 3881], 1435}; 1436 1437const hanidecChars = numberingSystems.hanidec.replace(/[\[|\]]/g, "").split(""); 1438 1439function parseDigits(str) { 1440 let value = parseInt(str, 10); 1441 if (isNaN(value)) { 1442 value = ""; 1443 for (let i = 0; i < str.length; i++) { 1444 const code = str.charCodeAt(i); 1445 1446 if (str[i].search(numberingSystems.hanidec) !== -1) { 1447 value += hanidecChars.indexOf(str[i]); 1448 } else { 1449 for (const key in numberingSystemsUTF16) { 1450 const [min, max] = numberingSystemsUTF16[key]; 1451 if (code >= min && code <= max) { 1452 value += code - min; 1453 } 1454 } 1455 } 1456 } 1457 return parseInt(value, 10); 1458 } else { 1459 return value; 1460 } 1461} 1462 1463// cache of {numberingSystem: {append: regex}} 1464let digitRegexCache = {}; 1465function resetDigitRegexCache() { 1466 digitRegexCache = {}; 1467} 1468 1469function digitRegex({ numberingSystem }, append = "") { 1470 const ns = numberingSystem || "latn"; 1471 1472 if (!digitRegexCache[ns]) { 1473 digitRegexCache[ns] = {}; 1474 } 1475 if (!digitRegexCache[ns][append]) { 1476 digitRegexCache[ns][append] = new RegExp(`${numberingSystems[ns]}${append}`); 1477 } 1478 1479 return digitRegexCache[ns][append]
vendor: 15,126 bytes, lines 1479-2020
1479; 1480} 1481 1482let now = () => Date.now(), 1483 defaultZone = "system", 1484 defaultLocale = null, 1485 defaultNumberingSystem = null, 1486 defaultOutputCalendar = null, 1487 twoDigitCutoffYear = 60, 1488 throwOnInvalid, 1489 defaultWeekSettings = null; 1490 1491/** 1492 * Settings contains static getters and setters that control Luxon's overall behavior. Luxon is a simple library with few options, but the ones it does have live here. 1493 */ 1494class Settings { 1495 /** 1496 * Get the callback for returning the current timestamp. 1497 * @type {function} 1498 */ 1499 static get now() { 1500 return now; 1501 } 1502 1503 /** 1504 * Set the callback for returning the current timestamp. 1505 * The function should return a number, which will be interpreted as an Epoch millisecond count 1506 * @type {function} 1507 * @example Settings.now = () => Date.now() + 3000 // pretend it is 3 seconds in the future 1508 * @example Settings.now = () => 0 // always pretend it's Jan 1, 1970 at midnight in UTC time 1509 */ 1510 static set now(n) { 1511 now = n; 1512 } 1513 1514 /** 1515 * Set the default time zone to create DateTimes in. Does not affect existing instances. 1516 * Use the value "system" to reset this value to the system's time zone. 1517 * @type {string} 1518 */ 1519 static set defaultZone(zone) { 1520 defaultZone = zone; 1521 } 1522 1523 /** 1524 * Get the default time zone object currently used to create DateTimes. Does not affect existing instances. 1525 * The default value is the system's time zone (the one set on the machine that runs this code). 1526 * @type {Zone} 1527 */ 1528 static get defaultZone() { 1529 return normalizeZone(defaultZone, SystemZone.instance); 1530 } 1531 1532 /** 1533 * Get the default locale to create DateTimes with. Does not affect existing instances. 1534 * @type {string} 1535 */ 1536 static get defaultLocale() { 1537 return defaultLocale; 1538 } 1539 1540 /** 1541 * Set the default locale to create DateTimes with. Does not affect existing instances. 1542 * @type {string} 1543 */ 1544 static set defaultLocale(locale) { 1545 defaultLocale = locale; 1546 } 1547 1548 /** 1549 * Get the default numbering system to create DateTimes with. Does not affect existing instances. 1550 * @type {string} 1551 */ 1552 static get defaultNumberingSystem() { 1553 return defaultNumberingSystem; 1554 } 1555 1556 /** 1557 * Set the default numbering system to create DateTimes with. Does not affect existing instances. 1558 * @type {string} 1559 */ 1560 static set defaultNumberingSystem(numberingSystem) { 1561 defaultNumberingSystem = numberingSystem; 1562 } 1563 1564 /** 1565 * Get the default output calendar to create DateTimes with. Does not affect existing instances. 1566 * @type {string} 1567 */ 1568 static get defaultOutputCalendar() { 1569 return defaultOutputCalendar; 1570 } 1571 1572 /** 1573 * Set the default output calendar to create DateTimes with. Does not affect existing instances. 1574 * @type {string} 1575 */ 1576 static set defaultOutputCalendar(outputCalendar) { 1577 defaultOutputCalendar = outputCalendar; 1578 } 1579 1580 /** 1581 * @typedef {Object} WeekSettings 1582 * @property {number} firstDay 1583 * @property {number} minimalDays 1584 * @property {number[]} weekend 1585 */ 1586 1587 /** 1588 * @return {WeekSettings|null} 1589 */ 1590 static get defaultWeekSettings() { 1591 return defaultWeekSettings; 1592 } 1593 1594 /** 1595 * Allows overriding the default locale week settings, i.e. the start of the week, the weekend and 1596 * how many days are required in the first week of a year. 1597 * Does not affect existing instances. 1598 * 1599 * @param {WeekSettings|null} weekSettings 1600 */ 1601 static set defaultWeekSettings(weekSettings) { 1602 defaultWeekSettings = validateWeekSettings(weekSettings); 1603 } 1604 1605 /** 1606 * Get the cutoff year for whether a 2-digit year string is interpreted in the current or previous century. Numbers higher than the cutoff will be considered to mean 19xx and numbers lower or equal to the cutoff will be considered 20xx. 1607 * @type {number} 1608 */ 1609 static get twoDigitCutoffYear() { 1610 return twoDigitCutoffYear; 1611 } 1612 1613 /** 1614 * Set the cutoff year for whether a 2-digit year string is interpreted in the current or previous century. Numbers higher than the cutoff will be considered to mean 19xx and numbers lower or equal to the cutoff will be considered 20xx. 1615 * @type {number} 1616 * @example Settings.twoDigitCutoffYear = 0 // all 'yy' are interpreted as 20th century 1617 * @example Settings.twoDigitCutoffYear = 99 // all 'yy' are interpreted as 21st century 1618 * @example Settings.twoDigitCutoffYear = 50 // '49' -> 2049; '50' -> 1950 1619 * @example Settings.twoDigitCutoffYear = 1950 // interpreted as 50 1620 * @example Settings.twoDigitCutoffYear = 2050 // ALSO interpreted as 50 1621 */ 1622 static set twoDigitCutoffYear(cutoffYear) { 1623 twoDigitCutoffYear = cutoffYear % 100; 1624 } 1625 1626 /** 1627 * Get whether Luxon will throw when it encounters invalid DateTimes, Durations, or Intervals 1628 * @type {boolean} 1629 */ 1630 static get throwOnInvalid() { 1631 return throwOnInvalid; 1632 } 1633 1634 /** 1635 * Set whether Luxon will throw when it encounters invalid DateTimes, Durations, or Intervals 1636 * @type {boolean} 1637 */ 1638 static set throwOnInvalid(t) { 1639 throwOnInvalid = t; 1640 } 1641 1642 /** 1643 * Reset Luxon's global caches. Should only be necessary in testing scenarios. 1644 * @return {void} 1645 */ 1646 static resetCaches() { 1647 Locale.resetCache(); 1648 IANAZone.resetCache(); 1649 DateTime.resetCache(); 1650 resetDigitRegexCache(); 1651 } 1652} 1653 1654class Invalid { 1655 constructor(reason, explanation) { 1656 this.reason = reason; 1657 this.explanation = explanation; 1658 } 1659 1660 toMessage() { 1661 if (this.explanation) { 1662 return `${this.reason}: ${this.explanation}`; 1663 } else { 1664 return this.reason; 1665 } 1666 } 1667} 1668 1669const nonLeapLadder = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], 1670 leapLadder = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]; 1671 1672function unitOutOfRange(unit, value) { 1673 return new Invalid( 1674 "unit out of range", 1675 `you specified ${value} (of type ${typeof value}) as a ${unit}, which is invalid` 1676 ); 1677} 1678 1679function dayOfWeek(year, month, day) { 1680 const d = new Date(Date.UTC(year, month - 1, day)); 1681 1682 if (year < 100 && year >= 0) { 1683 d.setUTCFullYear(d.getUTCFullYear() - 1900); 1684 } 1685 1686 const js = d.getUTCDay(); 1687 1688 return js === 0 ? 7 : js; 1689} 1690 1691function computeOrdinal(year, month, day) { 1692 return day + (isLeapYear(year) ? leapLadder : nonLeapLadder)[month - 1]; 1693} 1694 1695function uncomputeOrdinal(year, ordinal) { 1696 const table = isLeapYear(year) ? leapLadder : nonLeapLadder, 1697 month0 = table.findIndex((i) => i < ordinal), 1698 day = ordinal - table[month0]; 1699 return { month: month0 + 1, day }; 1700} 1701 1702function isoWeekdayToLocal(isoWeekday, startOfWeek) { 1703 return ((isoWeekday - startOfWeek + 7) % 7) + 1; 1704} 1705 1706/** 1707 * @private 1708 */ 1709 1710function gregorianToWeek(gregObj, minDaysInFirstWeek = 4, startOfWeek = 1) { 1711 const { year, month, day } = gregObj, 1712 ordinal = computeOrdinal(year, month, day), 1713 weekday = isoWeekdayToLocal(dayOfWeek(year, month, day), startOfWeek); 1714 1715 let weekNumber = Math.floor((ordinal - weekday + 14 - minDaysInFirstWeek) / 7), 1716 weekYear; 1717 1718 if (weekNumber < 1) { 1719 weekYear = year - 1; 1720 weekNumber = weeksInWeekYear(weekYear, minDaysInFirstWeek, startOfWeek); 1721 } else if (weekNumber > weeksInWeekYear(year, minDaysInFirstWeek, startOfWeek)) { 1722 weekYear = year + 1; 1723 weekNumber = 1; 1724 } else { 1725 weekYear = year; 1726 } 1727 1728 return { weekYear, weekNumber, weekday, ...timeObject(gregObj) }; 1729} 1730 1731function weekToGregorian(weekData, minDaysInFirstWeek = 4, startOfWeek = 1) { 1732 const { weekYear, weekNumber, weekday } = weekData, 1733 weekdayOfJan4 = isoWeekdayToLocal(dayOfWeek(weekYear, 1, minDaysInFirstWeek), startOfWeek), 1734 yearInDays = daysInYear(weekYear); 1735 1736 let ordinal = weekNumber * 7 + weekday - weekdayOfJan4 - 7 + minDaysInFirstWeek, 1737 year; 1738 1739 if (ordinal < 1) { 1740 year = weekYear - 1; 1741 ordinal += daysInYear(year); 1742 } else if (ordinal > yearInDays) { 1743 year = weekYear + 1; 1744 ordinal -= daysInYear(weekYear); 1745 } else { 1746 year = weekYear; 1747 } 1748 1749 const { month, day } = uncomputeOrdinal(year, ordinal); 1750 return { year, month, day, ...timeObject(weekData) }; 1751} 1752 1753function gregorianToOrdinal(gregData) { 1754 const { year, month, day } = gregData; 1755 const ordinal = computeOrdinal(year, month, day); 1756 return { year, ordinal, ...timeObject(gregData) }; 1757} 1758 1759function ordinalToGregorian(ordinalData) { 1760 const { year, ordinal } = ordinalData; 1761 const { month, day } = uncomputeOrdinal(year, ordinal); 1762 return { year, month, day, ...timeObject(ordinalData) }; 1763} 1764 1765/** 1766 * Check if local week units like localWeekday are used in obj. 1767 * If so, validates that they are not mixed with ISO week units and then copies them to the normal week unit properties. 1768 * Modifies obj in-place! 1769 * @param obj the object values 1770 */ 1771function usesLocalWeekValues(obj, loc) { 1772 const hasLocaleWeekData = 1773 !isUndefined(obj.localWeekday) || 1774 !isUndefined(obj.localWeekNumber) || 1775 !isUndefined(obj.localWeekYear); 1776 if (hasLocaleWeekData) { 1777 const hasIsoWeekData = 1778 !isUndefined(obj.weekday) || !isUndefined(obj.weekNumber) || !isUndefined(obj.weekYear); 1779 1780 if (hasIsoWeekData) { 1781 throw new ConflictingSpecificationError( 1782 "Cannot mix locale-based week fields with ISO-based week fields" 1783 ); 1784 } 1785 if (!isUndefined(obj.localWeekday)) obj.weekday = obj.localWeekday; 1786 if (!isUndefined(obj.localWeekNumber)) obj.weekNumber = obj.localWeekNumber; 1787 if (!isUndefined(obj.localWeekYear)) obj.weekYear = obj.localWeekYear; 1788 delete obj.localWeekday; 1789 delete obj.localWeekNumber; 1790 delete obj.localWeekYear; 1791 return { 1792 minDaysInFirstWeek: loc.getMinDaysInFirstWeek(), 1793 startOfWeek: loc.getStartOfWeek(), 1794 }; 1795 } else { 1796 return { minDaysInFirstWeek: 4, startOfWeek: 1 }; 1797 } 1798} 1799 1800function hasInvalidWeekData(obj, minDaysInFirstWeek = 4, startOfWeek = 1) { 1801 const validYear = isInteger(obj.weekYear), 1802 validWeek = integerBetween( 1803 obj.weekNumber, 1804 1, 1805 weeksInWeekYear(obj.weekYear, minDaysInFirstWeek, startOfWeek) 1806 ), 1807 validWeekday = integerBetween(obj.weekday, 1, 7); 1808 1809 if (!validYear) { 1810 return unitOutOfRange("weekYear", obj.weekYear); 1811 } else if (!validWeek) { 1812 return unitOutOfRange("week", obj.weekNumber); 1813 } else if (!validWeekday) { 1814 return unitOutOfRange("weekday", obj.weekday); 1815 } else return false; 1816} 1817 1818function hasInvalidOrdinalData(obj) { 1819 const validYear = isInteger(obj.year), 1820 validOrdinal = integerBetween(obj.ordinal, 1, daysInYear(obj.year)); 1821 1822 if (!validYear) { 1823 return unitOutOfRange("year", obj.year); 1824 } else if (!validOrdinal) { 1825 return unitOutOfRange("ordinal", obj.ordinal); 1826 } else return false; 1827} 1828 1829function hasInvalidGregorianData(obj) { 1830 const validYear = isInteger(obj.year), 1831 validMonth = integerBetween(obj.month, 1, 12), 1832 validDay = integerBetween(obj.day, 1, daysInMonth(obj.year, obj.month)); 1833 1834 if (!validYear) { 1835 return unitOutOfRange("year", obj.year); 1836 } else if (!validMonth) { 1837 return unitOutOfRange("month", obj.month); 1838 } else if (!validDay) { 1839 return unitOutOfRange("day", obj.day); 1840 } else return false; 1841} 1842 1843function hasInvalidTimeData(obj) { 1844 const { hour, minute, second, millisecond } = obj; 1845 const validHour = 1846 integerBetween(hour, 0, 23) || 1847 (hour === 24 && minute === 0 && second === 0 && millisecond === 0), 1848 validMinute = integerBetween(minute, 0, 59), 1849 validSecond = integerBetween(second, 0, 59), 1850 validMillisecond = integerBetween(millisecond, 0, 999); 1851 1852 if (!validHour) { 1853 return unitOutOfRange("hour", hour); 1854 } else if (!validMinute) { 1855 return unitOutOfRange("minute", minute); 1856 } else if (!validSecond) { 1857 return unitOutOfRange("second", second); 1858 } else if (!validMillisecond) { 1859 return unitOutOfRange("millisecond", millisecond); 1860 } else return false; 1861} 1862 1863/* 1864 This is just a junk drawer, containing anything used across multiple classes. 1865 Because Luxon is small(ish), this should stay small and we won't worry about splitting 1866 it up into, say, parsingUtil.js and basicUtil.js and so on. But they are divided up by feature area. 1867*/ 1868 1869/** 1870 * @private 1871 */ 1872 1873// TYPES 1874 1875function isUndefined(o) { 1876 return typeof o === "undefined"; 1877} 1878 1879function isNumber(o) { 1880 return typeof o === "number"; 1881} 1882 1883function isInteger(o) { 1884 return typeof o === "number" && o % 1 === 0; 1885} 1886 1887function isString(o) { 1888 return typeof o === "string"; 1889} 1890 1891function isDate(o) { 1892 return Object.prototype.toString.call(o) === "[object Date]"; 1893} 1894 1895// CAPABILITIES 1896 1897function hasRelative() { 1898 try { 1899 return typeof Intl !== "undefined" && !!Intl.RelativeTimeFormat; 1900 } catch (e) { 1901 return false; 1902 } 1903} 1904 1905function hasLocaleWeekInfo() { 1906 try { 1907 return ( 1908 typeof Intl !== "undefined" && 1909 !!Intl.Locale && 1910 ("weekInfo" in Intl.Locale.prototype || "getWeekInfo" in Intl.Locale.prototype) 1911 ); 1912 } catch (e) { 1913 return false; 1914 } 1915} 1916 1917// OBJECTS AND ARRAYS 1918 1919function maybeArray(thing) { 1920 return Array.isArray(thing) ? thing : [thing]; 1921} 1922 1923function bestBy(arr, by, compare) { 1924 if (arr.length === 0) { 1925 return undefined; 1926 } 1927 return arr.reduce((best, next) => { 1928 const pair = [by(next), next]; 1929 if (!best) { 1930 return pair; 1931 } else if (compare(best[0], pair[0]) === best[0]) { 1932 return best; 1933 } else { 1934 return pair; 1935 } 1936 }, null)[1]; 1937} 1938 1939function pick(obj, keys) { 1940 return keys.reduce((a, k) => { 1941 a[k] = obj[k]; 1942 return a; 1943 }, {}); 1944} 1945 1946function hasOwnProperty(obj, prop) { 1947 return Object.prototype.hasOwnProperty.call(obj, prop); 1948} 1949 1950function validateWeekSettings(settings) { 1951 if (settings == null) { 1952 return null; 1953 } else if (typeof settings !== "object") { 1954 throw new InvalidArgumentError("Week settings must be an object"); 1955 } else { 1956 if ( 1957 !integerBetween(settings.firstDay, 1, 7) || 1958 !integerBetween(settings.minimalDays, 1, 7) || 1959 !Array.isArray(settings.weekend) || 1960 settings.weekend.some((v) => !integerBetween(v, 1, 7)) 1961 ) { 1962 throw new InvalidArgumentError("Invalid week settings"); 1963 } 1964 return { 1965 firstDay: settings.firstDay, 1966 minimalDays: settings.minimalDays, 1967 weekend: Array.from(settings.weekend), 1968 }; 1969 } 1970} 1971 1972// NUMBERS AND STRINGS 1973 1974function integerBetween(thing, bottom, top) { 1975 return isInteger(thing) && thing >= bottom && thing <= top; 1976} 1977 1978// x % n but takes the sign of n instead of x 1979function floorMod(x, n) { 1980 return x - n * Math.floor(x / n); 1981} 1982 1983function padStart(input, n = 2) { 1984 const isNeg = input < 0; 1985 let padded; 1986 if (isNeg) { 1987 padded = "-" + ("" + -input).padStart(n, "0"); 1988 } else { 1989 padded = ("" + input).padStart(n, "0"); 1990 } 1991 return padded; 1992} 1993 1994function parseInteger(string) { 1995 if (isUndefined(string) || string === null || string === "") { 1996 return undefined; 1997 } else { 1998 return parseInt(string, 10); 1999 } 2000} 2001 2002function parseFloating(string) { 2003 if (isUndefined(string) || string === null || string === "") { 2004 return undefined; 2005 } else { 2006 return parseFloat(string); 2007 } 2008} 2009 2010function parseMillis(fraction) { 2011 // Return undefined (instead of 0) in these cases, where fraction is not set 2012 if (isUndefined(fraction) || fraction === null || fraction === "") { 2013 return undefined; 2014 } else { 2015 const f = parseFloat("0." + fraction) * 1000; 2016 return Math.floor(f); 2017 } 2018} 2019 2020function roundTo(number, digits,
vendor: 4,020 bytes, lines 2020-2154
2020towardZero = false) { 2021 const factor = 10 ** digits, 2022 rounder = towardZero ? Math.trunc : Math.round; 2023 return rounder(number * factor) / factor; 2024} 2025 2026// DATE BASICS 2027 2028function isLeapYear(year) { 2029 return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); 2030} 2031 2032function daysInYear(year) { 2033 return isLeapYear(year) ? 366 : 365; 2034} 2035 2036function daysInMonth(year, month) { 2037 const modMonth = floorMod(month - 1, 12) + 1, 2038 modYear = year + (month - modMonth) / 12; 2039 2040 if (modMonth === 2) { 2041 return isLeapYear(modYear) ? 29 : 28; 2042 } else { 2043 return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1]; 2044 } 2045} 2046 2047// convert a calendar object to a local timestamp (epoch, but with the offset baked in) 2048function objToLocalTS(obj) { 2049 let d = Date.UTC( 2050 obj.year, 2051 obj.month - 1, 2052 obj.day, 2053 obj.hour, 2054 obj.minute, 2055 obj.second, 2056 obj.millisecond 2057 ); 2058 2059 // for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that 2060 if (obj.year < 100 && obj.year >= 0) { 2061 d = new Date(d); 2062 // set the month and day again, this is necessary because year 2000 is a leap year, but year 100 is not 2063 // so if obj.year is in 99, but obj.day makes it roll over into year 100, 2064 // the calculations done by Date.UTC are using year 2000 - which is incorrect 2065 d.setUTCFullYear(obj.year, obj.month - 1, obj.day); 2066 } 2067 return +d; 2068} 2069 2070// adapted from moment.js: https://github.com/moment/moment/blob/000ac1800e620f770f4eb31b5ae908f6167b0ab2/src/lib/units/week-calendar-utils.js 2071function firstWeekOffset(year, minDaysInFirstWeek, startOfWeek) { 2072 const fwdlw = isoWeekdayToLocal(dayOfWeek(year, 1, minDaysInFirstWeek), startOfWeek); 2073 return -fwdlw + minDaysInFirstWeek - 1; 2074} 2075 2076function weeksInWeekYear(weekYear, minDaysInFirstWeek = 4, startOfWeek = 1) { 2077 const weekOffset = firstWeekOffset(weekYear, minDaysInFirstWeek, startOfWeek); 2078 const weekOffsetNext = firstWeekOffset(weekYear + 1, minDaysInFirstWeek, startOfWeek); 2079 return (daysInYear(weekYear) - weekOffset + weekOffsetNext) / 7; 2080} 2081 2082function untruncateYear(year) { 2083 if (year > 99) { 2084 return year; 2085 } else return year > Settings.twoDigitCutoffYear ? 1900 + year : 2000 + year; 2086} 2087 2088// PARSING 2089 2090function parseZoneInfo(ts, offsetFormat, locale, timeZone = null) { 2091 const date = new Date(ts), 2092 intlOpts = { 2093 hourCycle: "h23", 2094 year: "numeric", 2095 month: "2-digit", 2096 day: "2-digit", 2097 hour: "2-digit", 2098 minute: "2-digit", 2099 }; 2100 2101 if (timeZone) { 2102 intlOpts.timeZone = timeZone; 2103 } 2104 2105 const modified = { timeZoneName: offsetFormat, ...intlOpts }; 2106 2107 const parsed = new Intl.DateTimeFormat(locale, modified) 2108 .formatToParts(date) 2109 .find((m) => m.type.toLowerCase() === "timezonename"); 2110 return parsed ? parsed.value : null; 2111} 2112 2113// signedOffset('-5', '30') -> -330 2114function signedOffset(offHourStr, offMinuteStr) { 2115 let offHour = parseInt(offHourStr, 10); 2116 2117 // don't || this because we want to preserve -0 2118 if (Number.isNaN(offHour)) { 2119 offHour = 0; 2120 } 2121 2122 const offMin = parseInt(offMinuteStr, 10) || 0, 2123 offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin; 2124 return offHour * 60 + offMinSigned; 2125} 2126 2127// COERCION 2128 2129function asNumber(value) { 2130 const numericValue = Number(value); 2131 if (typeof value === "boolean" || value === "" || Number.isNaN(numericValue)) 2132 throw new InvalidArgumentError(`Invalid unit value ${value}`); 2133 return numericValue; 2134} 2135 2136function normalizeObject(obj, normalizer) { 2137 const normalized = {}; 2138 for (const u in obj) { 2139 if (hasOwnProperty(obj, u)) { 2140 const v = obj[u]; 2141 if (v === undefined || v === null) continue; 2142 normalized[normalizer(u)] = asNumber(v); 2143 } 2144 } 2145 return normalized; 2146} 2147 2148/** 2149 * Returns the offset's value as a string 2150 * @param {number} ts - Epoch milliseconds for which to get the offset 2151 * @param {string} format - What style of offset to return. 2152 * Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively 2153 * @return {string} 2154 */
vendor: 72,141 bytes, lines 2154-4439
2154 2155function formatOffset(offset, format) { 2156 const hours = Math.trunc(Math.abs(offset / 60)), 2157 minutes = Math.trunc(Math.abs(offset % 60)), 2158 sign = offset >= 0 ? "+" : "-"; 2159 2160 switch (format) { 2161 case "short": 2162 return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`; 2163 case "narrow": 2164 return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ""}`; 2165 case "techie": 2166 return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`; 2167 default: 2168 throw new RangeError(`Value format ${format} is out of range for property format`); 2169 } 2170} 2171 2172function timeObject(obj) { 2173 return pick(obj, ["hour", "minute", "second", "millisecond"]); 2174} 2175 2176/** 2177 * @private 2178 */ 2179 2180const monthsLong = [ 2181 "January", 2182 "February", 2183 "March", 2184 "April", 2185 "May", 2186 "June", 2187 "July", 2188 "August", 2189 "September", 2190 "October", 2191 "November", 2192 "December", 2193]; 2194 2195const monthsShort = [ 2196 "Jan", 2197 "Feb", 2198 "Mar", 2199 "Apr", 2200 "May", 2201 "Jun", 2202 "Jul", 2203 "Aug", 2204 "Sep", 2205 "Oct", 2206 "Nov", 2207 "Dec", 2208]; 2209 2210const monthsNarrow = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"]; 2211 2212function months(length) { 2213 switch (length) { 2214 case "narrow": 2215 return [...monthsNarrow]; 2216 case "short": 2217 return [...monthsShort]; 2218 case "long": 2219 return [...monthsLong]; 2220 case "numeric": 2221 return ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]; 2222 case "2-digit": 2223 return ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"]; 2224 default: 2225 return null; 2226 } 2227} 2228 2229const weekdaysLong = [ 2230 "Monday", 2231 "Tuesday", 2232 "Wednesday", 2233 "Thursday", 2234 "Friday", 2235 "Saturday", 2236 "Sunday", 2237]; 2238 2239const weekdaysShort = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]; 2240 2241const weekdaysNarrow = ["M", "T", "W", "T", "F", "S", "S"]; 2242 2243function weekdays(length) { 2244 switch (length) { 2245 case "narrow": 2246 return [...weekdaysNarrow]; 2247 case "short": 2248 return [...weekdaysShort]; 2249 case "long": 2250 return [...weekdaysLong]; 2251 case "numeric": 2252 return ["1", "2", "3", "4", "5", "6", "7"]; 2253 default: 2254 return null; 2255 } 2256} 2257 2258const meridiems = ["AM", "PM"]; 2259 2260const erasLong = ["Before Christ", "Anno Domini"]; 2261 2262const erasShort = ["BC", "AD"]; 2263 2264const erasNarrow = ["B", "A"]; 2265 2266function eras(length) { 2267 switch (length) { 2268 case "narrow": 2269 return [...erasNarrow]; 2270 case "short": 2271 return [...erasShort]; 2272 case "long": 2273 return [...erasLong]; 2274 default: 2275 return null; 2276 } 2277} 2278 2279function meridiemForDateTime(dt) { 2280 return meridiems[dt.hour < 12 ? 0 : 1]; 2281} 2282 2283function weekdayForDateTime(dt, length) { 2284 return weekdays(length)[dt.weekday - 1]; 2285} 2286 2287function monthForDateTime(dt, length) { 2288 return months(length)[dt.month - 1]; 2289} 2290 2291function eraForDateTime(dt, length) { 2292 return eras(length)[dt.year < 0 ? 0 : 1]; 2293} 2294 2295function formatRelativeTime(unit, count, numeric = "always", narrow = false) { 2296 const units = { 2297 years: ["year", "yr."], 2298 quarters: ["quarter", "qtr."], 2299 months: ["month", "mo."], 2300 weeks: ["week", "wk."], 2301 days: ["day", "day", "days"], 2302 hours: ["hour", "hr."], 2303 minutes: ["minute", "min."], 2304 seconds: ["second", "sec."], 2305 }; 2306 2307 const lastable = ["hours", "minutes", "seconds"].indexOf(unit) === -1; 2308 2309 if (numeric === "auto" && lastable) { 2310 const isDay = unit === "days"; 2311 switch (count) { 2312 case 1: 2313 return isDay ? "tomorrow" : `next ${units[unit][0]}`; 2314 case -1: 2315 return isDay ? "yesterday" : `last ${units[unit][0]}`; 2316 case 0: 2317 return isDay ? "today" : `this ${units[unit][0]}`; 2318 } 2319 } 2320 2321 const isInPast = Object.is(count, -0) || count < 0, 2322 fmtValue = Math.abs(count), 2323 singular = fmtValue === 1, 2324 lilUnits = units[unit], 2325 fmtUnit = narrow 2326 ? singular 2327 ? lilUnits[1] 2328 : lilUnits[2] || lilUnits[1] 2329 : singular 2330 ? units[unit][0] 2331 : unit; 2332 return isInPast ? `${fmtValue} ${fmtUnit} ago` : `in ${fmtValue} ${fmtUnit}`; 2333} 2334 2335function stringifyTokens(splits, tokenToString) { 2336 let s = ""; 2337 for (const token of splits) { 2338 if (token.literal) { 2339 s += token.val; 2340 } else { 2341 s += tokenToString(token.val); 2342 } 2343 } 2344 return s; 2345} 2346 2347const macroTokenToFormatOpts = { 2348 D: DATE_SHORT, 2349 DD: DATE_MED, 2350 DDD: DATE_FULL, 2351 DDDD: DATE_HUGE, 2352 t: TIME_SIMPLE, 2353 tt: TIME_WITH_SECONDS, 2354 ttt: TIME_WITH_SHORT_OFFSET, 2355 tttt: TIME_WITH_LONG_OFFSET, 2356 T: TIME_24_SIMPLE, 2357 TT: TIME_24_WITH_SECONDS, 2358 TTT: TIME_24_WITH_SHORT_OFFSET, 2359 TTTT: TIME_24_WITH_LONG_OFFSET, 2360 f: DATETIME_SHORT, 2361 ff: DATETIME_MED, 2362 fff: DATETIME_FULL, 2363 ffff: DATETIME_HUGE, 2364 F: DATETIME_SHORT_WITH_SECONDS, 2365 FF: DATETIME_MED_WITH_SECONDS, 2366 FFF: DATETIME_FULL_WITH_SECONDS, 2367 FFFF: DATETIME_HUGE_WITH_SECONDS, 2368}; 2369 2370/** 2371 * @private 2372 */ 2373 2374class Formatter { 2375 static create(locale, opts = {}) { 2376 return new Formatter(locale, opts); 2377 } 2378 2379 static parseFormat(fmt) { 2380 // white-space is always considered a literal in user-provided formats 2381 // the " " token has a special meaning (see unitForToken) 2382 2383 let current = null, 2384 currentFull = "", 2385 bracketed = false; 2386 const splits = []; 2387 for (let i = 0; i < fmt.length; i++) { 2388 const c = fmt.charAt(i); 2389 if (c === "'") { 2390 if (currentFull.length > 0) { 2391 splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull }); 2392 } 2393 current = null; 2394 currentFull = ""; 2395 bracketed = !bracketed; 2396 } else if (bracketed) { 2397 currentFull += c; 2398 } else if (c === current) { 2399 currentFull += c; 2400 } else { 2401 if (currentFull.length > 0) { 2402 splits.push({ literal: /^\s+$/.test(currentFull), val: currentFull }); 2403 } 2404 currentFull = c; 2405 current = c; 2406 } 2407 } 2408 2409 if (currentFull.length > 0) { 2410 splits.push({ literal: bracketed || /^\s+$/.test(currentFull), val: currentFull }); 2411 } 2412 2413 return splits; 2414 } 2415 2416 static macroTokenToFormatOpts(token) { 2417 return macroTokenToFormatOpts[token]; 2418 } 2419 2420 constructor(locale, formatOpts) { 2421 this.opts = formatOpts; 2422 this.loc = locale; 2423 this.systemLoc = null; 2424 } 2425 2426 formatWithSystemDefault(dt, opts) { 2427 if (this.systemLoc === null) { 2428 this.systemLoc = this.loc.redefaultToSystem(); 2429 } 2430 const df = this.systemLoc.dtFormatter(dt, { ...this.opts, ...opts }); 2431 return df.format(); 2432 } 2433 2434 dtFormatter(dt, opts = {}) { 2435 return this.loc.dtFormatter(dt, { ...this.opts, ...opts }); 2436 } 2437 2438 formatDateTime(dt, opts) { 2439 return this.dtFormatter(dt, opts).format(); 2440 } 2441 2442 formatDateTimeParts(dt, opts) { 2443 return this.dtFormatter(dt, opts).formatToParts(); 2444 } 2445 2446 formatInterval(interval, opts) { 2447 const df = this.dtFormatter(interval.start, opts); 2448 return df.dtf.formatRange(interval.start.toJSDate(), interval.end.toJSDate()); 2449 } 2450 2451 resolvedOptions(dt, opts) { 2452 return this.dtFormatter(dt, opts).resolvedOptions(); 2453 } 2454 2455 num(n, p = 0) { 2456 // we get some perf out of doing this here, annoyingly 2457 if (this.opts.forceSimple) { 2458 return padStart(n, p); 2459 } 2460 2461 const opts = { ...this.opts }; 2462 2463 if (p > 0) { 2464 opts.padTo = p; 2465 } 2466 2467 return this.loc.numberFormatter(opts).format(n); 2468 } 2469 2470 formatDateTimeFromString(dt, fmt) { 2471 const knownEnglish = this.loc.listingMode() === "en", 2472 useDateTimeFormatter = this.loc.outputCalendar && this.loc.outputCalendar !== "gregory", 2473 string = (opts, extract) => this.loc.extract(dt, opts, extract), 2474 formatOffset = (opts) => { 2475 if (dt.isOffsetFixed && dt.offset === 0 && opts.allowZ) { 2476 return "Z"; 2477 } 2478 2479 return dt.isValid ? dt.zone.formatOffset(dt.ts, opts.format) : ""; 2480 }, 2481 meridiem = () => 2482 knownEnglish 2483 ? meridiemForDateTime(dt) 2484 : string({ hour: "numeric", hourCycle: "h12" }, "dayperiod"), 2485 month = (length, standalone) => 2486 knownEnglish 2487 ? monthForDateTime(dt, length) 2488 : string(standalone ? { month: length } : { month: length, day: "numeric" }, "month"), 2489 weekday = (length, standalone) => 2490 knownEnglish 2491 ? weekdayForDateTime(dt, length) 2492 : string( 2493 standalone ? { weekday: length } : { weekday: length, month: "long", day: "numeric" }, 2494 "weekday" 2495 ), 2496 maybeMacro = (token) => { 2497 const formatOpts = Formatter.macroTokenToFormatOpts(token); 2498 if (formatOpts) { 2499 return this.formatWithSystemDefault(dt, formatOpts); 2500 } else { 2501 return token; 2502 } 2503 }, 2504 era = (length) => 2505 knownEnglish ? eraForDateTime(dt, length) : string({ era: length }, "era"), 2506 tokenToString = (token) => { 2507 // Where possible: https://cldr.unicode.org/translation/date-time/date-time-symbols 2508 switch (token) { 2509 // ms 2510 case "S": 2511 return this.num(dt.millisecond); 2512 case "u": 2513 // falls through 2514 case "SSS": 2515 return this.num(dt.millisecond, 3); 2516 // seconds 2517 case "s": 2518 return this.num(dt.second); 2519 case "ss": 2520 return this.num(dt.second, 2); 2521 // fractional seconds 2522 case "uu": 2523 return this.num(Math.floor(dt.millisecond / 10), 2); 2524 case "uuu": 2525 return this.num(Math.floor(dt.millisecond / 100)); 2526 // minutes 2527 case "m": 2528 return this.num(dt.minute); 2529 case "mm": 2530 return this.num(dt.minute, 2); 2531 // hours 2532 case "h": 2533 return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12); 2534 case "hh": 2535 return this.num(dt.hour % 12 === 0 ? 12 : dt.hour % 12, 2); 2536 case "H": 2537 return this.num(dt.hour); 2538 case "HH": 2539 return this.num(dt.hour, 2); 2540 // offset 2541 case "Z": 2542 // like +6 2543 return formatOffset({ format: "narrow", allowZ: this.opts.allowZ }); 2544 case "ZZ": 2545 // like +06:00 2546 return formatOffset({ format: "short", allowZ: this.opts.allowZ }); 2547 case "ZZZ": 2548 // like +0600 2549 return formatOffset({ format: "techie", allowZ: this.opts.allowZ }); 2550 case "ZZZZ": 2551 // like EST 2552 return dt.zone.offsetName(dt.ts, { format: "short", locale: this.loc.locale }); 2553 case "ZZZZZ": 2554 // like Eastern Standard Time 2555 return dt.zone.offsetName(dt.ts, { format: "long", locale: this.loc.locale }); 2556 // zone 2557 case "z": 2558 // like America/New_York 2559 return dt.zoneName; 2560 // meridiems 2561 case "a": 2562 return meridiem(); 2563 // dates 2564 case "d": 2565 return useDateTimeFormatter ? string({ day: "numeric" }, "day") : this.num(dt.day); 2566 case "dd": 2567 return useDateTimeFormatter ? string({ day: "2-digit" }, "day") : this.num(dt.day, 2); 2568 // weekdays - standalone 2569 case "c": 2570 // like 1 2571 return this.num(dt.weekday); 2572 case "ccc": 2573 // like 'Tues' 2574 return weekday("short", true); 2575 case "cccc": 2576 // like 'Tuesday' 2577 return weekday("long", true); 2578 case "ccccc": 2579 // like 'T' 2580 return weekday("narrow", true); 2581 // weekdays - format 2582 case "E": 2583 // like 1 2584 return this.num(dt.weekday); 2585 case "EEE": 2586 // like 'Tues' 2587 return weekday("short", false); 2588 case "EEEE": 2589 // like 'Tuesday' 2590 return weekday("long", false); 2591 case "EEEEE": 2592 // like 'T' 2593 return weekday("narrow", false); 2594 // months - standalone 2595 case "L": 2596 // like 1 2597 return useDateTimeFormatter 2598 ? string({ month: "numeric", day: "numeric" }, "month") 2599 : this.num(dt.month); 2600 case "LL": 2601 // like 01, doesn't seem to work 2602 return useDateTimeFormatter 2603 ? string({ month: "2-digit", day: "numeric" }, "month") 2604 : this.num(dt.month, 2); 2605 case "LLL": 2606 // like Jan 2607 return month("short", true); 2608 case "LLLL": 2609 // like January 2610 return month("long", true); 2611 case "LLLLL": 2612 // like J 2613 return month("narrow", true); 2614 // months - format 2615 case "M": 2616 // like 1 2617 return useDateTimeFormatter 2618 ? string({ month: "numeric" }, "month") 2619 : this.num(dt.month); 2620 case "MM": 2621 // like 01 2622 return useDateTimeFormatter 2623 ? string({ month: "2-digit" }, "month") 2624 : this.num(dt.month, 2); 2625 case "MMM": 2626 // like Jan 2627 return month("short", false); 2628 case "MMMM": 2629 // like January 2630 return month("long", false); 2631 case "MMMMM": 2632 // like J 2633 return month("narrow", false); 2634 // years 2635 case "y": 2636 // like 2014 2637 return useDateTimeFormatter ? string({ year: "numeric" }, "year") : this.num(dt.year); 2638 case "yy": 2639 // like 14 2640 return useDateTimeFormatter 2641 ? string({ year: "2-digit" }, "year") 2642 : this.num(dt.year.toString().slice(-2), 2); 2643 case "yyyy": 2644 // like 0012 2645 return useDateTimeFormatter 2646 ? string({ year: "numeric" }, "year") 2647 : this.num(dt.year, 4); 2648 case "yyyyyy": 2649 // like 000012 2650 return useDateTimeFormatter 2651 ? string({ year: "numeric" }, "year") 2652 : this.num(dt.year, 6); 2653 // eras 2654 case "G": 2655 // like AD 2656 return era("short"); 2657 case "GG": 2658 // like Anno Domini 2659 return era("long"); 2660 case "GGGGG": 2661 return era("narrow"); 2662 case "kk": 2663 return this.num(dt.weekYear.toString().slice(-2), 2); 2664 case "kkkk": 2665 return this.num(dt.weekYear, 4); 2666 case "W": 2667 return this.num(dt.weekNumber); 2668 case "WW": 2669 return this.num(dt.weekNumber, 2); 2670 case "n": 2671 return this.num(dt.localWeekNumber); 2672 case "nn": 2673 return this.num(dt.localWeekNumber, 2); 2674 case "ii": 2675 return this.num(dt.localWeekYear.toString().slice(-2), 2); 2676 case "iiii": 2677 return this.num(dt.localWeekYear, 4); 2678 case "o": 2679 return this.num(dt.ordinal); 2680 case "ooo": 2681 return this.num(dt.ordinal, 3); 2682 case "q": 2683 // like 1 2684 return this.num(dt.quarter); 2685 case "qq": 2686 // like 01 2687 return this.num(dt.quarter, 2); 2688 case "X": 2689 return this.num(Math.floor(dt.ts / 1000)); 2690 case "x": 2691 return this.num(dt.ts); 2692 default: 2693 return maybeMacro(token); 2694 } 2695 }; 2696 2697 return stringifyTokens(Formatter.parseFormat(fmt), tokenToString); 2698 } 2699 2700 formatDurationFromString(dur, fmt) { 2701 const tokenToField = (token) => { 2702 switch (token[0]) { 2703 case "S": 2704 return "millisecond"; 2705 case "s": 2706 return "second"; 2707 case "m": 2708 return "minute"; 2709 case "h": 2710 return "hour"; 2711 case "d": 2712 return "day"; 2713 case "w": 2714 return "week"; 2715 case "M": 2716 return "month"; 2717 case "y": 2718 return "year"; 2719 default: 2720 return null; 2721 } 2722 }, 2723 tokenToString = (lildur) => (token) => { 2724 const mapped = tokenToField(token); 2725 if (mapped) { 2726 return this.num(lildur.get(mapped), token.length); 2727 } else { 2728 return token; 2729 } 2730 }, 2731 tokens = Formatter.parseFormat(fmt), 2732 realTokens = tokens.reduce( 2733 (found, { literal, val }) => (literal ? found : found.concat(val)), 2734 [] 2735 ), 2736 collapsed = dur.shiftTo(...realTokens.map(tokenToField).filter((t) => t)); 2737 return stringifyTokens(tokens, tokenToString(collapsed)); 2738 } 2739} 2740 2741/* 2742 * This file handles parsing for well-specified formats. Here's how it works: 2743 * Two things go into parsing: a regex to match with and an extractor to take apart the groups in the match. 2744 * An extractor is just a function that takes a regex match array and returns a { year: ..., month: ... } object 2745 * parse() does the work of executing the regex and applying the extractor. It takes multiple regex/extractor pairs to try in sequence. 2746 * Extractors can take a "cursor" representing the offset in the match to look at. This makes it easy to combine extractors. 2747 * combineExtractors() does the work of combining them, keeping track of the cursor through multiple extractions. 2748 * Some extractions are super dumb and simpleParse and fromStrings help DRY them. 2749 */ 2750 2751const ianaRegex = /[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/; 2752 2753function combineRegexes(...regexes) { 2754 const full = regexes.reduce((f, r) => f + r.source, ""); 2755 return RegExp(`^${full}$`); 2756} 2757 2758function combineExtractors(...extractors) { 2759 return (m) => 2760 extractors 2761 .reduce( 2762 ([mergedVals, mergedZone, cursor], ex) => { 2763 const [val, zone, next] = ex(m, cursor); 2764 return [{ ...mergedVals, ...val }, zone || mergedZone, next]; 2765 }, 2766 [{}, null, 1] 2767 ) 2768 .slice(0, 2); 2769} 2770 2771function parse(s, ...patterns) { 2772 if (s == null) { 2773 return [null, null]; 2774 } 2775 2776 for (const [regex, extractor] of patterns) { 2777 const m = regex.exec(s); 2778 if (m) { 2779 return extractor(m); 2780 } 2781 } 2782 return [null, null]; 2783} 2784 2785function simpleParse(...keys) { 2786 return (match, cursor) => { 2787 const ret = {}; 2788 let i; 2789 2790 for (i = 0; i < keys.length; i++) { 2791 ret[keys[i]] = parseInteger(match[cursor + i]); 2792 } 2793 return [ret, null, cursor + i]; 2794 }; 2795} 2796 2797// ISO and SQL parsing 2798const offsetRegex = /(?:(Z)|([+-]\d\d)(?::?(\d\d))?)/; 2799const isoExtendedZone = `(?:${offsetRegex.source}?(?:\\[(${ianaRegex.source})\\])?)?`; 2800const isoTimeBaseRegex = /(\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d{1,30}))?)?)?/; 2801const isoTimeRegex = RegExp(`${isoTimeBaseRegex.source}${isoExtendedZone}`); 2802const isoTimeExtensionRegex = RegExp(`(?:T${isoTimeRegex.source})?`); 2803const isoYmdRegex = /([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/; 2804const isoWeekRegex = /(\d{4})-?W(\d\d)(?:-?(\d))?/; 2805const isoOrdinalRegex = /(\d{4})-?(\d{3})/; 2806const extractISOWeekData = simpleParse("weekYear", "weekNumber", "weekDay"); 2807const extractISOOrdinalData = simpleParse("year", "ordinal"); 2808const sqlYmdRegex = /(\d{4})-(\d\d)-(\d\d)/; // dumbed-down version of the ISO one 2809const sqlTimeRegex = RegExp( 2810 `${isoTimeBaseRegex.source} ?(?:${offsetRegex.source}|(${ianaRegex.source}))?` 2811); 2812const sqlTimeExtensionRegex = RegExp(`(?: ${sqlTimeRegex.source})?`); 2813 2814function int(match, pos, fallback) { 2815 const m = match[pos]; 2816 return isUndefined(m) ? fallback : parseInteger(m); 2817} 2818 2819function extractISOYmd(match, cursor) { 2820 const item = { 2821 year: int(match, cursor), 2822 month: int(match, cursor + 1, 1), 2823 day: int(match, cursor + 2, 1), 2824 }; 2825 2826 return [item, null, cursor + 3]; 2827} 2828 2829function extractISOTime(match, cursor) { 2830 const item = { 2831 hours: int(match, cursor, 0), 2832 minutes: int(match, cursor + 1, 0), 2833 seconds: int(match, cursor + 2, 0), 2834 milliseconds: parseMillis(match[cursor + 3]), 2835 }; 2836 2837 return [item, null, cursor + 4]; 2838} 2839 2840function extractISOOffset(match, cursor) { 2841 const local = !match[cursor] && !match[cursor + 1], 2842 fullOffset = signedOffset(match[cursor + 1], match[cursor + 2]), 2843 zone = local ? null : FixedOffsetZone.instance(fullOffset); 2844 return [{}, zone, cursor + 3]; 2845} 2846 2847function extractIANAZone(match, cursor) { 2848 const zone = match[cursor] ? IANAZone.create(match[cursor]) : null; 2849 return [{}, zone, cursor + 1]; 2850} 2851 2852// ISO time parsing 2853 2854const isoTimeOnly = RegExp(`^T?${isoTimeBaseRegex.source}$`); 2855 2856// ISO duration parsing 2857 2858const isoDuration = 2859 /^-?P(?:(?:(-?\d{1,20}(?:\.\d{1,20})?)Y)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20}(?:\.\d{1,20})?)W)?(?:(-?\d{1,20}(?:\.\d{1,20})?)D)?(?:T(?:(-?\d{1,20}(?:\.\d{1,20})?)H)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,20}))?S)?)?)$/; 2860 2861function extractISODuration(match) { 2862 const [s, yearStr, monthStr, weekStr, dayStr, hourStr, minuteStr, secondStr, millisecondsStr] = 2863 match; 2864 2865 const hasNegativePrefix = s[0] === "-"; 2866 const negativeSeconds = secondStr && secondStr[0] === "-"; 2867 2868 const maybeNegate = (num, force = false) => 2869 num !== undefined && (force || (num && hasNegativePrefix)) ? -num : num; 2870 2871 return [ 2872 { 2873 years: maybeNegate(parseFloating(yearStr)), 2874 months: maybeNegate(parseFloating(monthStr)), 2875 weeks: maybeNegate(parseFloating(weekStr)), 2876 days: maybeNegate(parseFloating(dayStr)), 2877 hours: maybeNegate(parseFloating(hourStr)), 2878 minutes: maybeNegate(parseFloating(minuteStr)), 2879 seconds: maybeNegate(parseFloating(secondStr), secondStr === "-0"), 2880 milliseconds: maybeNegate(parseMillis(millisecondsStr), negativeSeconds), 2881 }, 2882 ]; 2883} 2884 2885// These are a little braindead. EDT *should* tell us that we're in, say, America/New_York 2886// and not just that we're in -240 *right now*. But since I don't think these are used that often 2887// I'm just going to ignore that 2888const obsOffsets = { 2889 GMT: 0, 2890 EDT: -4 * 60, 2891 EST: -5 * 60, 2892 CDT: -5 * 60, 2893 CST: -6 * 60, 2894 MDT: -6 * 60, 2895 MST: -7 * 60, 2896 PDT: -7 * 60, 2897 PST: -8 * 60, 2898}; 2899 2900function fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) { 2901 const result = { 2902 year: yearStr.length === 2 ? untruncateYear(parseInteger(yearStr)) : parseInteger(yearStr), 2903 month: monthsShort.indexOf(monthStr) + 1, 2904 day: parseInteger(dayStr), 2905 hour: parseInteger(hourStr), 2906 minute: parseInteger(minuteStr), 2907 }; 2908 2909 if (secondStr) result.second = parseInteger(secondStr); 2910 if (weekdayStr) { 2911 result.weekday = 2912 weekdayStr.length > 3 2913 ? weekdaysLong.indexOf(weekdayStr) + 1 2914 : weekdaysShort.indexOf(weekdayStr) + 1; 2915 } 2916 2917 return result; 2918} 2919 2920// RFC 2822/5322 2921const rfc2822 = 2922 /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/; 2923 2924function extractRFC2822(match) { 2925 const [ 2926 , 2927 weekdayStr, 2928 dayStr, 2929 monthStr, 2930 yearStr, 2931 hourStr, 2932 minuteStr, 2933 secondStr, 2934 obsOffset, 2935 milOffset, 2936 offHourStr, 2937 offMinuteStr, 2938 ] = match, 2939 result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr); 2940 2941 let offset; 2942 if (obsOffset) { 2943 offset = obsOffsets[obsOffset]; 2944 } else if (milOffset) { 2945 offset = 0; 2946 } else { 2947 offset = signedOffset(offHourStr, offMinuteStr); 2948 } 2949 2950 return [result, new FixedOffsetZone(offset)]; 2951} 2952 2953function preprocessRFC2822(s) { 2954 // Remove comments and folding whitespace and replace multiple-spaces with a single space 2955 return s 2956 .replace(/\([^()]*\)|[\n\t]/g, " ") 2957 .replace(/(\s\s+)/g, " ") 2958 .trim(); 2959} 2960 2961// http date 2962 2963const rfc1123 = 2964 /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/, 2965 rfc850 = 2966 /^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/, 2967 ascii = 2968 /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/; 2969 2970function extractRFC1123Or850(match) { 2971 const [, weekdayStr, dayStr, monthStr, yearStr, hourStr, minuteStr, secondStr] = match, 2972 result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr); 2973 return [result, FixedOffsetZone.utcInstance]; 2974} 2975 2976function extractASCII(match) { 2977 const [, weekdayStr, monthStr, dayStr, hourStr, minuteStr, secondStr, yearStr] = match, 2978 result = fromStrings(weekdayStr, yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr); 2979 return [result, FixedOffsetZone.utcInstance]; 2980} 2981 2982const isoYmdWithTimeExtensionRegex = combineRegexes(isoYmdRegex, isoTimeExtensionRegex); 2983const isoWeekWithTimeExtensionRegex = combineRegexes(isoWeekRegex, isoTimeExtensionRegex); 2984const isoOrdinalWithTimeExtensionRegex = combineRegexes(isoOrdinalRegex, isoTimeExtensionRegex); 2985const isoTimeCombinedRegex = combineRegexes(isoTimeRegex); 2986 2987const extractISOYmdTimeAndOffset = combineExtractors( 2988 extractISOYmd, 2989 extractISOTime, 2990 extractISOOffset, 2991 extractIANAZone 2992); 2993const extractISOWeekTimeAndOffset = combineExtractors( 2994 extractISOWeekData, 2995 extractISOTime, 2996 extractISOOffset, 2997 extractIANAZone 2998); 2999const extractISOOrdinalDateAndTime = combineExtractors( 3000 extractISOOrdinalData, 3001 extractISOTime, 3002 extractISOOffset, 3003 extractIANAZone 3004); 3005const extractISOTimeAndOffset = combineExtractors( 3006 extractISOTime, 3007 extractISOOffset, 3008 extractIANAZone 3009); 3010 3011/* 3012 * @private 3013 */ 3014 3015function parseISODate(s) { 3016 return parse( 3017 s, 3018 [isoYmdWithTimeExtensionRegex, extractISOYmdTimeAndOffset], 3019 [isoWeekWithTimeExtensionRegex, extractISOWeekTimeAndOffset], 3020 [isoOrdinalWithTimeExtensionRegex, extractISOOrdinalDateAndTime], 3021 [isoTimeCombinedRegex, extractISOTimeAndOffset] 3022 ); 3023} 3024 3025function parseRFC2822Date(s) { 3026 return parse(preprocessRFC2822(s), [rfc2822, extractRFC2822]); 3027} 3028 3029function parseHTTPDate(s) { 3030 return parse( 3031 s, 3032 [rfc1123, extractRFC1123Or850], 3033 [rfc850, extractRFC1123Or850], 3034 [ascii, extractASCII] 3035 ); 3036} 3037 3038function parseISODuration(s) { 3039 return parse(s, [isoDuration, extractISODuration]); 3040} 3041 3042const extractISOTimeOnly = combineExtractors(extractISOTime); 3043 3044function parseISOTimeOnly(s) { 3045 return parse(s, [isoTimeOnly, extractISOTimeOnly]); 3046} 3047 3048const sqlYmdWithTimeExtensionRegex = combineRegexes(sqlYmdRegex, sqlTimeExtensionRegex); 3049const sqlTimeCombinedRegex = combineRegexes(sqlTimeRegex); 3050 3051const extractISOTimeOffsetAndIANAZone = combineExtractors( 3052 extractISOTime, 3053 extractISOOffset, 3054 extractIANAZone 3055); 3056 3057function parseSQL(s) { 3058 return parse( 3059 s, 3060 [sqlYmdWithTimeExtensionRegex, extractISOYmdTimeAndOffset], 3061 [sqlTimeCombinedRegex, extractISOTimeOffsetAndIANAZone] 3062 ); 3063} 3064 3065const INVALID$2 = "Invalid Duration"; 3066 3067// unit conversion constants 3068const lowOrderMatrix = { 3069 weeks: { 3070 days: 7, 3071 hours: 7 * 24, 3072 minutes: 7 * 24 * 60, 3073 seconds: 7 * 24 * 60 * 60, 3074 milliseconds: 7 * 24 * 60 * 60 * 1000, 3075 }, 3076 days: { 3077 hours: 24, 3078 minutes: 24 * 60, 3079 seconds: 24 * 60 * 60, 3080 milliseconds: 24 * 60 * 60 * 1000, 3081 }, 3082 hours: { minutes: 60, seconds: 60 * 60, milliseconds: 60 * 60 * 1000 }, 3083 minutes: { seconds: 60, milliseconds: 60 * 1000 }, 3084 seconds: { milliseconds: 1000 }, 3085 }, 3086 casualMatrix = { 3087 years: { 3088 quarters: 4, 3089 months: 12, 3090 weeks: 52, 3091 days: 365, 3092 hours: 365 * 24, 3093 minutes: 365 * 24 * 60, 3094 seconds: 365 * 24 * 60 * 60, 3095 milliseconds: 365 * 24 * 60 * 60 * 1000, 3096 }, 3097 quarters: { 3098 months: 3, 3099 weeks: 13, 3100 days: 91, 3101 hours: 91 * 24, 3102 minutes: 91 * 24 * 60, 3103 seconds: 91 * 24 * 60 * 60, 3104 milliseconds: 91 * 24 * 60 * 60 * 1000, 3105 }, 3106 months: { 3107 weeks: 4, 3108 days: 30, 3109 hours: 30 * 24, 3110 minutes: 30 * 24 * 60, 3111 seconds: 30 * 24 * 60 * 60, 3112 milliseconds: 30 * 24 * 60 * 60 * 1000, 3113 }, 3114 3115 ...lowOrderMatrix, 3116 }, 3117 daysInYearAccurate = 146097.0 / 400, 3118 daysInMonthAccurate = 146097.0 / 4800, 3119 accurateMatrix = { 3120 years: { 3121 quarters: 4, 3122 months: 12, 3123 weeks: daysInYearAccurate / 7, 3124 days: daysInYearAccurate, 3125 hours: daysInYearAccurate * 24, 3126 minutes: daysInYearAccurate * 24 * 60, 3127 seconds: daysInYearAccurate * 24 * 60 * 60, 3128 milliseconds: daysInYearAccurate * 24 * 60 * 60 * 1000, 3129 }, 3130 quarters: { 3131 months: 3, 3132 weeks: daysInYearAccurate / 28, 3133 days: daysInYearAccurate / 4, 3134 hours: (daysInYearAccurate * 24) / 4, 3135 minutes: (daysInYearAccurate * 24 * 60) / 4, 3136 seconds: (daysInYearAccurate * 24 * 60 * 60) / 4, 3137 milliseconds: (daysInYearAccurate * 24 * 60 * 60 * 1000) / 4, 3138 }, 3139 months: { 3140 weeks: daysInMonthAccurate / 7, 3141 days: daysInMonthAccurate, 3142 hours: daysInMonthAccurate * 24, 3143 minutes: daysInMonthAccurate * 24 * 60, 3144 seconds: daysInMonthAccurate * 24 * 60 * 60, 3145 milliseconds: daysInMonthAccurate * 24 * 60 * 60 * 1000, 3146 }, 3147 ...lowOrderMatrix, 3148 }; 3149 3150// units ordered by size 3151const orderedUnits$1 = [ 3152 "years", 3153 "quarters", 3154 "months", 3155 "weeks", 3156 "days", 3157 "hours", 3158 "minutes", 3159 "seconds", 3160 "milliseconds", 3161]; 3162 3163const reverseUnits = orderedUnits$1.slice(0).reverse(); 3164 3165// clone really means "create another instance just like this one, but with these changes" 3166function clone$1(dur, alts, clear = false) { 3167 // deep merge for vals 3168 const conf = { 3169 values: clear ? alts.values : { ...dur.values, ...(alts.values || {}) }, 3170 loc: dur.loc.clone(alts.loc), 3171 conversionAccuracy: alts.conversionAccuracy || dur.conversionAccuracy, 3172 matrix: alts.matrix || dur.matrix, 3173 }; 3174 return new Duration(conf); 3175} 3176 3177function durationToMillis(matrix, vals) { 3178 let sum = vals.milliseconds ?? 0; 3179 for (const unit of reverseUnits.slice(1)) { 3180 if (vals[unit]) { 3181 sum += vals[unit] * matrix[unit]["milliseconds"]; 3182 } 3183 } 3184 return sum; 3185} 3186 3187// NB: mutates parameters 3188function normalizeValues(matrix, vals) { 3189 // the logic below assumes the overall value of the duration is positive 3190 // if this is not the case, factor is used to make it so 3191 const factor = durationToMillis(matrix, vals) < 0 ? -1 : 1; 3192 3193 orderedUnits$1.reduceRight((previous, current) => { 3194 if (!isUndefined(vals[current])) { 3195 if (previous) { 3196 const previousVal = vals[previous] * factor; 3197 const conv = matrix[current][previous]; 3198 3199 // if (previousVal < 0): 3200 // lower order unit is negative (e.g. { years: 2, days: -2 }) 3201 // normalize this by reducing the higher order unit by the appropriate amount 3202 // and increasing the lower order unit 3203 // this can never make the higher order unit negative, because this function only operates 3204 // on positive durations, so the amount of time represented by the lower order unit cannot 3205 // be larger than the higher order unit 3206 // else: 3207 // lower order unit is positive (e.g. { years: 2, days: 450 } or { years: -2, days: 450 }) 3208 // in this case we attempt to convert as much as possible from the lower order unit into 3209 // the higher order one 3210 // 3211 // Math.floor takes care of both of these cases, rounding away from 0 3212 // if previousVal < 0 it makes the absolute value larger 3213 // if previousVal >= it makes the absolute value smaller 3214 const rollUp = Math.floor(previousVal / conv); 3215 vals[current] += rollUp * factor; 3216 vals[previous] -= rollUp * conv * factor; 3217 } 3218 return current; 3219 } else { 3220 return previous; 3221 } 3222 }, null); 3223 3224 // try to convert any decimals into smaller units if possible 3225 // for example for { years: 2.5, days: 0, seconds: 0 } we want to get { years: 2, days: 182, hours: 12 } 3226 orderedUnits$1.reduce((previous, current) => { 3227 if (!isUndefined(vals[current])) { 3228 if (previous) { 3229 const fraction = vals[previous] % 1; 3230 vals[previous] -= fraction; 3231 vals[current] += fraction * matrix[previous][current]; 3232 } 3233 return current; 3234 } else { 3235 return previous; 3236 } 3237 }, null); 3238} 3239 3240// Remove all properties with a value of 0 from an object 3241function removeZeroes(vals) { 3242 const newVals = {}; 3243 for (const [key, value] of Object.entries(vals)) { 3244 if (value !== 0) { 3245 newVals[key] = value; 3246 } 3247 } 3248 return newVals; 3249} 3250 3251/** 3252 * A Duration object represents a period of time, like "2 months" or "1 day, 1 hour". Conceptually, it's just a map of units to their quantities, accompanied by some additional configuration and methods for creating, parsing, interrogating, transforming, and formatting them. They can be used on their own or in conjunction with other Luxon types; for example, you can use {@link DateTime#plus} to add a Duration object to a DateTime, producing another DateTime. 3253 * 3254 * Here is a brief overview of commonly used methods and getters in Duration: 3255 * 3256 * * **Creation** To create a Duration, use {@link Duration.fromMillis}, {@link Duration.fromObject}, or {@link Duration.fromISO}. 3257 * * **Unit values** See the {@link Duration#years}, {@link Duration#months}, {@link Duration#weeks}, {@link Duration#days}, {@link Duration#hours}, {@link Duration#minutes}, {@link Duration#seconds}, {@link Duration#milliseconds} accessors. 3258 * * **Configuration** See {@link Duration#locale} and {@link Duration#numberingSystem} accessors. 3259 * * **Transformation** To create new Durations out of old ones use {@link Duration#plus}, {@link Duration#minus}, {@link Duration#normalize}, {@link Duration#set}, {@link Duration#reconfigure}, {@link Duration#shiftTo}, and {@link Duration#negate}. 3260 * * **Output** To convert the Duration into other representations, see {@link Duration#as}, {@link Duration#toISO}, {@link Duration#toFormat}, and {@link Duration#toJSON} 3261 * 3262 * There's are more methods documented below. In addition, for more information on subtler topics like internationalization and validity, see the external documentation. 3263 */ 3264class Duration { 3265 /** 3266 * @private 3267 */ 3268 constructor(config) { 3269 const accurate = config.conversionAccuracy === "longterm" || false; 3270 let matrix = accurate ? accurateMatrix : casualMatrix; 3271 3272 if (config.matrix) { 3273 matrix = config.matrix; 3274 } 3275 3276 /** 3277 * @access private 3278 */ 3279 this.values = config.values; 3280 /** 3281 * @access private 3282 */ 3283 this.loc = config.loc || Locale.create(); 3284 /** 3285 * @access private 3286 */ 3287 this.conversionAccuracy = accurate ? "longterm" : "casual"; 3288 /** 3289 * @access private 3290 */ 3291 this.invalid = config.invalid || null; 3292 /** 3293 * @access private 3294 */ 3295 this.matrix = matrix; 3296 /** 3297 * @access private 3298 */ 3299 this.isLuxonDuration = true; 3300 } 3301 3302 /** 3303 * Create Duration from a number of milliseconds. 3304 * @param {number} count of milliseconds 3305 * @param {Object} opts - options for parsing 3306 * @param {string} [opts.locale='en-US'] - the locale to use 3307 * @param {string} opts.numberingSystem - the numbering system to use 3308 * @param {string} [opts.conversionAccuracy='casual'] - the conversion system to use 3309 * @return {Duration} 3310 */ 3311 static fromMillis(count, opts) { 3312 return Duration.fromObject({ milliseconds: count }, opts); 3313 } 3314 3315 /** 3316 * Create a Duration from a JavaScript object with keys like 'years' and 'hours'. 3317 * If this object is empty then a zero milliseconds duration is returned. 3318 * @param {Object} obj - the object to create the DateTime from 3319 * @param {number} obj.years 3320 * @param {number} obj.quarters 3321 * @param {number} obj.months 3322 * @param {number} obj.weeks 3323 * @param {number} obj.days 3324 * @param {number} obj.hours 3325 * @param {number} obj.minutes 3326 * @param {number} obj.seconds 3327 * @param {number} obj.milliseconds 3328 * @param {Object} [opts=[]] - options for creating this Duration 3329 * @param {string} [opts.locale='en-US'] - the locale to use 3330 * @param {string} opts.numberingSystem - the numbering system to use 3331 * @param {string} [opts.conversionAccuracy='casual'] - the preset conversion system to use 3332 * @param {string} [opts.matrix=Object] - the custom conversion system to use 3333 * @return {Duration} 3334 */ 3335 static fromObject(obj, opts = {}) { 3336 if (obj == null || typeof obj !== "object") { 3337 throw new InvalidArgumentError( 3338 `Duration.fromObject: argument expected to be an object, got ${ 3339 obj === null ? "null" : typeof obj 3340 }` 3341 ); 3342 } 3343 3344 return new Duration({ 3345 values: normalizeObject(obj, Duration.normalizeUnit), 3346 loc: Locale.fromObject(opts), 3347 conversionAccuracy: opts.conversionAccuracy, 3348 matrix: opts.matrix, 3349 }); 3350 } 3351 3352 /** 3353 * Create a Duration from DurationLike. 3354 * 3355 * @param {Object | number | Duration} durationLike 3356 * One of: 3357 * - object with keys like 'years' and 'hours'. 3358 * - number representing milliseconds 3359 * - Duration instance 3360 * @return {Duration} 3361 */ 3362 static fromDurationLike(durationLike) { 3363 if (isNumber(durationLike)) { 3364 return Duration.fromMillis(durationLike); 3365 } else if (Duration.isDuration(durationLike)) { 3366 return durationLike; 3367 } else if (typeof durationLike === "object") { 3368 return Duration.fromObject(durationLike); 3369 } else { 3370 throw new InvalidArgumentError( 3371 `Unknown duration argument ${durationLike} of type ${typeof durationLike}` 3372 ); 3373 } 3374 } 3375 3376 /** 3377 * Create a Duration from an ISO 8601 duration string. 3378 * @param {string} text - text to parse 3379 * @param {Object} opts - options for parsing 3380 * @param {string} [opts.locale='en-US'] - the locale to use 3381 * @param {string} opts.numberingSystem - the numbering system to use 3382 * @param {string} [opts.conversionAccuracy='casual'] - the preset conversion system to use 3383 * @param {string} [opts.matrix=Object] - the preset conversion system to use 3384 * @see https://en.wikipedia.org/wiki/ISO_8601#Durations 3385 * @example Duration.fromISO('P3Y6M1W4DT12H30M5S').toObject() //=> { years: 3, months: 6, weeks: 1, days: 4, hours: 12, minutes: 30, seconds: 5 } 3386 * @example Duration.fromISO('PT23H').toObject() //=> { hours: 23 } 3387 * @example Duration.fromISO('P5Y3M').toObject() //=> { years: 5, months: 3 } 3388 * @return {Duration} 3389 */ 3390 static fromISO(text, opts) { 3391 const [parsed] = parseISODuration(text); 3392 if (parsed) { 3393 return Duration.fromObject(parsed, opts); 3394 } else { 3395 return Duration.invalid("unparsable", `the input "${text}" can't be parsed as ISO 8601`); 3396 } 3397 } 3398 3399 /** 3400 * Create a Duration from an ISO 8601 time string. 3401 * @param {string} text - text to parse 3402 * @param {Object} opts - options for parsing 3403 * @param {string} [opts.locale='en-US'] - the locale to use 3404 * @param {string} opts.numberingSystem - the numbering system to use 3405 * @param {string} [opts.conversionAccuracy='casual'] - the preset conversion system to use 3406 * @param {string} [opts.matrix=Object] - the conversion system to use 3407 * @see https://en.wikipedia.org/wiki/ISO_8601#Times 3408 * @example Duration.fromISOTime('11:22:33.444').toObject() //=> { hours: 11, minutes: 22, seconds: 33, milliseconds: 444 } 3409 * @example Duration.fromISOTime('11:00').toObject() //=> { hours: 11, minutes: 0, seconds: 0 } 3410 * @example Duration.fromISOTime('T11:00').toObject() //=> { hours: 11, minutes: 0, seconds: 0 } 3411 * @example Duration.fromISOTime('1100').toObject() //=> { hours: 11, minutes: 0, seconds: 0 } 3412 * @example Duration.fromISOTime('T1100').toObject() //=> { hours: 11, minutes: 0, seconds: 0 } 3413 * @return {Duration} 3414 */ 3415 static fromISOTime(text, opts) { 3416 const [parsed] = parseISOTimeOnly(text); 3417 if (parsed) { 3418 return Duration.fromObject(parsed, opts); 3419 } else { 3420 return Duration.invalid("unparsable", `the input "${text}" can't be parsed as ISO 8601`); 3421 } 3422 } 3423 3424 /** 3425 * Create an invalid Duration. 3426 * @param {string} reason - simple string of why this datetime is invalid. Should not contain parameters or anything else data-dependent 3427 * @param {string} [explanation=null] - longer explanation, may include parameters and other useful debugging information 3428 * @return {Duration} 3429 */ 3430 static invalid(reason, explanation = null) { 3431 if (!reason) { 3432 throw new InvalidArgumentError("need to specify a reason the Duration is invalid"); 3433 } 3434 3435 const invalid = reason instanceof Invalid ? reason : new Invalid(reason, explanation); 3436 3437 if (Settings.throwOnInvalid) { 3438 throw new InvalidDurationError(invalid); 3439 } else { 3440 return new Duration({ invalid }); 3441 } 3442 } 3443 3444 /** 3445 * @private 3446 */ 3447 static normalizeUnit(unit) { 3448 const normalized = { 3449 year: "years", 3450 years: "years", 3451 quarter: "quarters", 3452 quarters: "quarters", 3453 month: "months", 3454 months: "months", 3455 week: "weeks", 3456 weeks: "weeks", 3457 day: "days", 3458 days: "days", 3459 hour: "hours", 3460 hours: "hours", 3461 minute: "minutes", 3462 minutes: "minutes", 3463 second: "seconds", 3464 seconds: "seconds", 3465 millisecond: "milliseconds", 3466 milliseconds: "milliseconds", 3467 }[unit ? unit.toLowerCase() : unit]; 3468 3469 if (!normalized) throw new InvalidUnitError(unit); 3470 3471 return normalized; 3472 } 3473 3474 /** 3475 * Check if an object is a Duration. Works across context boundaries 3476 * @param {object} o 3477 * @return {boolean} 3478 */ 3479 static isDuration(o) { 3480 return (o && o.isLuxonDuration) || false; 3481 } 3482 3483 /** 3484 * Get the locale of a Duration, such 'en-GB' 3485 * @type {string} 3486 */ 3487 get locale() { 3488 return this.isValid ? this.loc.locale : null; 3489 } 3490 3491 /** 3492 * Get the numbering system of a Duration, such 'beng'. The numbering system is used when formatting the Duration 3493 * 3494 * @type {string} 3495 */ 3496 get numberingSystem() { 3497 return this.isValid ? this.loc.numberingSystem : null; 3498 } 3499 3500 /** 3501 * Returns a string representation of this Duration formatted according to the specified format string. You may use these tokens: 3502 * * `S` for milliseconds 3503 * * `s` for seconds 3504 * * `m` for minutes 3505 * * `h` for hours 3506 * * `d` for days 3507 * * `w` for weeks 3508 * * `M` for months 3509 * * `y` for years 3510 * Notes: 3511 * * Add padding by repeating the token, e.g. "yy" pads the years to two digits, "hhhh" pads the hours out to four digits 3512 * * Tokens can be escaped by wrapping with single quotes. 3513 * * The duration will be converted to the set of units in the format string using {@link Duration#shiftTo} and the Durations's conversion accuracy setting. 3514 * @param {string} fmt - the format string 3515 * @param {Object} opts - options 3516 * @param {boolean} [opts.floor=true] - floor numerical values 3517 * @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("y d s") //=> "1 6 2" 3518 * @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("yy dd sss") //=> "01 06 002" 3519 * @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toFormat("M S") //=> "12 518402000" 3520 * @return {string} 3521 */ 3522 toFormat(fmt, opts = {}) { 3523 // reverse-compat since 1.2; we always round down now, never up, and we do it by default 3524 const fmtOpts = { 3525 ...opts, 3526 floor: opts.round !== false && opts.floor !== false, 3527 }; 3528 return this.isValid 3529 ? Formatter.create(this.loc, fmtOpts).formatDurationFromString(this, fmt) 3530 : INVALID$2; 3531 } 3532 3533 /** 3534 * Returns a string representation of a Duration with all units included. 3535 * To modify its behavior, use `listStyle` and any Intl.NumberFormat option, though `unitDisplay` is especially relevant. 3536 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options 3537 * @param {Object} opts - Formatting options. Accepts the same keys as the options parameter of the native `Intl.NumberFormat` constructor, as well as `listStyle`. 3538 * @param {string} [opts.listStyle='narrow'] - How to format the merged list. Corresponds to the `style` property of the options parameter of the native `Intl.ListFormat` constructor. 3539 * @example 3540 * ```js 3541 * var dur = Duration.fromObject({ days: 1, hours: 5, minutes: 6 }) 3542 * dur.toHuman() //=> '1 day, 5 hours, 6 minutes' 3543 * dur.toHuman({ listStyle: "long" }) //=> '1 day, 5 hours, and 6 minutes' 3544 * dur.toHuman({ unitDisplay: "short" }) //=> '1 day, 5 hr, 6 min' 3545 * ``` 3546 */ 3547 toHuman(opts = {}) { 3548 if (!this.isValid) return INVALID$2; 3549 3550 const l = orderedUnits$1 3551 .map((unit) => { 3552 const val = this.values[unit]; 3553 if (isUndefined(val)) { 3554 return null; 3555 } 3556 return this.loc 3557 .numberFormatter({ style: "unit", unitDisplay: "long", ...opts, unit: unit.slice(0, -1) }) 3558 .format(val); 3559 }) 3560 .filter((n) => n); 3561 3562 return this.loc 3563 .listFormatter({ type: "conjunction", style: opts.listStyle || "narrow", ...opts }) 3564 .format(l); 3565 } 3566 3567 /** 3568 * Returns a JavaScript object with this Duration's values. 3569 * @example Duration.fromObject({ years: 1, days: 6, seconds: 2 }).toObject() //=> { years: 1, days: 6, seconds: 2 } 3570 * @return {Object} 3571 */ 3572 toObject() { 3573 if (!this.isValid) return {}; 3574 return { ...this.values }; 3575 } 3576 3577 /** 3578 * Returns an ISO 8601-compliant string representation of this Duration. 3579 * @see https://en.wikipedia.org/wiki/ISO_8601#Durations 3580 * @example Duration.fromObject({ years: 3, seconds: 45 }).toISO() //=> 'P3YT45S' 3581 * @example Duration.fromObject({ months: 4, seconds: 45 }).toISO() //=> 'P4MT45S' 3582 * @example Duration.fromObject({ months: 5 }).toISO() //=> 'P5M' 3583 * @example Duration.fromObject({ minutes: 5 }).toISO() //=> 'PT5M' 3584 * @example Duration.fromObject({ milliseconds: 6 }).toISO() //=> 'PT0.006S' 3585 * @return {string} 3586 */ 3587 toISO() { 3588 // we could use the formatter, but this is an easier way to get the minimum string 3589 if (!this.isValid) return null; 3590 3591 let s = "P"; 3592 if (this.years !== 0) s += this.years + "Y"; 3593 if (this.months !== 0 || this.quarters !== 0) s += this.months + this.quarters * 3 + "M"; 3594 if (this.weeks !== 0) s += this.weeks + "W"; 3595 if (this.days !== 0) s += this.days + "D"; 3596 if (this.hours !== 0 || this.minutes !== 0 || this.seconds !== 0 || this.milliseconds !== 0) 3597 s += "T"; 3598 if (this.hours !== 0) s += this.hours + "H"; 3599 if (this.minutes !== 0) s += this.minutes + "M"; 3600 if (this.seconds !== 0 || this.milliseconds !== 0) 3601 // this will handle "floating point madness" by removing extra decimal places 3602 // https://stackoverflow.com/questions/588004/is-floating-point-math-broken 3603 s += roundTo(this.seconds + this.milliseconds / 1000, 3) + "S"; 3604 if (s === "P") s += "T0S"; 3605 return s; 3606 } 3607 3608 /** 3609 * Returns an ISO 8601-compliant string representation of this Duration, formatted as a time of day. 3610 * Note that this will return null if the duration is invalid, negative, or equal to or greater than 24 hours. 3611 * @see https://en.wikipedia.org/wiki/ISO_8601#Times 3612 * @param {Object} opts - options 3613 * @param {boolean} [opts.suppressMilliseconds=false] - exclude milliseconds from the format if they're 0 3614 * @param {boolean} [opts.suppressSeconds=false] - exclude seconds from the format if they're 0 3615 * @param {boolean} [opts.includePrefix=false] - include the `T` prefix 3616 * @param {string} [opts.format='extended'] - choose between the basic and extended format 3617 * @example Duration.fromObject({ hours: 11 }).toISOTime() //=> '11:00:00.000' 3618 * @example Duration.fromObject({ hours: 11 }).toISOTime({ suppressMilliseconds: true }) //=> '11:00:00' 3619 * @example Duration.fromObject({ hours: 11 }).toISOTime({ suppressSeconds: true }) //=> '11:00' 3620 * @example Duration.fromObject({ hours: 11 }).toISOTime({ includePrefix: true }) //=> 'T11:00:00.000' 3621 * @example Duration.fromObject({ hours: 11 }).toISOTime({ format: 'basic' }) //=> '110000.000' 3622 * @return {string} 3623 */ 3624 toISOTime(opts = {}) { 3625 if (!this.isValid) return null; 3626 3627 const millis = this.toMillis(); 3628 if (millis < 0 || millis >= 86400000) return null; 3629 3630 opts = { 3631 suppressMilliseconds: false, 3632 suppressSeconds: false, 3633 includePrefix: false, 3634 format: "extended", 3635 ...opts, 3636 includeOffset: false, 3637 }; 3638 3639 const dateTime = DateTime.fromMillis(millis, { zone: "UTC" }); 3640 return dateTime.toISOTime(opts); 3641 } 3642 3643 /** 3644 * Returns an ISO 8601 representation of this Duration appropriate for use in JSON. 3645 * @return {string} 3646 */ 3647 toJSON() { 3648 return this.toISO(); 3649 } 3650 3651 /** 3652 * Returns an ISO 8601 representation of this Duration appropriate for use in debugging. 3653 * @return {string} 3654 */ 3655 toString() { 3656 return this.toISO(); 3657 } 3658 3659 /** 3660 * Returns a string representation of this Duration appropriate for the REPL. 3661 * @return {string} 3662 */ 3663 [Symbol.for("nodejs.util.inspect.custom")]() { 3664 if (this.isValid) { 3665 return `Duration { values: ${JSON.stringify(this.values)} }`; 3666 } else { 3667 return `Duration { Invalid, reason: ${this.invalidReason} }`; 3668 } 3669 } 3670 3671 /** 3672 * Returns an milliseconds value of this Duration. 3673 * @return {number} 3674 */ 3675 toMillis() { 3676 if (!this.isValid) return NaN; 3677 3678 return durationToMillis(this.matrix, this.values); 3679 } 3680 3681 /** 3682 * Returns an milliseconds value of this Duration. Alias of {@link toMillis} 3683 * @return {number} 3684 */ 3685 valueOf() { 3686 return this.toMillis(); 3687 } 3688 3689 /** 3690 * Make this Duration longer by the specified amount. Return a newly-constructed Duration. 3691 * @param {Duration|Object|number} duration - The amount to add. Either a Luxon Duration, a number of milliseconds, the object argument to Duration.fromObject() 3692 * @return {Duration} 3693 */ 3694 plus(duration) { 3695 if (!this.isValid) return this; 3696 3697 const dur = Duration.fromDurationLike(duration), 3698 result = {}; 3699 3700 for (const k of orderedUnits$1) { 3701 if (hasOwnProperty(dur.values, k) || hasOwnProperty(this.values, k)) { 3702 result[k] = dur.get(k) + this.get(k); 3703 } 3704 } 3705 3706 return clone$1(this, { values: result }, true); 3707 } 3708 3709 /** 3710 * Make this Duration shorter by the specified amount. Return a newly-constructed Duration. 3711 * @param {Duration|Object|number} duration - The amount to subtract. Either a Luxon Duration, a number of milliseconds, the object argument to Duration.fromObject() 3712 * @return {Duration} 3713 */ 3714 minus(duration) { 3715 if (!this.isValid) return this; 3716 3717 const dur = Duration.fromDurationLike(duration); 3718 return this.plus(dur.negate()); 3719 } 3720 3721 /** 3722 * Scale this Duration by the specified amount. Return a newly-constructed Duration. 3723 * @param {function} fn - The function to apply to each unit. Arity is 1 or 2: the value of the unit and, optionally, the unit name. Must return a number. 3724 * @example Duration.fromObject({ hours: 1, minutes: 30 }).mapUnits(x => x * 2) //=> { hours: 2, minutes: 60 } 3725 * @example Duration.fromObject({ hours: 1, minutes: 30 }).mapUnits((x, u) => u === "hours" ? x * 2 : x) //=> { hours: 2, minutes: 30 } 3726 * @return {Duration} 3727 */ 3728 mapUnits(fn) { 3729 if (!this.isValid) return this; 3730 const result = {}; 3731 for (const k of Object.keys(this.values)) { 3732 result[k] = asNumber(fn(this.values[k], k)); 3733 } 3734 return clone$1(this, { values: result }, true); 3735 } 3736 3737 /** 3738 * Get the value of unit. 3739 * @param {string} unit - a unit such as 'minute' or 'day' 3740 * @example Duration.fromObject({years: 2, days: 3}).get('years') //=> 2 3741 * @example Duration.fromObject({years: 2, days: 3}).get('months') //=> 0 3742 * @example Duration.fromObject({years: 2, days: 3}).get('days') //=> 3 3743 * @return {number} 3744 */ 3745 get(unit) { 3746 return this[Duration.normalizeUnit(unit)]; 3747 } 3748 3749 /** 3750 * "Set" the values of specified units. Return a newly-constructed Duration. 3751 * @param {Object} values - a mapping of units to numbers 3752 * @example dur.set({ years: 2017 }) 3753 * @example dur.set({ hours: 8, minutes: 30 }) 3754 * @return {Duration} 3755 */ 3756 set(values) { 3757 if (!this.isValid) return this; 3758 3759 const mixed = { ...this.values, ...normalizeObject(values, Duration.normalizeUnit) }; 3760 return clone$1(this, { values: mixed }); 3761 } 3762 3763 /** 3764 * "Set" the locale and/or numberingSystem. Returns a newly-constructed Duration. 3765 * @example dur.reconfigure({ locale: 'en-GB' }) 3766 * @return {Duration} 3767 */ 3768 reconfigure({ locale, numberingSystem, conversionAccuracy, matrix } = {}) { 3769 const loc = this.loc.clone({ locale, numberingSystem }); 3770 const opts = { loc, matrix, conversionAccuracy }; 3771 return clone$1(this, opts); 3772 } 3773 3774 /** 3775 * Return the length of the duration in the specified unit. 3776 * @param {string} unit - a unit such as 'minutes' or 'days' 3777 * @example Duration.fromObject({years: 1}).as('days') //=> 365 3778 * @example Duration.fromObject({years: 1}).as('months') //=> 12 3779 * @example Duration.fromObject({hours: 60}).as('days') //=> 2.5 3780 * @return {number} 3781 */ 3782 as(unit) { 3783 return this.isValid ? this.shiftTo(unit).get(unit) : NaN; 3784 } 3785 3786 /** 3787 * Reduce this Duration to its canonical representation in its current units. 3788 * Assuming the overall value of the Duration is positive, this means: 3789 * - excessive values for lower-order units are converted to higher-order units (if possible, see first and second example) 3790 * - negative lower-order units are converted to higher order units (there must be such a higher order unit, otherwise 3791 * the overall value would be negative, see third example) 3792 * - fractional values for higher-order units are converted to lower-order units (if possible, see fourth example) 3793 * 3794 * If the overall value is negative, the result of this method is equivalent to `this.negate().normalize().negate()`. 3795 * @example Duration.fromObject({ years: 2, days: 5000 }).normalize().toObject() //=> { years: 15, days: 255 } 3796 * @example Duration.fromObject({ days: 5000 }).normalize().toObject() //=> { days: 5000 } 3797 * @example Duration.fromObject({ hours: 12, minutes: -45 }).normalize().toObject() //=> { hours: 11, minutes: 15 } 3798 * @example Duration.fromObject({ years: 2.5, days: 0, hours: 0 }).normalize().toObject() //=> { years: 2, days: 182, hours: 12 } 3799 * @return {Duration} 3800 */ 3801 normalize() { 3802 if (!this.isValid) return this; 3803 const vals = this.toObject(); 3804 normalizeValues(this.matrix, vals); 3805 return clone$1(this, { values: vals }, true); 3806 } 3807 3808 /** 3809 * Rescale units to its largest representation 3810 * @example Duration.fromObject({ milliseconds: 90000 }).rescale().toObject() //=> { minutes: 1, seconds: 30 } 3811 * @return {Duration} 3812 */ 3813 rescale() { 3814 if (!this.isValid) return this; 3815 const vals = removeZeroes(this.normalize().shiftToAll().toObject()); 3816 return clone$1(this, { values: vals }, true); 3817 } 3818 3819 /** 3820 * Convert this Duration into its representation in a different set of units. 3821 * @example Duration.fromObject({ hours: 1, seconds: 30 }).shiftTo('minutes', 'milliseconds').toObject() //=> { minutes: 60, milliseconds: 30000 } 3822 * @return {Duration} 3823 */ 3824 shiftTo(...units) { 3825 if (!this.isValid) return this; 3826 3827 if (units.length === 0) { 3828 return this; 3829 } 3830 3831 units = units.map((u) => Duration.normalizeUnit(u)); 3832 3833 const built = {}, 3834 accumulated = {}, 3835 vals = this.toObject(); 3836 let lastUnit; 3837 3838 for (const k of orderedUnits$1) { 3839 if (units.indexOf(k) >= 0) { 3840 lastUnit = k; 3841 3842 let own = 0; 3843 3844 // anything we haven't boiled down yet should get boiled to this unit 3845 for (const ak in accumulated) { 3846 own += this.matrix[ak][k] * accumulated[ak]; 3847 accumulated[ak] = 0; 3848 } 3849 3850 // plus anything that's already in this unit 3851 if (isNumber(vals[k])) { 3852 own += vals[k]; 3853 } 3854 3855 // only keep the integer part for now in the hopes of putting any decimal part 3856 // into a smaller unit later 3857 const i = Math.trunc(own); 3858 built[k] = i; 3859 accumulated[k] = (own * 1000 - i * 1000) / 1000; 3860 3861 // otherwise, keep it in the wings to boil it later 3862 } else if (isNumber(vals[k])) { 3863 accumulated[k] = vals[k]; 3864 } 3865 } 3866 3867 // anything leftover becomes the decimal for the last unit 3868 // lastUnit must be defined since units is not empty 3869 for (const key in accumulated) { 3870 if (accumulated[key] !== 0) { 3871 built[lastUnit] += 3872 key === lastUnit ? accumulated[key] : accumulated[key] / this.matrix[lastUnit][key]; 3873 } 3874 } 3875 3876 normalizeValues(this.matrix, built); 3877 return clone$1(this, { values: built }, true); 3878 } 3879 3880 /** 3881 * Shift this Duration to all available units. 3882 * Same as shiftTo("years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds") 3883 * @return {Duration} 3884 */ 3885 shiftToAll() { 3886 if (!this.isValid) return this; 3887 return this.shiftTo( 3888 "years", 3889 "months", 3890 "weeks", 3891 "days", 3892 "hours", 3893 "minutes", 3894 "seconds", 3895 "milliseconds" 3896 ); 3897 } 3898 3899 /** 3900 * Return the negative of this Duration. 3901 * @example Duration.fromObject({ hours: 1, seconds: 30 }).negate().toObject() //=> { hours: -1, seconds: -30 } 3902 * @return {Duration} 3903 */ 3904 negate() { 3905 if (!this.isValid) return this; 3906 const negated = {}; 3907 for (const k of Object.keys(this.values)) { 3908 negated[k] = this.values[k] === 0 ? 0 : -this.values[k]; 3909 } 3910 return clone$1(this, { values: negated }, true); 3911 } 3912 3913 /** 3914 * Get the years. 3915 * @type {number} 3916 */ 3917 get years() { 3918 return this.isValid ? this.values.years || 0 : NaN; 3919 } 3920 3921 /** 3922 * Get the quarters. 3923 * @type {number} 3924 */ 3925 get quarters() { 3926 return this.isValid ? this.values.quarters || 0 : NaN; 3927 } 3928 3929 /** 3930 * Get the months. 3931 * @type {number} 3932 */ 3933 get months() { 3934 return this.isValid ? this.values.months || 0 : NaN; 3935 } 3936 3937 /** 3938 * Get the weeks 3939 * @type {number} 3940 */ 3941 get weeks() { 3942 return this.isValid ? this.values.weeks || 0 : NaN; 3943 } 3944 3945 /** 3946 * Get the days. 3947 * @type {number} 3948 */ 3949 get days() { 3950 return this.isValid ? this.values.days || 0 : NaN; 3951 } 3952 3953 /** 3954 * Get the hours. 3955 * @type {number} 3956 */ 3957 get hours() { 3958 return this.isValid ? this.values.hours || 0 : NaN; 3959 } 3960 3961 /** 3962 * Get the minutes. 3963 * @type {number} 3964 */ 3965 get minutes() { 3966 return this.isValid ? this.values.minutes || 0 : NaN; 3967 } 3968 3969 /** 3970 * Get the seconds. 3971 * @return {number} 3972 */ 3973 get seconds() { 3974 return this.isValid ? this.values.seconds || 0 : NaN; 3975 } 3976 3977 /** 3978 * Get the milliseconds. 3979 * @return {number} 3980 */ 3981 get milliseconds() { 3982 return this.isValid ? this.values.milliseconds || 0 : NaN; 3983 } 3984 3985 /** 3986 * Returns whether the Duration is invalid. Invalid durations are returned by diff operations 3987 * on invalid DateTimes or Intervals. 3988 * @return {boolean} 3989 */ 3990 get isValid() { 3991 return this.invalid === null; 3992 } 3993 3994 /** 3995 * Returns an error code if this Duration became invalid, or null if the Duration is valid 3996 * @return {string} 3997 */ 3998 get invalidReason() { 3999 return this.invalid ? this.invalid.reason : null; 4000 } 4001 4002 /** 4003 * Returns an explanation of why this Duration became invalid, or null if the Duration is valid 4004 * @type {string} 4005 */ 4006 get invalidExplanation() { 4007 return this.invalid ? this.invalid.explanation : null; 4008 } 4009 4010 /** 4011 * Equality check 4012 * Two Durations are equal iff they have the same units and the same values for each unit. 4013 * @param {Duration} other 4014 * @return {boolean} 4015 */ 4016 equals(other) { 4017 if (!this.isValid || !other.isValid) { 4018 return false; 4019 } 4020 4021 if (!this.loc.equals(other.loc)) { 4022 return false; 4023 } 4024 4025 function eq(v1, v2) { 4026 // Consider 0 and undefined as equal 4027 if (v1 === undefined || v1 === 0) return v2 === undefined || v2 === 0; 4028 return v1 === v2; 4029 } 4030 4031 for (const u of orderedUnits$1) { 4032 if (!eq(this.values[u], other.values[u])) { 4033 return false; 4034 } 4035 } 4036 return true; 4037 } 4038} 4039 4040const INVALID$1 = "Invalid Interval"; 4041 4042// checks if the start is equal to or before the end 4043function validateStartEnd(start, end) { 4044 if (!start || !start.isValid) { 4045 return Interval.invalid("missing or invalid start"); 4046 } else if (!end || !end.isValid) { 4047 return Interval.invalid("missing or invalid end"); 4048 } else if (end < start) { 4049 return Interval.invalid( 4050 "end before start", 4051 `The end of an interval must be after its start, but you had start=${start.toISO()} and end=${end.toISO()}` 4052 ); 4053 } else { 4054 return null; 4055 } 4056} 4057 4058/** 4059 * An Interval object represents a half-open interval of time, where each endpoint is a {@link DateTime}. Conceptually, it's a container for those two endpoints, accompanied by methods for creating, parsing, interrogating, comparing, transforming, and formatting them. 4060 * 4061 * Here is a brief overview of the most commonly used methods and getters in Interval: 4062 * 4063 * * **Creation** To create an Interval, use {@link Interval.fromDateTimes}, {@link Interval.after}, {@link Interval.before}, or {@link Interval.fromISO}. 4064 * * **Accessors** Use {@link Interval#start} and {@link Interval#end} to get the start and end. 4065 * * **Interrogation** To analyze the Interval, use {@link Interval#count}, {@link Interval#length}, {@link Interval#hasSame}, {@link Interval#contains}, {@link Interval#isAfter}, or {@link Interval#isBefore}. 4066 * * **Transformation** To create other Intervals out of this one, use {@link Interval#set}, {@link Interval#splitAt}, {@link Interval#splitBy}, {@link Interval#divideEqually}, {@link Interval.merge}, {@link Interval.xor}, {@link Interval#union}, {@link Interval#intersection}, or {@link Interval#difference}. 4067 * * **Comparison** To compare this Interval to another one, use {@link Interval#equals}, {@link Interval#overlaps}, {@link Interval#abutsStart}, {@link Interval#abutsEnd}, {@link Interval#engulfs} 4068 * * **Output** To convert the Interval into other representations, see {@link Interval#toString}, {@link Interval#toLocaleString}, {@link Interval#toISO}, {@link Interval#toISODate}, {@link Interval#toISOTime}, {@link Interval#toFormat}, and {@link Interval#toDuration}. 4069 */ 4070class Interval { 4071 /** 4072 * @private 4073 */ 4074 constructor(config) { 4075 /** 4076 * @access private 4077 */ 4078 this.s = config.start; 4079 /** 4080 * @access private 4081 */ 4082 this.e = config.end; 4083 /** 4084 * @access private 4085 */ 4086 this.invalid = config.invalid || null; 4087 /** 4088 * @access private 4089 */ 4090 this.isLuxonInterval = true; 4091 } 4092 4093 /** 4094 * Create an invalid Interval. 4095 * @param {string} reason - simple string of why this Interval is invalid. Should not contain parameters or anything else data-dependent 4096 * @param {string} [explanation=null] - longer explanation, may include parameters and other useful debugging information 4097 * @return {Interval} 4098 */ 4099 static invalid(reason, explanation = null) { 4100 if (!reason) { 4101 throw new InvalidArgumentError("need to specify a reason the Interval is invalid"); 4102 } 4103 4104 const invalid = reason instanceof Invalid ? reason : new Invalid(reason, explanation); 4105 4106 if (Settings.throwOnInvalid) { 4107 throw new InvalidIntervalError(invalid); 4108 } else { 4109 return new Interval({ invalid }); 4110 } 4111 } 4112 4113 /** 4114 * Create an Interval from a start DateTime and an end DateTime. Inclusive of the start but not the end. 4115 * @param {DateTime|Date|Object} start 4116 * @param {DateTime|Date|Object} end 4117 * @return {Interval} 4118 */ 4119 static fromDateTimes(start, end) { 4120 const builtStart = friendlyDateTime(start), 4121 builtEnd = friendlyDateTime(end); 4122 4123 const validateError = validateStartEnd(builtStart, builtEnd); 4124 4125 if (validateError == null) { 4126 return new Interval({ 4127 start: builtStart, 4128 end: builtEnd, 4129 }); 4130 } else { 4131 return validateError; 4132 } 4133 } 4134 4135 /** 4136 * Create an Interval from a start DateTime and a Duration to extend to. 4137 * @param {DateTime|Date|Object} start 4138 * @param {Duration|Object|number} duration - the length of the Interval. 4139 * @return {Interval} 4140 */ 4141 static after(start, duration) { 4142 const dur = Duration.fromDurationLike(duration), 4143 dt = friendlyDateTime(start); 4144 return Interval.fromDateTimes(dt, dt.plus(dur)); 4145 } 4146 4147 /** 4148 * Create an Interval from an end DateTime and a Duration to extend backwards to. 4149 * @param {DateTime|Date|Object} end 4150 * @param {Duration|Object|number} duration - the length of the Interval. 4151 * @return {Interval} 4152 */ 4153 static before(end, duration) { 4154 const dur = Duration.fromDurationLike(duration), 4155 dt = friendlyDateTime(end); 4156 return Interval.fromDateTimes(dt.minus(dur), dt); 4157 } 4158 4159 /** 4160 * Create an Interval from an ISO 8601 string. 4161 * Accepts `<start>/<end>`, `<start>/<duration>`, and `<duration>/<end>` formats. 4162 * @param {string} text - the ISO string to parse 4163 * @param {Object} [opts] - options to pass {@link DateTime#fromISO} and optionally {@link Duration#fromISO} 4164 * @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals 4165 * @return {Interval} 4166 */ 4167 static fromISO(text, opts) { 4168 const [s, e] = (text || "").split("/", 2); 4169 if (s && e) { 4170 let start, startIsValid; 4171 try { 4172 start = DateTime.fromISO(s, opts); 4173 startIsValid = start.isValid; 4174 } catch (e) { 4175 startIsValid = false; 4176 } 4177 4178 let end, endIsValid; 4179 try { 4180 end = DateTime.fromISO(e, opts); 4181 endIsValid = end.isValid; 4182 } catch (e) { 4183 endIsValid = false; 4184 } 4185 4186 if (startIsValid && endIsValid) { 4187 return Interval.fromDateTimes(start, end); 4188 } 4189 4190 if (startIsValid) { 4191 const dur = Duration.fromISO(e, opts); 4192 if (dur.isValid) { 4193 return Interval.after(start, dur); 4194 } 4195 } else if (endIsValid) { 4196 const dur = Duration.fromISO(s, opts); 4197 if (dur.isValid) { 4198 return Interval.before(end, dur); 4199 } 4200 } 4201 } 4202 return Interval.invalid("unparsable", `the input "${text}" can't be parsed as ISO 8601`); 4203 } 4204 4205 /** 4206 * Check if an object is an Interval. Works across context boundaries 4207 * @param {object} o 4208 * @return {boolean} 4209 */ 4210 static isInterval(o) { 4211 return (o && o.isLuxonInterval) || false; 4212 } 4213 4214 /** 4215 * Returns the start of the Interval 4216 * @type {DateTime} 4217 */ 4218 get start() { 4219 return this.isValid ? this.s : null; 4220 } 4221 4222 /** 4223 * Returns the end of the Interval 4224 * @type {DateTime} 4225 */ 4226 get end() { 4227 return this.isValid ? this.e : null; 4228 } 4229 4230 /** 4231 * Returns whether this Interval's end is at least its start, meaning that the Interval isn't 'backwards'. 4232 * @type {boolean} 4233 */ 4234 get isValid() { 4235 return this.invalidReason === null; 4236 } 4237 4238 /** 4239 * Returns an error code if this Interval is invalid, or null if the Interval is valid 4240 * @type {string} 4241 */ 4242 get invalidReason() { 4243 return this.invalid ? this.invalid.reason : null; 4244 } 4245 4246 /** 4247 * Returns an explanation of why this Interval became invalid, or null if the Interval is valid 4248 * @type {string} 4249 */ 4250 get invalidExplanation() { 4251 return this.invalid ? this.invalid.explanation : null; 4252 } 4253 4254 /** 4255 * Returns the length of the Interval in the specified unit. 4256 * @param {string} unit - the unit (such as 'hours' or 'days') to return the length in. 4257 * @return {number} 4258 */ 4259 length(unit = "milliseconds") { 4260 return this.isValid ? this.toDuration(...[unit]).get(unit) : NaN; 4261 } 4262 4263 /** 4264 * Returns the count of minutes, hours, days, months, or years included in the Interval, even in part. 4265 * Unlike {@link Interval#length} this counts sections of the calendar, not periods of time, e.g. specifying 'day' 4266 * asks 'what dates are included in this interval?', not 'how many days long is this interval?' 4267 * @param {string} [unit='milliseconds'] - the unit of time to count. 4268 * @param {Object} opts - options 4269 * @param {boolean} [opts.useLocaleWeeks=false] - If true, use weeks based on the locale, i.e. use the locale-dependent start of the week; this operation will always use the locale of the start DateTime 4270 * @return {number} 4271 */ 4272 count(unit = "milliseconds", opts) { 4273 if (!this.isValid) return NaN; 4274 const start = this.start.startOf(unit, opts); 4275 let end; 4276 if (opts?.useLocaleWeeks) { 4277 end = this.end.reconfigure({ locale: start.locale }); 4278 } else { 4279 end = this.end; 4280 } 4281 end = end.startOf(unit, opts); 4282 return Math.floor(end.diff(start, unit).get(unit)) + (end.valueOf() !== this.end.valueOf()); 4283 } 4284 4285 /** 4286 * Returns whether this Interval's start and end are both in the same unit of time 4287 * @param {string} unit - the unit of time to check sameness on 4288 * @return {boolean} 4289 */ 4290 hasSame(unit) { 4291 return this.isValid ? this.isEmpty() || this.e.minus(1).hasSame(this.s, unit) : false; 4292 } 4293 4294 /** 4295 * Return whether this Interval has the same start and end DateTimes. 4296 * @return {boolean} 4297 */ 4298 isEmpty() { 4299 return this.s.valueOf() === this.e.valueOf(); 4300 } 4301 4302 /** 4303 * Return whether this Interval's start is after the specified DateTime. 4304 * @param {DateTime} dateTime 4305 * @return {boolean} 4306 */ 4307 isAfter(dateTime) { 4308 if (!this.isValid) return false; 4309 return this.s > dateTime; 4310 } 4311 4312 /** 4313 * Return whether this Interval's end is before the specified DateTime. 4314 * @param {DateTime} dateTime 4315 * @return {boolean} 4316 */ 4317 isBefore(dateTime) { 4318 if (!this.isValid) return false; 4319 return this.e <= dateTime; 4320 } 4321 4322 /** 4323 * Return whether this Interval contains the specified DateTime. 4324 * @param {DateTime} dateTime 4325 * @return {boolean} 4326 */ 4327 contains(dateTime) { 4328 if (!this.isValid) return false; 4329 return this.s <= dateTime && this.e > dateTime; 4330 } 4331 4332 /** 4333 * "Sets" the start and/or end dates. Returns a newly-constructed Interval. 4334 * @param {Object} values - the values to set 4335 * @param {DateTime} values.start - the starting DateTime 4336 * @param {DateTime} values.end - the ending DateTime 4337 * @return {Interval} 4338 */ 4339 set({ start, end } = {}) { 4340 if (!this.isValid) return this; 4341 return Interval.fromDateTimes(start || this.s, end || this.e); 4342 } 4343 4344 /** 4345 * Split this Interval at each of the specified DateTimes 4346 * @param {...DateTime} dateTimes - the unit of time to count. 4347 * @return {Array} 4348 */ 4349 splitAt(...dateTimes) { 4350 if (!this.isValid) return []; 4351 const sorted = dateTimes 4352 .map(friendlyDateTime) 4353 .filter((d) => this.contains(d)) 4354 .sort((a, b) => a.toMillis() - b.toMillis()), 4355 results = []; 4356 let { s } = this, 4357 i = 0; 4358 4359 while (s < this.e) { 4360 const added = sorted[i] || this.e, 4361 next = +added > +this.e ? this.e : added; 4362 results.push(Interval.fromDateTimes(s, next)); 4363 s = next; 4364 i += 1; 4365 } 4366 4367 return results; 4368 } 4369 4370 /** 4371 * Split this Interval into smaller Intervals, each of the specified length. 4372 * Left over time is grouped into a smaller interval 4373 * @param {Duration|Object|number} duration - The length of each resulting interval. 4374 * @return {Array} 4375 */ 4376 splitBy(duration) { 4377 const dur = Duration.fromDurationLike(duration); 4378 4379 if (!this.isValid || !dur.isValid || dur.as("milliseconds") === 0) { 4380 return []; 4381 } 4382 4383 let { s } = this, 4384 idx = 1, 4385 next; 4386 4387 const results = []; 4388 while (s < this.e) { 4389 const added = this.start.plus(dur.mapUnits((x) => x * idx)); 4390 next = +added > +this.e ? this.e : added; 4391 results.push(Interval.fromDateTimes(s, next)); 4392 s = next; 4393 idx += 1; 4394 } 4395 4396 return results; 4397 } 4398 4399 /** 4400 * Split this Interval into the specified number of smaller intervals. 4401 * @param {number} numberOfParts - The number of Intervals to divide the Interval into. 4402 * @return {Array} 4403 */ 4404 divideEqually(numberOfParts) { 4405 if (!this.isValid) return []; 4406 return this.splitBy(this.length() / numberOfParts).slice(0, numberOfParts); 4407 } 4408 4409 /** 4410 * Return whether this Interval overlaps with the specified Interval 4411 * @param {Interval} other 4412 * @return {boolean} 4413 */ 4414 overlaps(other) { 4415 return this.e > other.s && this.s < other.e; 4416 } 4417 4418 /** 4419 * Return whether this Interval's end is adjacent to the specified Interval's start. 4420 * @param {Interval} other 4421 * @return {boolean} 4422 */ 4423 abutsStart(other) { 4424 if (!this.isValid) return false; 4425 return +this.e === +other.s; 4426 } 4427 4428 /** 4429 * Return whether this Interval's start is adjacent to the specified Interval's end. 4430 * @param {Interval} other 4431 * @return {boolean} 4432 */ 4433 abutsEnd(other) { 4434 if (!this.isValid) return false; 4435 return +other.e === +this.s; 4436 } 4437 4438 /** 4439 * Return
4439s true if this Interval fully contains the specified Interval, specifically if the intersect (of this Interval and the other Interval) is equal to the other Interval; false otherwise
vendor: 18,333 bytes, lines 4439-4888
4439. 4440 * @param {Interval} other 4441 * @return {boolean} 4442 */ 4443 engulfs(other) { 4444 if (!this.isValid) return false; 4445 return this.s <= other.s && this.e >= other.e; 4446 } 4447 4448 /** 4449 * Return whether this Interval has the same start and end as the specified Interval. 4450 * @param {Interval} other 4451 * @return {boolean} 4452 */ 4453 equals(other) { 4454 if (!this.isValid || !other.isValid) { 4455 return false; 4456 } 4457 4458 return this.s.equals(other.s) && this.e.equals(other.e); 4459 } 4460 4461 /** 4462 * Return an Interval representing the intersection of this Interval and the specified Interval. 4463 * Specifically, the resulting Interval has the maximum start time and the minimum end time of the two Intervals. 4464 * Returns null if the intersection is empty, meaning, the intervals don't intersect. 4465 * @param {Interval} other 4466 * @return {Interval} 4467 */ 4468 intersection(other) { 4469 if (!this.isValid) return this; 4470 const s = this.s > other.s ? this.s : other.s, 4471 e = this.e < other.e ? this.e : other.e; 4472 4473 if (s >= e) { 4474 return null; 4475 } else { 4476 return Interval.fromDateTimes(s, e); 4477 } 4478 } 4479 4480 /** 4481 * Return an Interval representing the union of this Interval and the specified Interval. 4482 * Specifically, the resulting Interval has the minimum start time and the maximum end time of the two Intervals. 4483 * @param {Interval} other 4484 * @return {Interval} 4485 */ 4486 union(other) { 4487 if (!this.isValid) return this; 4488 const s = this.s < other.s ? this.s : other.s, 4489 e = this.e > other.e ? this.e : other.e; 4490 return Interval.fromDateTimes(s, e); 4491 } 4492 4493 /** 4494 * Merge an array of Intervals into a equivalent minimal set of Intervals. 4495 * Combines overlapping and adjacent Intervals. 4496 * @param {Array} intervals 4497 * @return {Array} 4498 */ 4499 static merge(intervals) { 4500 const [found, final] = intervals 4501 .sort((a, b) => a.s - b.s) 4502 .reduce( 4503 ([sofar, current], item) => { 4504 if (!current) { 4505 return [sofar, item]; 4506 } else if (current.overlaps(item) || current.abutsStart(item)) { 4507 return [sofar, current.union(item)]; 4508 } else { 4509 return [sofar.concat([current]), item]; 4510 } 4511 }, 4512 [[], null] 4513 ); 4514 if (final) { 4515 found.push(final); 4516 } 4517 return found; 4518 } 4519 4520 /** 4521 * Return an array of Intervals representing the spans of time that only appear in one of the specified Intervals. 4522 * @param {Array} intervals 4523 * @return {Array} 4524 */ 4525 static xor(intervals) { 4526 let start = null, 4527 currentCount = 0; 4528 const results = [], 4529 ends = intervals.map((i) => [ 4530 { time: i.s, type: "s" }, 4531 { time: i.e, type: "e" }, 4532 ]), 4533 flattened = Array.prototype.concat(...ends), 4534 arr = flattened.sort((a, b) => a.time - b.time); 4535 4536 for (const i of arr) { 4537 currentCount += i.type === "s" ? 1 : -1; 4538 4539 if (currentCount === 1) { 4540 start = i.time; 4541 } else { 4542 if (start && +start !== +i.time) { 4543 results.push(Interval.fromDateTimes(start, i.time)); 4544 } 4545 4546 start = null; 4547 } 4548 } 4549 4550 return Interval.merge(results); 4551 } 4552 4553 /** 4554 * Return an Interval representing the span of time in this Interval that doesn't overlap with any of the specified Intervals. 4555 * @param {...Interval} intervals 4556 * @return {Array} 4557 */ 4558 difference(...intervals) { 4559 return Interval.xor([this].concat(intervals)) 4560 .map((i) => this.intersection(i)) 4561 .filter((i) => i && !i.isEmpty()); 4562 } 4563 4564 /** 4565 * Returns a string representation of this Interval appropriate for debugging. 4566 * @return {string} 4567 */ 4568 toString() { 4569 if (!this.isValid) return INVALID$1; 4570 return `[${this.s.toISO()} â ${this.e.toISO()})`; 4571 } 4572 4573 /** 4574 * Returns a string representation of this Interval appropriate for the REPL. 4575 * @return {string} 4576 */ 4577 [Symbol.for("nodejs.util.inspect.custom")]() { 4578 if (this.isValid) { 4579 return `Interval { start: ${this.s.toISO()}, end: ${this.e.toISO()} }`; 4580 } else { 4581 return `Interval { Invalid, reason: ${this.invalidReason} }`; 4582 } 4583 } 4584 4585 /** 4586 * Returns a localized string representing this Interval. Accepts the same options as the 4587 * Intl.DateTimeFormat constructor and any presets defined by Luxon, such as 4588 * {@link DateTime.DATE_FULL} or {@link DateTime.TIME_SIMPLE}. The exact behavior of this method 4589 * is browser-specific, but in general it will return an appropriate representation of the 4590 * Interval in the assigned locale. Defaults to the system's locale if no locale has been 4591 * specified. 4592 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat 4593 * @param {Object} [formatOpts=DateTime.DATE_SHORT] - Either a DateTime preset or 4594 * Intl.DateTimeFormat constructor options. 4595 * @param {Object} opts - Options to override the configuration of the start DateTime. 4596 * @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(); //=> 11/7/2022 â 11/8/2022 4597 * @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(DateTime.DATE_FULL); //=> November 7 â 8, 2022 4598 * @example Interval.fromISO('2022-11-07T09:00Z/2022-11-08T09:00Z').toLocaleString(DateTime.DATE_FULL, { locale: 'fr-FR' }); //=> 7â8 novembre 2022 4599 * @example Interval.fromISO('2022-11-07T17:00Z/2022-11-07T19:00Z').toLocaleString(DateTime.TIME_SIMPLE); //=> 6:00 â 8:00 PM 4600 * @example Interval.fromISO('2022-11-07T17:00Z/2022-11-07T19:00Z').toLocaleString({ weekday: 'short', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }); //=> Mon, Nov 07, 6:00 â 8:00 p 4601 * @return {string} 4602 */ 4603 toLocaleString(formatOpts = DATE_SHORT, opts = {}) { 4604 return this.isValid 4605 ? Formatter.create(this.s.loc.clone(opts), formatOpts).formatInterval(this) 4606 : INVALID$1; 4607 } 4608 4609 /** 4610 * Returns an ISO 8601-compliant string representation of this Interval. 4611 * @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals 4612 * @param {Object} opts - The same options as {@link DateTime#toISO} 4613 * @return {string} 4614 */ 4615 toISO(opts) { 4616 if (!this.isValid) return INVALID$1; 4617 return `${this.s.toISO(opts)}/${this.e.toISO(opts)}`; 4618 } 4619 4620 /** 4621 * Returns an ISO 8601-compliant string representation of date of this Interval. 4622 * The time components are ignored. 4623 * @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals 4624 * @return {string} 4625 */ 4626 toISODate() { 4627 if (!this.isValid) return INVALID$1; 4628 return `${this.s.toISODate()}/${this.e.toISODate()}`; 4629 } 4630 4631 /** 4632 * Returns an ISO 8601-compliant string representation of time of this Interval. 4633 * The date components are ignored. 4634 * @see https://en.wikipedia.org/wiki/ISO_8601#Time_intervals 4635 * @param {Object} opts - The same options as {@link DateTime#toISO} 4636 * @return {string} 4637 */ 4638 toISOTime(opts) { 4639 if (!this.isValid) return INVALID$1; 4640 return `${this.s.toISOTime(opts)}/${this.e.toISOTime(opts)}`; 4641 } 4642 4643 /** 4644 * Returns a string representation of this Interval formatted according to the specified format 4645 * string. **You may not want this.** See {@link Interval#toLocaleString} for a more flexible 4646 * formatting tool. 4647 * @param {string} dateFormat - The format string. This string formats the start and end time. 4648 * See {@link DateTime#toFormat} for details. 4649 * @param {Object} opts - Options. 4650 * @param {string} [opts.separator = ' â '] - A separator to place between the start and end 4651 * representations. 4652 * @return {string} 4653 */ 4654 toFormat(dateFormat, { separator = " â " } = {}) { 4655 if (!this.isValid) return INVALID$1; 4656 return `${this.s.toFormat(dateFormat)}${separator}${this.e.toFormat(dateFormat)}`; 4657 } 4658 4659 /** 4660 * Return a Duration representing the time spanned by this interval. 4661 * @param {string|string[]} [unit=['milliseconds']] - the unit or units (such as 'hours' or 'days') to include in the duration. 4662 * @param {Object} opts - options that affect the creation of the Duration 4663 * @param {string} [opts.conversionAccuracy='casual'] - the conversion system to use 4664 * @example Interval.fromDateTimes(dt1, dt2).toDuration().toObject() //=> { milliseconds: 88489257 } 4665 * @example Interval.fromDateTimes(dt1, dt2).toDuration('days').toObject() //=> { days: 1.0241812152777778 } 4666 * @example Interval.fromDateTimes(dt1, dt2).toDuration(['hours', 'minutes']).toObject() //=> { hours: 24, minutes: 34.82095 } 4667 * @example Interval.fromDateTimes(dt1, dt2).toDuration(['hours', 'minutes', 'seconds']).toObject() //=> { hours: 24, minutes: 34, seconds: 49.257 } 4668 * @example Interval.fromDateTimes(dt1, dt2).toDuration('seconds').toObject() //=> { seconds: 88489.257 } 4669 * @return {Duration} 4670 */ 4671 toDuration(unit, opts) { 4672 if (!this.isValid) { 4673 return Duration.invalid(this.invalidReason); 4674 } 4675 return this.e.diff(this.s, unit, opts); 4676 } 4677 4678 /** 4679 * Run mapFn on the interval start and end, returning a new Interval from the resulting DateTimes 4680 * @param {function} mapFn 4681 * @return {Interval} 4682 * @example Interval.fromDateTimes(dt1, dt2).mapEndpoints(endpoint => endpoint.toUTC()) 4683 * @example Interval.fromDateTimes(dt1, dt2).mapEndpoints(endpoint => endpoint.plus({ hours: 2 })) 4684 */ 4685 mapEndpoints(mapFn) { 4686 return Interval.fromDateTimes(mapFn(this.s), mapFn(this.e)); 4687 } 4688} 4689 4690/** 4691 * The Info class contains static methods for retrieving general time and date related data. For example, it has methods for finding out if a time zone has a DST, for listing the months in any supported locale, and for discovering which of Luxon features are available in the current environment. 4692 */ 4693class Info { 4694 /** 4695 * Return whether the specified zone contains a DST. 4696 * @param {string|Zone} [zone='local'] - Zone to check. Defaults to the environment's local zone. 4697 * @return {boolean} 4698 */ 4699 static hasDST(zone = Settings.defaultZone) { 4700 const proto = DateTime.now().setZone(zone).set({ month: 12 }); 4701 4702 return !zone.isUniversal && proto.offset !== proto.set({ month: 6 }).offset; 4703 } 4704 4705 /** 4706 * Return whether the specified zone is a valid IANA specifier. 4707 * @param {string} zone - Zone to check 4708 * @return {boolean} 4709 */ 4710 static isValidIANAZone(zone) { 4711 return IANAZone.isValidZone(zone); 4712 } 4713 4714 /** 4715 * Converts the input into a {@link Zone} instance. 4716 * 4717 * * If `input` is already a Zone instance, it is returned unchanged. 4718 * * If `input` is a string containing a valid time zone name, a Zone instance 4719 * with that name is returned. 4720 * * If `input` is a string that doesn't refer to a known time zone, a Zone 4721 * instance with {@link Zone#isValid} == false is returned. 4722 * * If `input is a number, a Zone instance with the specified fixed offset 4723 * in minutes is returned. 4724 * * If `input` is `null` or `undefined`, the default zone is returned. 4725 * @param {string|Zone|number} [input] - the value to be converted 4726 * @return {Zone} 4727 */ 4728 static normalizeZone(input) { 4729 return normalizeZone(input, Settings.defaultZone); 4730 } 4731 4732 /** 4733 * Get the weekday on which the week starts according to the given locale. 4734 * @param {Object} opts - options 4735 * @param {string} [opts.locale] - the locale code 4736 * @param {string} [opts.locObj=null] - an existing locale object to use 4737 * @returns {number} the start of the week, 1 for Monday through 7 for Sunday 4738 */ 4739 static getStartOfWeek({ locale = null, locObj = null } = {}) { 4740 return (locObj || Locale.create(locale)).getStartOfWeek(); 4741 } 4742 4743 /** 4744 * Get the minimum number of days necessary in a week before it is considered part of the next year according 4745 * to the given locale. 4746 * @param {Object} opts - options 4747 * @param {string} [opts.locale] - the locale code 4748 * @param {string} [opts.locObj=null] - an existing locale object to use 4749 * @returns {number} 4750 */ 4751 static getMinimumDaysInFirstWeek({ locale = null, locObj = null } = {}) { 4752 return (locObj || Locale.create(locale)).getMinDaysInFirstWeek(); 4753 } 4754 4755 /** 4756 * Get the weekdays, which are considered the weekend according to the given locale 4757 * @param {Object} opts - options 4758 * @param {string} [opts.locale] - the locale code 4759 * @param {string} [opts.locObj=null] - an existing locale object to use 4760 * @returns {number[]} an array of weekdays, 1 for Monday through 7 for Sunday 4761 */ 4762 static getWeekendWeekdays({ locale = null, locObj = null } = {}) { 4763 // copy the array, because we cache it internally 4764 return (locObj || Locale.create(locale)).getWeekendDays().slice(); 4765 } 4766 4767 /** 4768 * Return an array of standalone month names. 4769 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat 4770 * @param {string} [length='long'] - the length of the month representation, such as "numeric", "2-digit", "narrow", "short", "long" 4771 * @param {Object} opts - options 4772 * @param {string} [opts.locale] - the locale code 4773 * @param {string} [opts.numberingSystem=null] - the numbering system 4774 * @param {string} [opts.locObj=null] - an existing locale object to use 4775 * @param {string} [opts.outputCalendar='gregory'] - the calendar 4776 * @example Info.months()[0] //=> 'January' 4777 * @example Info.months('short')[0] //=> 'Jan' 4778 * @example Info.months('numeric')[0] //=> '1' 4779 * @example Info.months('short', { locale: 'fr-CA' } )[0] //=> 'janv.' 4780 * @example Info.months('numeric', { locale: 'ar' })[0] //=> 'Ù¡' 4781 * @example Info.months('long', { outputCalendar: 'islamic' })[0] //=> 'RabiÊ» I' 4782 * @return {Array} 4783 */ 4784 static months( 4785 length = "long", 4786 { locale = null, numberingSystem = null, locObj = null, outputCalendar = "gregory" } = {} 4787 ) { 4788 return (locObj || Locale.create(locale, numberingSystem, outputCalendar)).months(length); 4789 } 4790 4791 /** 4792 * Return an array of format month names. 4793 * Format months differ from standalone months in that they're meant to appear next to the day of the month. In some languages, that 4794 * changes the string. 4795 * See {@link Info#months} 4796 * @param {string} [length='long'] - the length of the month representation, such as "numeric", "2-digit", "narrow", "short", "long" 4797 * @param {Object} opts - options 4798 * @param {string} [opts.locale] - the locale code 4799 * @param {string} [opts.numberingSystem=null] - the numbering system 4800 * @param {string} [opts.locObj=null] - an existing locale object to use 4801 * @param {string} [opts.outputCalendar='gregory'] - the calendar 4802 * @return {Array} 4803 */ 4804 static monthsFormat( 4805 length = "long", 4806 { locale = null, numberingSystem = null, locObj = null, outputCalendar = "gregory" } = {} 4807 ) { 4808 return (locObj || Locale.create(locale, numberingSystem, outputCalendar)).months(length, true); 4809 } 4810 4811 /** 4812 * Return an array of standalone week names. 4813 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat 4814 * @param {string} [length='long'] - the length of the weekday representation, such as "narrow", "short", "long". 4815 * @param {Object} opts - options 4816 * @param {string} [opts.locale] - the locale code 4817 * @param {string} [opts.numberingSystem=null] - the numbering system 4818 * @param {string} [opts.locObj=null] - an existing locale object to use 4819 * @example Info.weekdays()[0] //=> 'Monday' 4820 * @example Info.weekdays('short')[0] //=> 'Mon' 4821 * @example Info.weekdays('short', { locale: 'fr-CA' })[0] //=> 'lun.' 4822 * @example Info.weekdays('short', { locale: 'ar' })[0] //=> 'Ø§ÙØ§Ø«ÙÙÙ' 4823 * @return {Array} 4824 */ 4825 static weekdays(length = "long", { locale = null, numberingSystem = null, locObj = null } = {}) { 4826 return (locObj || Locale.create(locale, numberingSystem, null)).weekdays(length); 4827 } 4828 4829 /** 4830 * Return an array of format week names. 4831 * Format weekdays differ from standalone weekdays in that they're meant to appear next to more date information. In some languages, that 4832 * changes the string. 4833 * See {@link Info#weekdays} 4834 * @param {string} [length='long'] - the length of the month representation, such as "narrow", "short", "long". 4835 * @param {Object} opts - options 4836 * @param {string} [opts.locale=null] - the locale code 4837 * @param {string} [opts.numberingSystem=null] - the numbering system 4838 * @param {string} [opts.locObj=null] - an existing locale object to use 4839 * @return {Array} 4840 */ 4841 static weekdaysFormat( 4842 length = "long", 4843 { locale = null, numberingSystem = null, locObj = null } = {} 4844 ) { 4845 return (locObj || Locale.create(locale, numberingSystem, null)).weekdays(length, true); 4846 } 4847 4848 /** 4849 * Return an array of meridiems. 4850 * @param {Object} opts - options 4851 * @param {string} [opts.locale] - the locale code 4852 * @example Info.meridiems() //=> [ 'AM', 'PM' ] 4853 * @example Info.meridiems({ locale: 'my' }) //=> [ 'áá¶áááº', 'ááá±' ] 4854 * @return {Array} 4855 */ 4856 static meridiems({ locale = null } = {}) { 4857 return Locale.create(locale).meridiems(); 4858 } 4859 4860 /** 4861 * Return an array of eras, such as ['BC', 'AD']. The locale can be specified, but the calendar system is always Gregorian. 4862 * @param {string} [length='short'] - the length of the era representation, such as "short" or "long". 4863 * @param {Object} opts - options 4864 * @param {string} [opts.locale] - the locale code 4865 * @example Info.eras() //=> [ 'BC', 'AD' ] 4866 * @example Info.eras('long') //=> [ 'Before Christ', 'Anno Domini' ] 4867 * @example Info.eras('long', { locale: 'fr' }) //=> [ 'avant Jésus-Christ', 'après Jésus-Christ' ] 4868 * @return {Array} 4869 */ 4870 static eras(length = "short", { locale = null } = {}) { 4871 return Locale.create(locale, null, "gregory").eras(length); 4872 } 4873 4874 /** 4875 * Return the set of available features in this environment. 4876 * Some features of Luxon are not available in all environments. For example, on older browsers, relative time formatting support is not available. Use this function to figure out if that's the case. 4877 * Keys: 4878 * * `relative`: whether this environment supports relative time formatting 4879 * * `localeWeek`: whether this environment supports different weekdays for the start of the week based on the locale 4880 * @example Info.features() //=> { relative: false, localeWeek: true } 4881 * @return {Object} 4882 */ 4883 static features() { 4884 return { relative: hasRelative(), localeWeek: hasLocaleWeekInfo() }; 4885 } 4886} 4887 4888function dayDiff(earlier, later) {
vendor: 16,499 bytes, lines 4889-5520
4889 const utcDayStart = (dt) => dt.toUTC(0, { keepLocalTime: true }).startOf("day").valueOf(), 4890 ms = utcDayStart(later) - utcDayStart(earlier); 4891 return Math.floor(Duration.fromMillis(ms).as("days")); 4892} 4893 4894function highOrderDiffs(cursor, later, units) { 4895 const differs = [ 4896 ["years", (a, b) => b.year - a.year], 4897 ["quarters", (a, b) => b.quarter - a.quarter + (b.year - a.year) * 4], 4898 ["months", (a, b) => b.month - a.month + (b.year - a.year) * 12], 4899 [ 4900 "weeks", 4901 (a, b) => { 4902 const days = dayDiff(a, b); 4903 return (days - (days % 7)) / 7; 4904 }, 4905 ], 4906 ["days", dayDiff], 4907 ]; 4908 4909 const results = {}; 4910 const earlier = cursor; 4911 let lowestOrder, highWater; 4912 4913 /* This loop tries to diff using larger units first. 4914 If we overshoot, we backtrack and try the next smaller unit. 4915 "cursor" starts out at the earlier timestamp and moves closer and closer to "later" 4916 as we use smaller and smaller units. 4917 highWater keeps track of where we would be if we added one more of the smallest unit, 4918 this is used later to potentially convert any difference smaller than the smallest higher order unit 4919 into a fraction of that smallest higher order unit 4920 */ 4921 for (const [unit, differ] of differs) { 4922 if (units.indexOf(unit) >= 0) { 4923 lowestOrder = unit; 4924 4925 results[unit] = differ(cursor, later); 4926 highWater = earlier.plus(results); 4927 4928 if (highWater > later) { 4929 // we overshot the end point, backtrack cursor by 1 4930 results[unit]--; 4931 cursor = earlier.plus(results); 4932 4933 // if we are still overshooting now, we need to backtrack again 4934 // this happens in certain situations when diffing times in different zones, 4935 // because this calculation ignores time zones 4936 if (cursor > later) { 4937 // keep the "overshot by 1" around as highWater 4938 highWater = cursor; 4939 // backtrack cursor by 1 4940 results[unit]--; 4941 cursor = earlier.plus(results); 4942 } 4943 } else { 4944 cursor = highWater; 4945 } 4946 } 4947 } 4948 4949 return [cursor, results, highWater, lowestOrder]; 4950} 4951 4952function diff (earlier, later, units, opts) { 4953 let [cursor, results, highWater, lowestOrder] = highOrderDiffs(earlier, later, units); 4954 4955 const remainingMillis = later - cursor; 4956 4957 const lowerOrderUnits = units.filter( 4958 (u) => ["hours", "minutes", "seconds", "milliseconds"].indexOf(u) >= 0 4959 ); 4960 4961 if (lowerOrderUnits.length === 0) { 4962 if (highWater < later) { 4963 highWater = cursor.plus({ [lowestOrder]: 1 }); 4964 } 4965 4966 if (highWater !== cursor) { 4967 results[lowestOrder] = (results[lowestOrder] || 0) + remainingMillis / (highWater - cursor); 4968 } 4969 } 4970 4971 const duration = Duration.fromObject(results, opts); 4972 4973 if (lowerOrderUnits.length > 0) { 4974 return Duration.fromMillis(remainingMillis, opts) 4975 .shiftTo(...lowerOrderUnits) 4976 .plus(duration); 4977 } else { 4978 return duration; 4979 } 4980} 4981 4982const MISSING_FTP = "missing Intl.DateTimeFormat.formatToParts support"; 4983 4984function intUnit(regex, post = (i) => i) { 4985 return { regex, deser: ([s]) => post(parseDigits(s)) }; 4986} 4987 4988const NBSP = String.fromCharCode(160); 4989const spaceOrNBSP = `[ ${NBSP}]`; 4990const spaceOrNBSPRegExp = new RegExp(spaceOrNBSP, "g"); 4991 4992function fixListRegex(s) { 4993 // make dots optional and also make them literal 4994 // make space and non breakable space characters interchangeable 4995 return s.replace(/\./g, "\\.?").replace(spaceOrNBSPRegExp, spaceOrNBSP); 4996} 4997 4998function stripInsensitivities(s) { 4999 return s 5000 .replace(/\./g, "") // ignore dots that were made optional 5001 .replace(spaceOrNBSPRegExp, " ") // interchange space and nbsp 5002 .toLowerCase(); 5003} 5004 5005function oneOf(strings, startIndex) { 5006 if (strings === null) { 5007 return null; 5008 } else { 5009 return { 5010 regex: RegExp(strings.map(fixListRegex).join("|")), 5011 deser: ([s]) => 5012 strings.findIndex((i) => stripInsensitivities(s) === stripInsensitivities(i)) + startIndex, 5013 }; 5014 } 5015} 5016 5017function offset(regex, groups) { 5018 return { regex, deser: ([, h, m]) => signedOffset(h, m), groups }; 5019} 5020 5021function simple(regex) { 5022 return { regex, deser: ([s]) => s }; 5023} 5024 5025function escapeToken(value) { 5026 return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); 5027} 5028 5029/** 5030 * @param token 5031 * @param {Locale} loc 5032 */ 5033function unitForToken(token, loc) { 5034 const one = digitRegex(loc), 5035 two = digitRegex(loc, "{2}"), 5036 three = digitRegex(loc, "{3}"), 5037 four = digitRegex(loc, "{4}"), 5038 six = digitRegex(loc, "{6}"), 5039 oneOrTwo = digitRegex(loc, "{1,2}"), 5040 oneToThree = digitRegex(loc, "{1,3}"), 5041 oneToSix = digitRegex(loc, "{1,6}"), 5042 oneToNine = digitRegex(loc, "{1,9}"), 5043 twoToFour = digitRegex(loc, "{2,4}"), 5044 fourToSix = digitRegex(loc, "{4,6}"), 5045 literal = (t) => ({ regex: RegExp(escapeToken(t.val)), deser: ([s]) => s, literal: true }), 5046 unitate = (t) => { 5047 if (token.literal) { 5048 return literal(t); 5049 } 5050 switch (t.val) { 5051 // era 5052 case "G": 5053 return oneOf(loc.eras("short"), 0); 5054 case "GG": 5055 return oneOf(loc.eras("long"), 0); 5056 // years 5057 case "y": 5058 return intUnit(oneToSix); 5059 case "yy": 5060 return intUnit(twoToFour, untruncateYear); 5061 case "yyyy": 5062 return intUnit(four); 5063 case "yyyyy": 5064 return intUnit(fourToSix); 5065 case "yyyyyy": 5066 return intUnit(six); 5067 // months 5068 case "M": 5069 return intUnit(oneOrTwo); 5070 case "MM": 5071 return intUnit(two); 5072 case "MMM": 5073 return oneOf(loc.months("short", true), 1); 5074 case "MMMM": 5075 return oneOf(loc.months("long", true), 1); 5076 case "L": 5077 return intUnit(oneOrTwo); 5078 case "LL": 5079 return intUnit(two); 5080 case "LLL": 5081 return oneOf(loc.months("short", false), 1); 5082 case "LLLL": 5083 return oneOf(loc.months("long", false), 1); 5084 // dates 5085 case "d": 5086 return intUnit(oneOrTwo); 5087 case "dd": 5088 return intUnit(two); 5089 // ordinals 5090 case "o": 5091 return intUnit(oneToThree); 5092 case "ooo": 5093 return intUnit(three); 5094 // time 5095 case "HH": 5096 return intUnit(two); 5097 case "H": 5098 return intUnit(oneOrTwo); 5099 case "hh": 5100 return intUnit(two); 5101 case "h": 5102 return intUnit(oneOrTwo); 5103 case "mm": 5104 return intUnit(two); 5105 case "m": 5106 return intUnit(oneOrTwo); 5107 case "q": 5108 return intUnit(oneOrTwo); 5109 case "qq": 5110 return intUnit(two); 5111 case "s": 5112 return intUnit(oneOrTwo); 5113 case "ss": 5114 return intUnit(two); 5115 case "S": 5116 return intUnit(oneToThree); 5117 case "SSS": 5118 return intUnit(three); 5119 case "u": 5120 return simple(oneToNine); 5121 case "uu": 5122 return simple(oneOrTwo); 5123 case "uuu": 5124 return intUnit(one); 5125 // meridiem 5126 case "a": 5127 return oneOf(loc.meridiems(), 0); 5128 // weekYear (k) 5129 case "kkkk": 5130 return intUnit(four); 5131 case "kk": 5132 return intUnit(twoToFour, untruncateYear); 5133 // weekNumber (W) 5134 case "W": 5135 return intUnit(oneOrTwo); 5136 case "WW": 5137 return intUnit(two); 5138 // weekdays 5139 case "E": 5140 case "c": 5141 return intUnit(one); 5142 case "EEE": 5143 return oneOf(loc.weekdays("short", false), 1); 5144 case "EEEE": 5145 return oneOf(loc.weekdays("long", false), 1); 5146 case "ccc": 5147 return oneOf(loc.weekdays("short", true), 1); 5148 case "cccc": 5149 return oneOf(loc.weekdays("long", true), 1); 5150 // offset/zone 5151 case "Z": 5152 case "ZZ": 5153 return offset(new RegExp(`([+-]${oneOrTwo.source})(?::(${two.source}))?`), 2); 5154 case "ZZZ": 5155 return offset(new RegExp(`([+-]${oneOrTwo.source})(${two.source})?`), 2); 5156 // we don't support ZZZZ (PST) or ZZZZZ (Pacific Standard Time) in parsing 5157 // because we don't have any way to figure out what they are 5158 case "z": 5159 return simple(/[a-z_+-/]{1,256}?/i); 5160 // this special-case "token" represents a place where a macro-token expanded into a white-space literal 5161 // in this case we accept any non-newline white-space 5162 case " ": 5163 return simple(/[^\S\n\r]/); 5164 default: 5165 return literal(t); 5166 } 5167 }; 5168 5169 const unit = unitate(token) || { 5170 invalidReason: MISSING_FTP, 5171 }; 5172 5173 unit.token = token; 5174 5175 return unit; 5176} 5177 5178const partTypeStyleToTokenVal = { 5179 year: { 5180 "2-digit": "yy", 5181 numeric: "yyyyy", 5182 }, 5183 month: { 5184 numeric: "M", 5185 "2-digit": "MM", 5186 short: "MMM", 5187 long: "MMMM", 5188 }, 5189 day: { 5190 numeric: "d", 5191 "2-digit": "dd", 5192 }, 5193 weekday: { 5194 short: "EEE", 5195 long: "EEEE", 5196 }, 5197 dayperiod: "a", 5198 dayPeriod: "a", 5199 hour12: { 5200 numeric: "h", 5201 "2-digit": "hh", 5202 }, 5203 hour24: { 5204 numeric: "H", 5205 "2-digit": "HH", 5206 }, 5207 minute: { 5208 numeric: "m", 5209 "2-digit": "mm", 5210 }, 5211 second: { 5212 numeric: "s", 5213 "2-digit": "ss", 5214 }, 5215 timeZoneName: { 5216 long: "ZZZZZ", 5217 short: "ZZZ", 5218 }, 5219}; 5220 5221function tokenForPart(part, formatOpts, resolvedOpts) { 5222 const { type, value } = part; 5223 5224 if (type === "literal") { 5225 const isSpace = /^\s+$/.test(value); 5226 return { 5227 literal: !isSpace, 5228 val: isSpace ? " " : value, 5229 }; 5230 } 5231 5232 const style = formatOpts[type]; 5233 5234 // The user might have explicitly specified hour12 or hourCycle 5235 // if so, respect their decision 5236 // if not, refer back to the resolvedOpts, which are based on the locale 5237 let actualType = type; 5238 if (type === "hour") { 5239 if (formatOpts.hour12 != null) { 5240 actualType = formatOpts.hour12 ? "hour12" : "hour24"; 5241 } else if (formatOpts.hourCycle != null) { 5242 if (formatOpts.hourCycle === "h11" || formatOpts.hourCycle === "h12") { 5243 actualType = "hour12"; 5244 } else { 5245 actualType = "hour24"; 5246 } 5247 } else { 5248 // tokens only differentiate between 24 hours or not, 5249 // so we do not need to check hourCycle here, which is less supported anyways 5250 actualType = resolvedOpts.hour12 ? "hour12" : "hour24"; 5251 } 5252 } 5253 let val = partTypeStyleToTokenVal[actualType]; 5254 if (typeof val === "object") { 5255 val = val[style]; 5256 } 5257 5258 if (val) { 5259 return { 5260 literal: false, 5261 val, 5262 }; 5263 } 5264 5265 return undefined; 5266} 5267 5268function buildRegex(units) { 5269 const re = units.map((u) => u.regex).reduce((f, r) => `${f}(${r.source})`, ""); 5270 return [`^${re}$`, units]; 5271} 5272 5273function match(input, regex, handlers) { 5274 const matches = input.match(regex); 5275 5276 if (matches) { 5277 const all = {}; 5278 let matchIndex = 1; 5279 for (const i in handlers) { 5280 if (hasOwnProperty(handlers, i)) { 5281 const h = handlers[i], 5282 groups = h.groups ? h.groups + 1 : 1; 5283 if (!h.literal && h.token) { 5284 all[h.token.val[0]] = h.deser(matches.slice(matchIndex, matchIndex + groups)); 5285 } 5286 matchIndex += groups; 5287 } 5288 } 5289 return [matches, all]; 5290 } else { 5291 return [matches, {}]; 5292 } 5293} 5294 5295function dateTimeFromMatches(matches) { 5296 const toField = (token) => { 5297 switch (token) { 5298 case "S": 5299 return "millisecond"; 5300 case "s": 5301 return "second"; 5302 case "m": 5303 return "minute"; 5304 case "h": 5305 case "H": 5306 return "hour"; 5307 case "d": 5308 return "day"; 5309 case "o": 5310 return "ordinal"; 5311 case "L": 5312 case "M": 5313 return "month"; 5314 case "y": 5315 return "year"; 5316 case "E": 5317 case "c": 5318 return "weekday"; 5319 case "W": 5320 return "weekNumber"; 5321 case "k": 5322 return "weekYear"; 5323 case "q": 5324 return "quarter"; 5325 default: 5326 return null; 5327 } 5328 }; 5329 5330 let zone = null; 5331 let specificOffset; 5332 if (!isUndefined(matches.z)) { 5333 zone = IANAZone.create(matches.z); 5334 } 5335 5336 if (!isUndefined(matches.Z)) { 5337 if (!zone) { 5338 zone = new FixedOffsetZone(matches.Z); 5339 } 5340 specificOffset = matches.Z; 5341 } 5342 5343 if (!isUndefined(matches.q)) { 5344 matches.M = (matches.q - 1) * 3 + 1; 5345 } 5346 5347 if (!isUndefined(matches.h)) { 5348 if (matches.h < 12 && matches.a === 1) { 5349 matches.h += 12; 5350 } else if (matches.h === 12 && matches.a === 0) { 5351 matches.h = 0; 5352 } 5353 } 5354 5355 if (matches.G === 0 && matches.y) { 5356 matches.y = -matches.y; 5357 } 5358 5359 if (!isUndefined(matches.u)) { 5360 matches.S = parseMillis(matches.u); 5361 } 5362 5363 const vals = Object.keys(matches).reduce((r, k) => { 5364 const f = toField(k); 5365 if (f) { 5366 r[f] = matches[k]; 5367 } 5368 5369 return r; 5370 }, {}); 5371 5372 return [vals, zone, specificOffset]; 5373} 5374 5375let dummyDateTimeCache = null; 5376 5377function getDummyDateTime() { 5378 if (!dummyDateTimeCache) { 5379 dummyDateTimeCache = DateTime.fromMillis(1555555555555); 5380 } 5381 5382 return dummyDateTimeCache; 5383} 5384 5385function maybeExpandMacroToken(token, locale) { 5386 if (token.literal) { 5387 return token; 5388 } 5389 5390 const formatOpts = Formatter.macroTokenToFormatOpts(token.val); 5391 const tokens = formatOptsToTokens(formatOpts, locale); 5392 5393 if (tokens == null || tokens.includes(undefined)) { 5394 return token; 5395 } 5396 5397 return tokens; 5398} 5399 5400function expandMacroTokens(tokens, locale) { 5401 return Array.prototype.concat(...tokens.map((t) => maybeExpandMacroToken(t, locale))); 5402} 5403 5404/** 5405 * @private 5406 */ 5407 5408class TokenParser { 5409 constructor(locale, format) { 5410 this.locale = locale; 5411 this.format = format; 5412 this.tokens = expandMacroTokens(Formatter.parseFormat(format), locale); 5413 this.units = this.tokens.map((t) => unitForToken(t, locale)); 5414 this.disqualifyingUnit = this.units.find((t) => t.invalidReason); 5415 5416 if (!this.disqualifyingUnit) { 5417 const [regexString, handlers] = buildRegex(this.units); 5418 this.regex = RegExp(regexString, "i"); 5419 this.handlers = handlers; 5420 } 5421 } 5422 5423 explainFromTokens(input) { 5424 if (!this.isValid) { 5425 return { input, tokens: this.tokens, invalidReason: this.invalidReason }; 5426 } else { 5427 const [rawMatches, matches] = match(input, this.regex, this.handlers), 5428 [result, zone, specificOffset] = matches 5429 ? dateTimeFromMatches(matches) 5430 : [null, null, undefined]; 5431 if (hasOwnProperty(matches, "a") && hasOwnProperty(matches, "H")) { 5432 throw new ConflictingSpecificationError( 5433 "Can't include meridiem when specifying 24-hour format" 5434 ); 5435 } 5436 return { 5437 input, 5438 tokens: this.tokens, 5439 regex: this.regex, 5440 rawMatches, 5441 matches, 5442 result, 5443 zone, 5444 specificOffset, 5445 }; 5446 } 5447 } 5448 5449 get isValid() { 5450 return !this.disqualifyingUnit; 5451 } 5452 5453 get invalidReason() { 5454 return this.disqualifyingUnit ? this.disqualifyingUnit.invalidReason : null; 5455 } 5456} 5457 5458function explainFromTokens(locale, input, format) { 5459 const parser = new TokenParser(locale, format); 5460 return parser.explainFromTokens(input); 5461} 5462 5463function parseFromTokens(locale, input, format) { 5464 const { result, zone, specificOffset, invalidReason } = explainFromTokens(locale, input, format); 5465 return [result, zone, specificOffset, invalidReason]; 5466} 5467 5468function formatOptsToTokens(formatOpts, locale) { 5469 if (!formatOpts) { 5470 return null; 5471 } 5472 5473 const formatter = Formatter.create(locale, formatOpts); 5474 const df = formatter.dtFormatter(getDummyDateTime()); 5475 const parts = df.formatToParts(); 5476 const resolvedOpts = df.resolvedOptions(); 5477 return parts.map((p) => tokenForPart(p, formatOpts, resolvedOpts)); 5478} 5479 5480const INVALID = "Invalid DateTime"; 5481const MAX_DATE = 8.64e15; 5482 5483function unsupportedZone(zone) { 5484 return new Invalid("unsupported zone", `the zone "${zone.name}" is not supported`); 5485} 5486 5487// we cache week data on the DT object and this intermediates the cache 5488/** 5489 * @param {DateTime} dt 5490 */ 5491function possiblyCachedWeekData(dt) { 5492 if (dt.weekData === null) { 5493 dt.weekData = gregorianToWeek(dt.c); 5494 } 5495 return dt.weekData; 5496} 5497 5498/** 5499 * @param {DateTime} dt 5500 */ 5501function possiblyCachedLocalWeekData(dt) { 5502 if (dt.localWeekData === null) { 5503 dt.localWeekData = gregorianToWeek( 5504 dt.c, 5505 dt.loc.getMinDaysInFirstWeek(), 5506 dt.loc.getStartOfWeek() 5507 ); 5508 } 5509 return dt.localWeekData; 5510} 5511 5512// clone really means, "make a new object with these modifications". all "setters" really use this 5513// to create a new object while only changing some of the properties 5514function clone(inst, alts) { 5515 const current = { 5516 ts: inst.ts, 5517 zone: inst.zone, 5518 c: inst.c, 5519 o: inst.o, 5520 loc: inst.loc,
vendor: 7,114 bytes, lines 5521-5799
5521 invalid: inst.invalid, 5522 }; 5523 return new DateTime({ ...current, ...alts, old: current }); 5524} 5525 5526// find the right offset a given local time. The o input is our guess, which determines which 5527// offset we'll pick in ambiguous cases (e.g. there are two 3 AMs b/c Fallback DST) 5528function fixOffset(localTS, o, tz) { 5529 // Our UTC time is just a guess because our offset is just a guess 5530 let utcGuess = localTS - o * 60 * 1000; 5531 5532 // Test whether the zone matches the offset for this ts 5533 const o2 = tz.offset(utcGuess); 5534 5535 // If so, offset didn't change and we're done 5536 if (o === o2) { 5537 return [utcGuess, o]; 5538 } 5539 5540 // If not, change the ts by the difference in the offset 5541 utcGuess -= (o2 - o) * 60 * 1000; 5542 5543 // If that gives us the local time we want, we're done 5544 const o3 = tz.offset(utcGuess); 5545 if (o2 === o3) { 5546 return [utcGuess, o2]; 5547 } 5548 5549 // If it's different, we're in a hole time. The offset has changed, but the we don't adjust the time 5550 return [localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3)]; 5551} 5552 5553// convert an epoch timestamp into a calendar object with the given offset 5554function tsToObj(ts, offset) { 5555 ts += offset * 60 * 1000; 5556 5557 const d = new Date(ts); 5558 5559 return { 5560 year: d.getUTCFullYear(), 5561 month: d.getUTCMonth() + 1, 5562 day: d.getUTCDate(), 5563 hour: d.getUTCHours(), 5564 minute: d.getUTCMinutes(), 5565 second: d.getUTCSeconds(), 5566 millisecond: d.getUTCMilliseconds(), 5567 }; 5568} 5569 5570// convert a calendar object to a epoch timestamp 5571function objToTS(obj, offset, zone) { 5572 return fixOffset(objToLocalTS(obj), offset, zone); 5573} 5574 5575// create a new DT instance by adding a duration, adjusting for DSTs 5576function adjustTime(inst, dur) { 5577 const oPre = inst.o, 5578 year = inst.c.year + Math.trunc(dur.years), 5579 month = inst.c.month + Math.trunc(dur.months) + Math.trunc(dur.quarters) * 3, 5580 c = { 5581 ...inst.c, 5582 year, 5583 month, 5584 day: 5585 Math.min(inst.c.day, daysInMonth(year, month)) + 5586 Math.trunc(dur.days) + 5587 Math.trunc(dur.weeks) * 7, 5588 }, 5589 millisToAdd = Duration.fromObject({ 5590 years: dur.years - Math.trunc(dur.years), 5591 quarters: dur.quarters - Math.trunc(dur.quarters), 5592 months: dur.months - Math.trunc(dur.months), 5593 weeks: dur.weeks - Math.trunc(dur.weeks), 5594 days: dur.days - Math.trunc(dur.days), 5595 hours: dur.hours, 5596 minutes: dur.minutes, 5597 seconds: dur.seconds, 5598 milliseconds: dur.milliseconds, 5599 }).as("milliseconds"), 5600 localTS = objToLocalTS(c); 5601 5602 let [ts, o] = fixOffset(localTS, oPre, inst.zone); 5603 5604 if (millisToAdd !== 0) { 5605 ts += millisToAdd; 5606 // that could have changed the offset by going over a DST, but we want to keep the ts the same 5607 o = inst.zone.offset(ts); 5608 } 5609 5610 return { ts, o }; 5611} 5612 5613// helper useful in turning the results of parsing into real dates 5614// by handling the zone options 5615function parseDataToDateTime(parsed, parsedZone, opts, format, text, specificOffset) { 5616 const { setZone, zone } = opts; 5617 if ((parsed && Object.keys(parsed).length !== 0) || parsedZone) { 5618 const interpretationZone = parsedZone || zone, 5619 inst = DateTime.fromObject(parsed, { 5620 ...opts, 5621 zone: interpretationZone, 5622 specificOffset, 5623 }); 5624 return setZone ? inst : inst.setZone(zone); 5625 } else { 5626 return DateTime.invalid( 5627 new Invalid("unparsable", `the input "${text}" can't be parsed as ${format}`) 5628 ); 5629 } 5630} 5631 5632// if you want to output a technical format (e.g. RFC 2822), this helper 5633// helps handle the details 5634function toTechFormat(dt, format, allowZ = true) { 5635 return dt.isValid 5636 ? Formatter.create(Locale.create("en-US"), { 5637 allowZ, 5638 forceSimple: true, 5639 }).formatDateTimeFromString(dt, format) 5640 : null; 5641} 5642 5643function toISODate(o, extended) { 5644 const longFormat = o.c.year > 9999 || o.c.year < 0; 5645 let c = ""; 5646 if (longFormat && o.c.year >= 0) c += "+"; 5647 c += padStart(o.c.year, longFormat ? 6 : 4); 5648 5649 if (extended) { 5650 c += "-"; 5651 c += padStart(o.c.month); 5652 c += "-"; 5653 c += padStart(o.c.day); 5654 } else { 5655 c += padStart(o.c.month); 5656 c += padStart(o.c.day); 5657 } 5658 return c; 5659} 5660 5661function toISOTime( 5662 o, 5663 extended, 5664 suppressSeconds, 5665 suppressMilliseconds, 5666 includeOffset, 5667 extendedZone 5668) { 5669 let c = padStart(o.c.hour); 5670 if (extended) { 5671 c += ":"; 5672 c += padStart(o.c.minute); 5673 if (o.c.millisecond !== 0 || o.c.second !== 0 || !suppressSeconds) { 5674 c += ":"; 5675 } 5676 } else { 5677 c += padStart(o.c.minute); 5678 } 5679 5680 if (o.c.millisecond !== 0 || o.c.second !== 0 || !suppressSeconds) { 5681 c += padStart(o.c.second); 5682 5683 if (o.c.millisecond !== 0 || !suppressMilliseconds) { 5684 c += "."; 5685 c += padStart(o.c.millisecond, 3); 5686 } 5687 } 5688 5689 if (includeOffset) { 5690 if (o.isOffsetFixed && o.offset === 0 && !extendedZone) { 5691 c += "Z"; 5692 } else if (o.o < 0) { 5693 c += "-"; 5694 c += padStart(Math.trunc(-o.o / 60)); 5695 c += ":"; 5696 c += padStart(Math.trunc(-o.o % 60)); 5697 } else { 5698 c += "+"; 5699 c += padStart(Math.trunc(o.o / 60)); 5700 c += ":"; 5701 c += padStart(Math.trunc(o.o % 60)); 5702 } 5703 } 5704 5705 if (extendedZone) { 5706 c += "[" + o.zone.ianaName + "]"; 5707 } 5708 return c; 5709} 5710 5711// defaults for unspecified units in the supported calendars 5712const defaultUnitValues = { 5713 month: 1, 5714 day: 1, 5715 hour: 0, 5716 minute: 0, 5717 second: 0, 5718 millisecond: 0, 5719 }, 5720 defaultWeekUnitValues = { 5721 weekNumber: 1, 5722 weekday: 1, 5723 hour: 0, 5724 minute: 0, 5725 second: 0, 5726 millisecond: 0, 5727 }, 5728 defaultOrdinalUnitValues = { 5729 ordinal: 1, 5730 hour: 0, 5731 minute: 0, 5732 second: 0, 5733 millisecond: 0, 5734 }; 5735 5736// Units in the supported calendars, sorted by bigness 5737const orderedUnits = ["year", "month", "day", "hour", "minute", "second", "millisecond"], 5738 orderedWeekUnits = [ 5739 "weekYear", 5740 "weekNumber", 5741 "weekday", 5742 "hour", 5743 "minute", 5744 "second", 5745 "millisecond", 5746 ], 5747 orderedOrdinalUnits = ["year", "ordinal", "hour", "minute", "second", "millisecond"]; 5748 5749// standardize case and plurality in units 5750function normalizeUnit(unit) { 5751 const normalized = { 5752 year: "year", 5753 years: "year", 5754 month: "month", 5755 months: "month", 5756 day: "day", 5757 days: "day", 5758 hour: "hour", 5759 hours: "hour", 5760 minute: "minute", 5761 minutes: "minute", 5762 quarter: "quarter", 5763 quarters: "quarter", 5764 second: "second", 5765 seconds: "second", 5766 millisecond: "millisecond", 5767 milliseconds: "millisecond", 5768 weekday: "weekday", 5769 weekdays: "weekday", 5770 weeknumber: "weekNumber", 5771 weeksnumber: "weekNumber", 5772 weeknumbers: "weekNumber", 5773 weekyear: "weekYear", 5774 weekyears: "weekYear", 5775 ordinal: "ordinal", 5776 }[unit.toLowerCase()]; 5777 5778 if (!normalized) throw new InvalidUnitError(unit); 5779 5780 return normalized; 5781} 5782 5783function normalizeUnitWithLocalWeeks(unit) { 5784 switch (unit.toLowerCase()) { 5785 case "localweekday": 5786 case "localweekdays": 5787 return "localWeekday"; 5788 case "localweeknumber": 5789 case "localweeknumbers": 5790 return "localWeekNumber"; 5791 case "localweekyear": 5792 case "localweekyears": 5793 return "localWeekYear"; 5794 default: 5795 return normalizeUnit(unit); 5796 } 5797} 5798 5799//
5799cache offsets for zones based on the current timestamp when this function is 5800// first called. When we are handling a datetime from components like (year, 5801// month, day, hour) in a time zone, we need a guess about what the timezone 5802// offset is so that we can convert into a UTC timestamp. One way is to find the 5803// offset of now in the zone. The actual date may have a different offset (for 5804// example, if we handle a date in June while we're in December in a zone that 5805// observes DST), but we can check and adjust that. 5806// 5807// When handling many dates, calculating the offset for now every time is 5808// expensive. It's just a guess, so we can cache the offset to use even if we 5809// are right on a time change boundary (we'll just correct in the other 5810// direction). Using a timestamp from first read is a slight optimization for 5811// handling dates close to the current date, since those dates will usually be 5812// in the same offset (we could set the timestamp statically, instead). We use a 5813// single timestamp for all zones to make things a bit more predictable. 5814// 5815// This is safe for quickDT (used by local() and utc()) because we don't fill in 5816// higher-order units from tsNow (as we do in fromObject, this requires that 5817// offset is calculated from tsNow). 5818function guessOffsetForZone(zone) { 5819 if (!zoneOffsetGuessCache[zone]) { 5820 if (zoneOffsetTs === undefined) { 5821 zoneOffsetTs = Settings.now(); 5822 } 5823 5824 zoneOffsetGuessCache[zone] = zone.offset(zoneOffsetTs); 5825 } 5826 return zoneOffsetGuessCache[zone]; 5827} 5828 5829// this is a dumbed down version of fromObject() that runs about 60% faster 5830// but doesn't do any validation, makes a bunch of assumptions about what units 5831// are present, and so on. 5832function quickDT(obj, opts) { 5833 const zone = normalizeZone(opts.zone, Settings.defaultZone); 5834 if (!zone.isValid) { 5835 return DateTime.invalid(unsupportedZone(zone)); 5836 } 5837 5838 const loc = Locale.fromObject(opts); 5839 5840 let ts, o; 5841 5842 // assume we have the higher-order units 5843 if (!isUndefined(obj.year)) { 5844 for (const u of orderedUnits) { 5845 if (isUndefined(obj[u])) {
vendor: 1,849 bytes, lines 5846-5916
5846 obj[u] = defaultUnitValues[u]; 5847 } 5848 } 5849 5850 const invalid = hasInvalidGregorianData(obj) || hasInvalidTimeData(obj); 5851 if (invalid) { 5852 return DateTime.invalid(invalid); 5853 } 5854 5855 const offsetProvis = guessOffsetForZone(zone); 5856 [ts, o] = objToTS(obj, offsetProvis, zone); 5857 } else { 5858 ts = Settings.now(); 5859 } 5860 5861 return new DateTime({ ts, zone, loc, o }); 5862} 5863 5864function diffRelative(start, end, opts) { 5865 const round = isUndefined(opts.round) ? true : opts.round, 5866 format = (c, unit) => { 5867 c = roundTo(c, round || opts.calendary ? 0 : 2, true); 5868 const formatter = end.loc.clone(opts).relFormatter(opts); 5869 return formatter.format(c, unit); 5870 }, 5871 differ = (unit) => { 5872 if (opts.calendary) { 5873 if (!end.hasSame(start, unit)) { 5874 return end.startOf(unit).diff(start.startOf(unit), unit).get(unit); 5875 } else return 0; 5876 } else { 5877 return end.diff(start, unit).get(unit); 5878 } 5879 }; 5880 5881 if (opts.unit) { 5882 return format(differ(opts.unit), opts.unit); 5883 } 5884 5885 for (const unit of opts.units) { 5886 const count = differ(unit); 5887 if (Math.abs(count) >= 1) { 5888 return format(count, unit); 5889 } 5890 } 5891 return format(start > end ? -0 : 0, opts.units[opts.units.length - 1]); 5892} 5893 5894function lastOpts(argList) { 5895 let opts = {}, 5896 args; 5897 if (argList.length > 0 && typeof argList[argList.length - 1] === "object") { 5898 opts = argList[argList.length - 1]; 5899 args = Array.from(argList).slice(0, argList.length - 1); 5900 } else { 5901 args = Array.from(argList); 5902 } 5903 return [opts, args]; 5904} 5905 5906/** 5907 * Timestamp to use for cached zone offset guesses (exposed for test) 5908 */ 5909let zoneOffsetTs; 5910/** 5911 * Cache for zone offset guesses (exposed for test). 5912 * 5913 * This optimizes quickDT via guessOffsetForZone to avoid repeated calls of 5914 * zone.offset(). 5915 */ 5916let zoneOffsetGuessCache = {}
vendor: 28,762 bytes, lines 5916-6481
5916; 5917 5918/** 5919 * A DateTime is an immutable data structure representing a specific date and time and accompanying methods. It contains class and instance methods for creating, parsing, interrogating, transforming, and formatting them. 5920 * 5921 * A DateTime comprises of: 5922 * * A timestamp. Each DateTime instance refers to a specific millisecond of the Unix epoch. 5923 * * A time zone. Each instance is considered in the context of a specific zone (by default the local system's zone). 5924 * * Configuration properties that effect how output strings are formatted, such as `locale`, `numberingSystem`, and `outputCalendar`. 5925 * 5926 * Here is a brief overview of the most commonly used functionality it provides: 5927 * 5928 * * **Creation**: To create a DateTime from its components, use one of its factory class methods: {@link DateTime.local}, {@link DateTime.utc}, and (most flexibly) {@link DateTime.fromObject}. To create one from a standard string format, use {@link DateTime.fromISO}, {@link DateTime.fromHTTP}, and {@link DateTime.fromRFC2822}. To create one from a custom string format, use {@link DateTime.fromFormat}. To create one from a native JS date, use {@link DateTime.fromJSDate}. 5929 * * **Gregorian calendar and time**: To examine the Gregorian properties of a DateTime individually (i.e as opposed to collectively through {@link DateTime#toObject}), use the {@link DateTime#year}, {@link DateTime#month}, 5930 * {@link DateTime#day}, {@link DateTime#hour}, {@link DateTime#minute}, {@link DateTime#second}, {@link DateTime#millisecond} accessors. 5931 * * **Week calendar**: For ISO week calendar attributes, see the {@link DateTime#weekYear}, {@link DateTime#weekNumber}, and {@link DateTime#weekday} accessors. 5932 * * **Configuration** See the {@link DateTime#locale} and {@link DateTime#numberingSystem} accessors. 5933 * * **Transformation**: To transform the DateTime into other DateTimes, use {@link DateTime#set}, {@link DateTime#reconfigure}, {@link DateTime#setZone}, {@link DateTime#setLocale}, {@link DateTime.plus}, {@link DateTime#minus}, {@link DateTime#endOf}, {@link DateTime#startOf}, {@link DateTime#toUTC}, and {@link DateTime#toLocal}. 5934 * * **Output**: To convert the DateTime to other representations, use the {@link DateTime#toRelative}, {@link DateTime#toRelativeCalendar}, {@link DateTime#toJSON}, {@link DateTime#toISO}, {@link DateTime#toHTTP}, {@link DateTime#toObject}, {@link DateTime#toRFC2822}, {@link DateTime#toString}, {@link DateTime#toLocaleString}, {@link DateTime#toFormat}, {@link DateTime#toMillis} and {@link DateTime#toJSDate}. 5935 * 5936 * There's plenty others documented below. In addition, for more information on subtler topics like internationalization, time zones, alternative calendars, validity, and so on, see the external documentation. 5937 */ 5938class DateTime { 5939 /** 5940 * @access private 5941 */ 5942 constructor(config) { 5943 const zone = config.zone || Settings.defaultZone; 5944 5945 let invalid = 5946 config.invalid || 5947 (Number.isNaN(config.ts) ? new Invalid("invalid input") : null) || 5948 (!zone.isValid ? unsupportedZone(zone) : null); 5949 /** 5950 * @access private 5951 */ 5952 this.ts = isUndefined(config.ts) ? Settings.now() : config.ts; 5953 5954 let c = null, 5955 o = null; 5956 if (!invalid) { 5957 const unchanged = config.old && config.old.ts === this.ts && config.old.zone.equals(zone); 5958 5959 if (unchanged) { 5960 [c, o] = [config.old.c, config.old.o]; 5961 } else { 5962 // If an offset has been passed and we have not been called from 5963 // clone(), we can trust it and avoid the offset calculation. 5964 const ot = isNumber(config.o) && !config.old ? config.o : zone.offset(this.ts); 5965 c = tsToObj(this.ts, ot); 5966 invalid = Number.isNaN(c.year) ? new Invalid("invalid input") : null; 5967 c = invalid ? null : c; 5968 o = invalid ? null : ot; 5969 } 5970 } 5971 5972 /** 5973 * @access private 5974 */ 5975 this._zone = zone; 5976 /** 5977 * @access private 5978 */ 5979 this.loc = config.loc || Locale.create(); 5980 /** 5981 * @access private 5982 */ 5983 this.invalid = invalid; 5984 /** 5985 * @access private 5986 */ 5987 this.weekData = null; 5988 /** 5989 * @access private 5990 */ 5991 this.localWeekData = null; 5992 /** 5993 * @access private 5994 */ 5995 this.c = c; 5996 /** 5997 * @access private 5998 */ 5999 this.o = o; 6000 /** 6001 * @access private 6002 */ 6003 this.isLuxonDateTime = true; 6004 } 6005 6006 // CONSTRUCT 6007 6008 /** 6009 * Create a DateTime for the current instant, in the system's time zone. 6010 * 6011 * Use Settings to override these default values if needed. 6012 * @example DateTime.now().toISO() //~> now in the ISO format 6013 * @return {DateTime} 6014 */ 6015 static now() { 6016 return new DateTime({}); 6017 } 6018 6019 /** 6020 * Create a local DateTime 6021 * @param {number} [year] - The calendar year. If omitted (as in, call `local()` with no arguments), the current time will be used 6022 * @param {number} [month=1] - The month, 1-indexed 6023 * @param {number} [day=1] - The day of the month, 1-indexed 6024 * @param {number} [hour=0] - The hour of the day, in 24-hour time 6025 * @param {number} [minute=0] - The minute of the hour, meaning a number between 0 and 59 6026 * @param {number} [second=0] - The second of the minute, meaning a number between 0 and 59 6027 * @param {number} [millisecond=0] - The millisecond of the second, meaning a number between 0 and 999 6028 * @example DateTime.local() //~> now 6029 * @example DateTime.local({ zone: "America/New_York" }) //~> now, in US east coast time 6030 * @example DateTime.local(2017) //~> 2017-01-01T00:00:00 6031 * @example DateTime.local(2017, 3) //~> 2017-03-01T00:00:00 6032 * @example DateTime.local(2017, 3, 12, { locale: "fr" }) //~> 2017-03-12T00:00:00, with a French locale 6033 * @example DateTime.local(2017, 3, 12, 5) //~> 2017-03-12T05:00:00 6034 * @example DateTime.local(2017, 3, 12, 5, { zone: "utc" }) //~> 2017-03-12T05:00:00, in UTC 6035 * @example DateTime.local(2017, 3, 12, 5, 45) //~> 2017-03-12T05:45:00 6036 * @example DateTime.local(2017, 3, 12, 5, 45, 10) //~> 2017-03-12T05:45:10 6037 * @example DateTime.local(2017, 3, 12, 5, 45, 10, 765) //~> 2017-03-12T05:45:10.765 6038 * @return {DateTime} 6039 */ 6040 static local() { 6041 const [opts, args] = lastOpts(arguments), 6042 [year, month, day, hour, minute, second, millisecond] = args; 6043 return quickDT({ year, month, day, hour, minute, second, millisecond }, opts); 6044 } 6045 6046 /** 6047 * Create a DateTime in UTC 6048 * @param {number} [year] - The calendar year. If omitted (as in, call `utc()` with no arguments), the current time will be used 6049 * @param {number} [month=1] - The month, 1-indexed 6050 * @param {number} [day=1] - The day of the month 6051 * @param {number} [hour=0] - The hour of the day, in 24-hour time 6052 * @param {number} [minute=0] - The minute of the hour, meaning a number between 0 and 59 6053 * @param {number} [second=0] - The second of the minute, meaning a number between 0 and 59 6054 * @param {number} [millisecond=0] - The millisecond of the second, meaning a number between 0 and 999 6055 * @param {Object} options - configuration options for the DateTime 6056 * @param {string} [options.locale] - a locale to set on the resulting DateTime instance 6057 * @param {string} [options.outputCalendar] - the output calendar to set on the resulting DateTime instance 6058 * @param {string} [options.numberingSystem] - the numbering system to set on the resulting DateTime instance 6059 * @param {string} [options.weekSettings] - the week settings to set on the resulting DateTime instance 6060 * @example DateTime.utc() //~> now 6061 * @example DateTime.utc(2017) //~> 2017-01-01T00:00:00Z 6062 * @example DateTime.utc(2017, 3) //~> 2017-03-01T00:00:00Z 6063 * @example DateTime.utc(2017, 3, 12) //~> 2017-03-12T00:00:00Z 6064 * @example DateTime.utc(2017, 3, 12, 5) //~> 2017-03-12T05:00:00Z 6065 * @example DateTime.utc(2017, 3, 12, 5, 45) //~> 2017-03-12T05:45:00Z 6066 * @example DateTime.utc(2017, 3, 12, 5, 45, { locale: "fr" }) //~> 2017-03-12T05:45:00Z with a French locale 6067 * @example DateTime.utc(2017, 3, 12, 5, 45, 10) //~> 2017-03-12T05:45:10Z 6068 * @example DateTime.utc(2017, 3, 12, 5, 45, 10, 765, { locale: "fr" }) //~> 2017-03-12T05:45:10.765Z with a French locale 6069 * @return {DateTime} 6070 */ 6071 static utc() { 6072 const [opts, args] = lastOpts(arguments), 6073 [year, month, day, hour, minute, second, millisecond] = args; 6074 6075 opts.zone = FixedOffsetZone.utcInstance; 6076 return quickDT({ year, month, day, hour, minute, second, millisecond }, opts); 6077 } 6078 6079 /** 6080 * Create a DateTime from a JavaScript Date object. Uses the default zone. 6081 * @param {Date} date - a JavaScript Date object 6082 * @param {Object} options - configuration options for the DateTime 6083 * @param {string|Zone} [options.zone='local'] - the zone to place the DateTime into 6084 * @return {DateTime} 6085 */ 6086 static fromJSDate(date, options = {}) { 6087 const ts = isDate(date) ? date.valueOf() : NaN; 6088 if (Number.isNaN(ts)) { 6089 return DateTime.invalid("invalid input"); 6090 } 6091 6092 const zoneToUse = normalizeZone(options.zone, Settings.defaultZone); 6093 if (!zoneToUse.isValid) { 6094 return DateTime.invalid(unsupportedZone(zoneToUse)); 6095 } 6096 6097 return new DateTime({ 6098 ts: ts, 6099 zone: zoneToUse, 6100 loc: Locale.fromObject(options), 6101 }); 6102 } 6103 6104 /** 6105 * Create a DateTime from a number of milliseconds since the epoch (meaning since 1 January 1970 00:00:00 UTC). Uses the default zone. 6106 * @param {number} milliseconds - a number of milliseconds since 1970 UTC 6107 * @param {Object} options - configuration options for the DateTime 6108 * @param {string|Zone} [options.zone='local'] - the zone to place the DateTime into 6109 * @param {string} [options.locale] - a locale to set on the resulting DateTime instance 6110 * @param {string} options.outputCalendar - the output calendar to set on the resulting DateTime instance 6111 * @param {string} options.numberingSystem - the numbering system to set on the resulting DateTime instance 6112 * @param {string} options.weekSettings - the week settings to set on the resulting DateTime instance 6113 * @return {DateTime} 6114 */ 6115 static fromMillis(milliseconds, options = {}) { 6116 if (!isNumber(milliseconds)) { 6117 throw new InvalidArgumentError( 6118 `fromMillis requires a numerical input, but received a ${typeof milliseconds} with value ${milliseconds}` 6119 ); 6120 } else if (milliseconds < -MAX_DATE || milliseconds > MAX_DATE) { 6121 // this isn't perfect because we can still end up out of range because of additional shifting, but it's a start 6122 return DateTime.invalid("Timestamp out of range"); 6123 } else { 6124 return new DateTime({ 6125 ts: milliseconds, 6126 zone: normalizeZone(options.zone, Settings.defaultZone), 6127 loc: Locale.fromObject(options), 6128 }); 6129 } 6130 } 6131 6132 /** 6133 * Create a DateTime from a number of seconds since the epoch (meaning since 1 January 1970 00:00:00 UTC). Uses the default zone. 6134 * @param {number} seconds - a number of seconds since 1970 UTC 6135 * @param {Object} options - configuration options for the DateTime 6136 * @param {string|Zone} [options.zone='local'] - the zone to place the DateTime into 6137 * @param {string} [options.locale] - a locale to set on the resulting DateTime instance 6138 * @param {string} options.outputCalendar - the output calendar to set on the resulting DateTime instance 6139 * @param {string} options.numberingSystem - the numbering system to set on the resulting DateTime instance 6140 * @param {string} options.weekSettings - the week settings to set on the resulting DateTime instance 6141 * @return {DateTime} 6142 */ 6143 static fromSeconds(seconds, options = {}) { 6144 if (!isNumber(seconds)) { 6145 throw new InvalidArgumentError("fromSeconds requires a numerical input"); 6146 } else { 6147 return new DateTime({ 6148 ts: seconds * 1000, 6149 zone: normalizeZone(options.zone, Settings.defaultZone), 6150 loc: Locale.fromObject(options), 6151 }); 6152 } 6153 } 6154 6155 /** 6156 * Create a DateTime from a JavaScript object with keys like 'year' and 'hour' with reasonable defaults. 6157 * @param {Object} obj - the object to create the DateTime from 6158 * @param {number} obj.year - a year, such as 1987 6159 * @param {number} obj.month - a month, 1-12 6160 * @param {number} obj.day - a day of the month, 1-31, depending on the month 6161 * @param {number} obj.ordinal - day of the year, 1-365 or 366 6162 * @param {number} obj.weekYear - an ISO week year 6163 * @param {number} obj.weekNumber - an ISO week number, between 1 and 52 or 53, depending on the year 6164 * @param {number} obj.weekday - an ISO weekday, 1-7, where 1 is Monday and 7 is Sunday 6165 * @param {number} obj.localWeekYear - a week year, according to the locale 6166 * @param {number} obj.localWeekNumber - a week number, between 1 and 52 or 53, depending on the year, according to the locale 6167 * @param {number} obj.localWeekday - a weekday, 1-7, where 1 is the first and 7 is the last day of the week, according to the locale 6168 * @param {number} obj.hour - hour of the day, 0-23 6169 * @param {number} obj.minute - minute of the hour, 0-59 6170 * @param {number} obj.second - second of the minute, 0-59 6171 * @param {number} obj.millisecond - millisecond of the second, 0-999 6172 * @param {Object} opts - options for creating this DateTime 6173 * @param {string|Zone} [opts.zone='local'] - interpret the numbers in the context of a particular zone. Can take any value taken as the first argument to setZone() 6174 * @param {string} [opts.locale='system\'s locale'] - a locale to set on the resulting DateTime instance 6175 * @param {string} opts.outputCalendar - the output calendar to set on the resulting DateTime instance 6176 * @param {string} opts.numberingSystem - the numbering system to set on the resulting DateTime instance 6177 * @param {string} opts.weekSettings - the week settings to set on the resulting DateTime instance 6178 * @example DateTime.fromObject({ year: 1982, month: 5, day: 25}).toISODate() //=> '1982-05-25' 6179 * @example DateTime.fromObject({ year: 1982 }).toISODate() //=> '1982-01-01' 6180 * @example DateTime.fromObject({ hour: 10, minute: 26, second: 6 }) //~> today at 10:26:06 6181 * @example DateTime.fromObject({ hour: 10, minute: 26, second: 6 }, { zone: 'utc' }), 6182 * @example DateTime.fromObject({ hour: 10, minute: 26, second: 6 }, { zone: 'local' }) 6183 * @example DateTime.fromObject({ hour: 10, minute: 26, second: 6 }, { zone: 'America/New_York' }) 6184 * @example DateTime.fromObject({ weekYear: 2016, weekNumber: 2, weekday: 3 }).toISODate() //=> '2016-01-13' 6185 * @example DateTime.fromObject({ localWeekYear: 2022, localWeekNumber: 1, localWeekday: 1 }, { locale: "en-US" }).toISODate() //=> '2021-12-26' 6186 * @return {DateTime} 6187 */ 6188 static fromObject(obj, opts = {}) { 6189 obj = obj || {}; 6190 const zoneToUse = normalizeZone(opts.zone, Settings.defaultZone); 6191 if (!zoneToUse.isValid) { 6192 return DateTime.invalid(unsupportedZone(zoneToUse)); 6193 } 6194 6195 const loc = Locale.fromObject(opts); 6196 const normalized = normalizeObject(obj, normalizeUnitWithLocalWeeks); 6197 const { minDaysInFirstWeek, startOfWeek } = usesLocalWeekValues(normalized, loc); 6198 6199 const tsNow = Settings.now(), 6200 offsetProvis = !isUndefined(opts.specificOffset) 6201 ? opts.specificOffset 6202 : zoneToUse.offset(tsNow), 6203 containsOrdinal = !isUndefined(normalized.ordinal), 6204 containsGregorYear = !isUndefined(normalized.year), 6205 containsGregorMD = !isUndefined(normalized.month) || !isUndefined(normalized.day), 6206 containsGregor = containsGregorYear || containsGregorMD, 6207 definiteWeekDef = normalized.weekYear || normalized.weekNumber; 6208 6209 // cases: 6210 // just a weekday -> this week's instance of that weekday, no worries 6211 // (gregorian data or ordinal) + (weekYear or weekNumber) -> error 6212 // (gregorian month or day) + ordinal -> error 6213 // otherwise just use weeks or ordinals or gregorian, depending on what's specified 6214 6215 if ((containsGregor || containsOrdinal) && definiteWeekDef) { 6216 throw new ConflictingSpecificationError( 6217 "Can't mix weekYear/weekNumber units with year/month/day or ordinals" 6218 ); 6219 } 6220 6221 if (containsGregorMD && containsOrdinal) { 6222 throw new ConflictingSpecificationError("Can't mix ordinal dates with month/day"); 6223 } 6224 6225 const useWeekData = definiteWeekDef || (normalized.weekday && !containsGregor); 6226 6227 // configure ourselves to deal with gregorian dates or week stuff 6228 let units, 6229 defaultValues, 6230 objNow = tsToObj(tsNow, offsetProvis); 6231 if (useWeekData) { 6232 units = orderedWeekUnits; 6233 defaultValues = defaultWeekUnitValues; 6234 objNow = gregorianToWeek(objNow, minDaysInFirstWeek, startOfWeek); 6235 } else if (containsOrdinal) { 6236 units = orderedOrdinalUnits; 6237 defaultValues = defaultOrdinalUnitValues; 6238 objNow = gregorianToOrdinal(objNow); 6239 } else { 6240 units = orderedUnits; 6241 defaultValues = defaultUnitValues; 6242 } 6243 6244 // set default values for missing stuff 6245 let foundFirst = false; 6246 for (const u of units) { 6247 const v = normalized[u]; 6248 if (!isUndefined(v)) { 6249 foundFirst = true; 6250 } else if (foundFirst) { 6251 normalized[u] = defaultValues[u]; 6252 } else { 6253 normalized[u] = objNow[u]; 6254 } 6255 } 6256 6257 // make sure the values we have are in range 6258 const higherOrderInvalid = useWeekData 6259 ? hasInvalidWeekData(normalized, minDaysInFirstWeek, startOfWeek) 6260 : containsOrdinal 6261 ? hasInvalidOrdinalData(normalized) 6262 : hasInvalidGregorianData(normalized), 6263 invalid = higherOrderInvalid || hasInvalidTimeData(normalized); 6264 6265 if (invalid) { 6266 return DateTime.invalid(invalid); 6267 } 6268 6269 // compute the actual time 6270 const gregorian = useWeekData 6271 ? weekToGregorian(normalized, minDaysInFirstWeek, startOfWeek) 6272 : containsOrdinal 6273 ? ordinalToGregorian(normalized) 6274 : normalized, 6275 [tsFinal, offsetFinal] = objToTS(gregorian, offsetProvis, zoneToUse), 6276 inst = new DateTime({ 6277 ts: tsFinal, 6278 zone: zoneToUse, 6279 o: offsetFinal, 6280 loc, 6281 }); 6282 6283 // gregorian data + weekday serves only to validate 6284 if (normalized.weekday && containsGregor && obj.weekday !== inst.weekday) { 6285 return DateTime.invalid( 6286 "mismatched weekday", 6287 `you can't specify both a weekday of ${normalized.weekday} and a date of ${inst.toISO()}` 6288 ); 6289 } 6290 6291 if (!inst.isValid) { 6292 return DateTime.invalid(inst.invalid); 6293 } 6294 6295 return inst; 6296 } 6297 6298 /** 6299 * Create a DateTime from an ISO 8601 string 6300 * @param {string} text - the ISO string 6301 * @param {Object} opts - options to affect the creation 6302 * @param {string|Zone} [opts.zone='local'] - use this zone if no offset is specified in the input string itself. Will also convert the time to this zone 6303 * @param {boolean} [opts.setZone=false] - override the zone with a fixed-offset zone specified in the string itself, if it specifies one 6304 * @param {string} [opts.locale='system's locale'] - a locale to set on the resulting DateTime instance 6305 * @param {string} [opts.outputCalendar] - the output calendar to set on the resulting DateTime instance 6306 * @param {string} [opts.numberingSystem] - the numbering system to set on the resulting DateTime instance 6307 * @param {string} [opts.weekSettings] - the week settings to set on the resulting DateTime instance 6308 * @example DateTime.fromISO('2016-05-25T09:08:34.123') 6309 * @example DateTime.fromISO('2016-05-25T09:08:34.123+06:00') 6310 * @example DateTime.fromISO('2016-05-25T09:08:34.123+06:00', {setZone: true}) 6311 * @example DateTime.fromISO('2016-05-25T09:08:34.123', {zone: 'utc'}) 6312 * @example DateTime.fromISO('2016-W05-4') 6313 * @return {DateTime} 6314 */ 6315 static fromISO(text, opts = {}) { 6316 const [vals, parsedZone] = parseISODate(text); 6317 return parseDataToDateTime(vals, parsedZone, opts, "ISO 8601", text); 6318 } 6319 6320 /** 6321 * Create a DateTime from an RFC 2822 string 6322 * @param {string} text - the RFC 2822 string 6323 * @param {Object} opts - options to affect the creation 6324 * @param {string|Zone} [opts.zone='local'] - convert the time to this zone. Since the offset is always specified in the string itself, this has no effect on the interpretation of string, merely the zone the resulting DateTime is expressed in. 6325 * @param {boolean} [opts.setZone=false] - override the zone with a fixed-offset zone specified in the string itself, if it specifies one 6326 * @param {string} [opts.locale='system's locale'] - a locale to set on the resulting DateTime instance 6327 * @param {string} opts.outputCalendar - the output calendar to set on the resulting DateTime instance 6328 * @param {string} opts.numberingSystem - the numbering system to set on the resulting DateTime instance 6329 * @param {string} opts.weekSettings - the week settings to set on the resulting DateTime instance 6330 * @example DateTime.fromRFC2822('25 Nov 2016 13:23:12 GMT') 6331 * @example DateTime.fromRFC2822('Fri, 25 Nov 2016 13:23:12 +0600') 6332 * @example DateTime.fromRFC2822('25 Nov 2016 13:23 Z') 6333 * @return {DateTime} 6334 */ 6335 static fromRFC2822(text, opts = {}) { 6336 const [vals, parsedZone] = parseRFC2822Date(text); 6337 return parseDataToDateTime(vals, parsedZone, opts, "RFC 2822", text); 6338 } 6339 6340 /** 6341 * Create a DateTime from an HTTP header date 6342 * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 6343 * @param {string} text - the HTTP header date 6344 * @param {Object} opts - options to affect the creation 6345 * @param {string|Zone} [opts.zone='local'] - convert the time to this zone. Since HTTP dates are always in UTC, this has no effect on the interpretation of string, merely the zone the resulting DateTime is expressed in. 6346 * @param {boolean} [opts.setZone=false] - override the zone with the fixed-offset zone specified in the string. For HTTP dates, this is always UTC, so this option is equivalent to setting the `zone` option to 'utc', but this option is included for consistency with similar methods. 6347 * @param {string} [opts.locale='system's locale'] - a locale to set on the resulting DateTime instance 6348 * @param {string} opts.outputCalendar - the output calendar to set on the resulting DateTime instance 6349 * @param {string} opts.numberingSystem - the numbering system to set on the resulting DateTime instance 6350 * @param {string} opts.weekSettings - the week settings to set on the resulting DateTime instance 6351 * @example DateTime.fromHTTP('Sun, 06 Nov 1994 08:49:37 GMT') 6352 * @example DateTime.fromHTTP('Sunday, 06-Nov-94 08:49:37 GMT') 6353 * @example DateTime.fromHTTP('Sun Nov 6 08:49:37 1994') 6354 * @return {DateTime} 6355 */ 6356 static fromHTTP(text, opts = {}) { 6357 const [vals, parsedZone] = parseHTTPDate(text); 6358 return parseDataToDateTime(vals, parsedZone, opts, "HTTP", opts); 6359 } 6360 6361 /** 6362 * Create a DateTime from an input string and format string. 6363 * Defaults to en-US if no locale has been specified, regardless of the system's locale. For a table of tokens and their interpretations, see [here](https://moment.github.io/luxon/#/parsing?id=table-of-tokens). 6364 * @param {string} text - the string to parse 6365 * @param {string} fmt - the format the string is expected to be in (see the link below for the formats) 6366 * @param {Object} opts - options to affect the creation 6367 * @param {string|Zone} [opts.zone='local'] - use this zone if no offset is specified in the input string itself. Will also convert the DateTime to this zone 6368 * @param {boolean} [opts.setZone=false] - override the zone with a zone specified in the string itself, if it specifies one 6369 * @param {string} [opts.locale='en-US'] - a locale string to use when parsing. Will also set the DateTime to this locale 6370 * @param {string} opts.numberingSystem - the numbering system to use when parsing. Will also set the resulting DateTime to this numbering system 6371 * @param {string} opts.weekSettings - the week settings to set on the resulting DateTime instance 6372 * @param {string} opts.outputCalendar - the output calendar to set on the resulting DateTime instance 6373 * @return {DateTime} 6374 */ 6375 static fromFormat(text, fmt, opts = {}) { 6376 if (isUndefined(text) || isUndefined(fmt)) { 6377 throw new InvalidArgumentError("fromFormat requires an input string and a format"); 6378 } 6379 6380 const { locale = null, numberingSystem = null } = opts, 6381 localeToUse = Locale.fromOpts({ 6382 locale, 6383 numberingSystem, 6384 defaultToEN: true, 6385 }), 6386 [vals, parsedZone, specificOffset, invalid] = parseFromTokens(localeToUse, text, fmt); 6387 if (invalid) { 6388 return DateTime.invalid(invalid); 6389 } else { 6390 return parseDataToDateTime(vals, parsedZone, opts, `format ${fmt}`, text, specificOffset); 6391 } 6392 } 6393 6394 /** 6395 * @deprecated use fromFormat instead 6396 */ 6397 static fromString(text, fmt, opts = {}) { 6398 return DateTime.fromFormat(text, fmt, opts); 6399 } 6400 6401 /** 6402 * Create a DateTime from a SQL date, time, or datetime 6403 * Defaults to en-US if no locale has been specified, regardless of the system's locale 6404 * @param {string} text - the string to parse 6405 * @param {Object} opts - options to affect the creation 6406 * @param {string|Zone} [opts.zone='local'] - use this zone if no offset is specified in the input string itself. Will also convert the DateTime to this zone 6407 * @param {boolean} [opts.setZone=false] - override the zone with a zone specified in the string itself, if it specifies one 6408 * @param {string} [opts.locale='en-US'] - a locale string to use when parsing. Will also set the DateTime to this locale 6409 * @param {string} opts.numberingSystem - the numbering system to use when parsing. Will also set the resulting DateTime to this numbering system 6410 * @param {string} opts.weekSettings - the week settings to set on the resulting DateTime instance 6411 * @param {string} opts.outputCalendar - the output calendar to set on the resulting DateTime instance 6412 * @example DateTime.fromSQL('2017-05-15') 6413 * @example DateTime.fromSQL('2017-05-15 09:12:34') 6414 * @example DateTime.fromSQL('2017-05-15 09:12:34.342') 6415 * @example DateTime.fromSQL('2017-05-15 09:12:34.342+06:00') 6416 * @example DateTime.fromSQL('2017-05-15 09:12:34.342 America/Los_Angeles') 6417 * @example DateTime.fromSQL('2017-05-15 09:12:34.342 America/Los_Angeles', { setZone: true }) 6418 * @example DateTime.fromSQL('2017-05-15 09:12:34.342', { zone: 'America/Los_Angeles' }) 6419 * @example DateTime.fromSQL('09:12:34.342') 6420 * @return {DateTime} 6421 */ 6422 static fromSQL(text, opts = {}) { 6423 const [vals, parsedZone] = parseSQL(text); 6424 return parseDataToDateTime(vals, parsedZone, opts, "SQL", text); 6425 } 6426 6427 /** 6428 * Create an invalid DateTime. 6429 * @param {string} reason - simple string of why this DateTime is invalid. Should not contain parameters or anything else data-dependent. 6430 * @param {string} [explanation=null] - longer explanation, may include parameters and other useful debugging information 6431 * @return {DateTime} 6432 */ 6433 static invalid(reason, explanation = null) { 6434 if (!reason) { 6435 throw new InvalidArgumentError("need to specify a reason the DateTime is invalid"); 6436 } 6437 6438 const invalid = reason instanceof Invalid ? reason : new Invalid(reason, explanation); 6439 6440 if (Settings.throwOnInvalid) { 6441 throw new InvalidDateTimeError(invalid); 6442 } else { 6443 return new DateTime({ invalid }); 6444 } 6445 } 6446 6447 /** 6448 * Check if an object is an instance of DateTime. Works across context boundaries 6449 * @param {object} o 6450 * @return {boolean} 6451 */ 6452 static isDateTime(o) { 6453 return (o && o.isLuxonDateTime) || false; 6454 } 6455 6456 /** 6457 * Produce the format string for a set of options 6458 * @param formatOpts 6459 * @param localeOpts 6460 * @returns {string} 6461 */ 6462 static parseFormatForOpts(formatOpts, localeOpts = {}) { 6463 const tokenList = formatOptsToTokens(formatOpts, Locale.fromObject(localeOpts)); 6464 return !tokenList ? null : tokenList.map((t) => (t ? t.val : null)).join(""); 6465 } 6466 6467 /** 6468 * Produce the the fully expanded format token for the locale 6469 * Does NOT quote characters, so quoted tokens will not round trip correctly 6470 * @param fmt 6471 * @param localeOpts 6472 * @returns {string} 6473 */ 6474 static expandFormat(fmt, localeOpts = {}) { 6475 const expanded = expandMacroTokens(Formatter.parseFormat(fmt), Locale.fromObject(localeOpts)); 6476 return expanded.map((t) => t.val).join(""); 6477 } 6478 6479 static resetCache() { 6480 zoneOffsetTs = undefined; 6481 zoneOffsetGuessCache
6481 = {}
vendor: 41,868 bytes, lines 6481-7617
6481; 6482 } 6483 6484 // INFO 6485 6486 /** 6487 * Get the value of unit. 6488 * @param {string} unit - a unit such as 'minute' or 'day' 6489 * @example DateTime.local(2017, 7, 4).get('month'); //=> 7 6490 * @example DateTime.local(2017, 7, 4).get('day'); //=> 4 6491 * @return {number} 6492 */ 6493 get(unit) { 6494 return this[unit]; 6495 } 6496 6497 /** 6498 * Returns whether the DateTime is valid. Invalid DateTimes occur when: 6499 * * The DateTime was created from invalid calendar information, such as the 13th month or February 30 6500 * * The DateTime was created by an operation on another invalid date 6501 * @type {boolean} 6502 */ 6503 get isValid() { 6504 return this.invalid === null; 6505 } 6506 6507 /** 6508 * Returns an error code if this DateTime is invalid, or null if the DateTime is valid 6509 * @type {string} 6510 */ 6511 get invalidReason() { 6512 return this.invalid ? this.invalid.reason : null; 6513 } 6514 6515 /** 6516 * Returns an explanation of why this DateTime became invalid, or null if the DateTime is valid 6517 * @type {string} 6518 */ 6519 get invalidExplanation() { 6520 return this.invalid ? this.invalid.explanation : null; 6521 } 6522 6523 /** 6524 * Get the locale of a DateTime, such 'en-GB'. The locale is used when formatting the DateTime 6525 * 6526 * @type {string} 6527 */ 6528 get locale() { 6529 return this.isValid ? this.loc.locale : null; 6530 } 6531 6532 /** 6533 * Get the numbering system of a DateTime, such 'beng'. The numbering system is used when formatting the DateTime 6534 * 6535 * @type {string} 6536 */ 6537 get numberingSystem() { 6538 return this.isValid ? this.loc.numberingSystem : null; 6539 } 6540 6541 /** 6542 * Get the output calendar of a DateTime, such 'islamic'. The output calendar is used when formatting the DateTime 6543 * 6544 * @type {string} 6545 */ 6546 get outputCalendar() { 6547 return this.isValid ? this.loc.outputCalendar : null; 6548 } 6549 6550 /** 6551 * Get the time zone associated with this DateTime. 6552 * @type {Zone} 6553 */ 6554 get zone() { 6555 return this._zone; 6556 } 6557 6558 /** 6559 * Get the name of the time zone. 6560 * @type {string} 6561 */ 6562 get zoneName() { 6563 return this.isValid ? this.zone.name : null; 6564 } 6565 6566 /** 6567 * Get the year 6568 * @example DateTime.local(2017, 5, 25).year //=> 2017 6569 * @type {number} 6570 */ 6571 get year() { 6572 return this.isValid ? this.c.year : NaN; 6573 } 6574 6575 /** 6576 * Get the quarter 6577 * @example DateTime.local(2017, 5, 25).quarter //=> 2 6578 * @type {number} 6579 */ 6580 get quarter() { 6581 return this.isValid ? Math.ceil(this.c.month / 3) : NaN; 6582 } 6583 6584 /** 6585 * Get the month (1-12). 6586 * @example DateTime.local(2017, 5, 25).month //=> 5 6587 * @type {number} 6588 */ 6589 get month() { 6590 return this.isValid ? this.c.month : NaN; 6591 } 6592 6593 /** 6594 * Get the day of the month (1-30ish). 6595 * @example DateTime.local(2017, 5, 25).day //=> 25 6596 * @type {number} 6597 */ 6598 get day() { 6599 return this.isValid ? this.c.day : NaN; 6600 } 6601 6602 /** 6603 * Get the hour of the day (0-23). 6604 * @example DateTime.local(2017, 5, 25, 9).hour //=> 9 6605 * @type {number} 6606 */ 6607 get hour() { 6608 return this.isValid ? this.c.hour : NaN; 6609 } 6610 6611 /** 6612 * Get the minute of the hour (0-59). 6613 * @example DateTime.local(2017, 5, 25, 9, 30).minute //=> 30 6614 * @type {number} 6615 */ 6616 get minute() { 6617 return this.isValid ? this.c.minute : NaN; 6618 } 6619 6620 /** 6621 * Get the second of the minute (0-59). 6622 * @example DateTime.local(2017, 5, 25, 9, 30, 52).second //=> 52 6623 * @type {number} 6624 */ 6625 get second() { 6626 return this.isValid ? this.c.second : NaN; 6627 } 6628 6629 /** 6630 * Get the millisecond of the second (0-999). 6631 * @example DateTime.local(2017, 5, 25, 9, 30, 52, 654).millisecond //=> 654 6632 * @type {number} 6633 */ 6634 get millisecond() { 6635 return this.isValid ? this.c.millisecond : NaN; 6636 } 6637 6638 /** 6639 * Get the week year 6640 * @see https://en.wikipedia.org/wiki/ISO_week_date 6641 * @example DateTime.local(2014, 12, 31).weekYear //=> 2015 6642 * @type {number} 6643 */ 6644 get weekYear() { 6645 return this.isValid ? possiblyCachedWeekData(this).weekYear : NaN; 6646 } 6647 6648 /** 6649 * Get the week number of the week year (1-52ish). 6650 * @see https://en.wikipedia.org/wiki/ISO_week_date 6651 * @example DateTime.local(2017, 5, 25).weekNumber //=> 21 6652 * @type {number} 6653 */ 6654 get weekNumber() { 6655 return this.isValid ? possiblyCachedWeekData(this).weekNumber : NaN; 6656 } 6657 6658 /** 6659 * Get the day of the week. 6660 * 1 is Monday and 7 is Sunday 6661 * @see https://en.wikipedia.org/wiki/ISO_week_date 6662 * @example DateTime.local(2014, 11, 31).weekday //=> 4 6663 * @type {number} 6664 */ 6665 get weekday() { 6666 return this.isValid ? possiblyCachedWeekData(this).weekday : NaN; 6667 } 6668 6669 /** 6670 * Returns true if this date is on a weekend according to the locale, false otherwise 6671 * @returns {boolean} 6672 */ 6673 get isWeekend() { 6674 return this.isValid && this.loc.getWeekendDays().includes(this.weekday); 6675 } 6676 6677 /** 6678 * Get the day of the week according to the locale. 6679 * 1 is the first day of the week and 7 is the last day of the week. 6680 * If the locale assigns Sunday as the first day of the week, then a date which is a Sunday will return 1, 6681 * @returns {number} 6682 */ 6683 get localWeekday() { 6684 return this.isValid ? possiblyCachedLocalWeekData(this).weekday : NaN; 6685 } 6686 6687 /** 6688 * Get the week number of the week year according to the locale. Different locales assign week numbers differently, 6689 * because the week can start on different days of the week (see localWeekday) and because a different number of days 6690 * is required for a week to count as the first week of a year. 6691 * @returns {number} 6692 */ 6693 get localWeekNumber() { 6694 return this.isValid ? possiblyCachedLocalWeekData(this).weekNumber : NaN; 6695 } 6696 6697 /** 6698 * Get the week year according to the locale. Different locales assign week numbers (and therefor week years) 6699 * differently, see localWeekNumber. 6700 * @returns {number} 6701 */ 6702 get localWeekYear() { 6703 return this.isValid ? possiblyCachedLocalWeekData(this).weekYear : NaN; 6704 } 6705 6706 /** 6707 * Get the ordinal (meaning the day of the year) 6708 * @example DateTime.local(2017, 5, 25).ordinal //=> 145 6709 * @type {number|DateTime} 6710 */ 6711 get ordinal() { 6712 return this.isValid ? gregorianToOrdinal(this.c).ordinal : NaN; 6713 } 6714 6715 /** 6716 * Get the human readable short month name, such as 'Oct'. 6717 * Defaults to the system's locale if no locale has been specified 6718 * @example DateTime.local(2017, 10, 30).monthShort //=> Oct 6719 * @type {string} 6720 */ 6721 get monthShort() { 6722 return this.isValid ? Info.months("short", { locObj: this.loc })[this.month - 1] : null; 6723 } 6724 6725 /** 6726 * Get the human readable long month name, such as 'October'. 6727 * Defaults to the system's locale if no locale has been specified 6728 * @example DateTime.local(2017, 10, 30).monthLong //=> October 6729 * @type {string} 6730 */ 6731 get monthLong() { 6732 return this.isValid ? Info.months("long", { locObj: this.loc })[this.month - 1] : null; 6733 } 6734 6735 /** 6736 * Get the human readable short weekday, such as 'Mon'. 6737 * Defaults to the system's locale if no locale has been specified 6738 * @example DateTime.local(2017, 10, 30).weekdayShort //=> Mon 6739 * @type {string} 6740 */ 6741 get weekdayShort() { 6742 return this.isValid ? Info.weekdays("short", { locObj: this.loc })[this.weekday - 1] : null; 6743 } 6744 6745 /** 6746 * Get the human readable long weekday, such as 'Monday'. 6747 * Defaults to the system's locale if no locale has been specified 6748 * @example DateTime.local(2017, 10, 30).weekdayLong //=> Monday 6749 * @type {string} 6750 */ 6751 get weekdayLong() { 6752 return this.isValid ? Info.weekdays("long", { locObj: this.loc })[this.weekday - 1] : null; 6753 } 6754 6755 /** 6756 * Get the UTC offset of this DateTime in minutes 6757 * @example DateTime.now().offset //=> -240 6758 * @example DateTime.utc().offset //=> 0 6759 * @type {number} 6760 */ 6761 get offset() { 6762 return this.isValid ? +this.o : NaN; 6763 } 6764 6765 /** 6766 * Get the short human name for the zone's current offset, for example "EST" or "EDT". 6767 * Defaults to the system's locale if no locale has been specified 6768 * @type {string} 6769 */ 6770 get offsetNameShort() { 6771 if (this.isValid) { 6772 return this.zone.offsetName(this.ts, { 6773 format: "short", 6774 locale: this.locale, 6775 }); 6776 } else { 6777 return null; 6778 } 6779 } 6780 6781 /** 6782 * Get the long human name for the zone's current offset, for example "Eastern Standard Time" or "Eastern Daylight Time". 6783 * Defaults to the system's locale if no locale has been specified 6784 * @type {string} 6785 */ 6786 get offsetNameLong() { 6787 if (this.isValid) { 6788 return this.zone.offsetName(this.ts, { 6789 format: "long", 6790 locale: this.locale, 6791 }); 6792 } else { 6793 return null; 6794 } 6795 } 6796 6797 /** 6798 * Get whether this zone's offset ever changes, as in a DST. 6799 * @type {boolean} 6800 */ 6801 get isOffsetFixed() { 6802 return this.isValid ? this.zone.isUniversal : null; 6803 } 6804 6805 /** 6806 * Get whether the DateTime is in a DST. 6807 * @type {boolean} 6808 */ 6809 get isInDST() { 6810 if (this.isOffsetFixed) { 6811 return false; 6812 } else { 6813 return ( 6814 this.offset > this.set({ month: 1, day: 1 }).offset || 6815 this.offset > this.set({ month: 5 }).offset 6816 ); 6817 } 6818 } 6819 6820 /** 6821 * Get those DateTimes which have the same local time as this DateTime, but a different offset from UTC 6822 * in this DateTime's zone. During DST changes local time can be ambiguous, for example 6823 * `2023-10-29T02:30:00` in `Europe/Berlin` can have offset `+01:00` or `+02:00`. 6824 * This method will return both possible DateTimes if this DateTime's local time is ambiguous. 6825 * @returns {DateTime[]} 6826 */ 6827 getPossibleOffsets() { 6828 if (!this.isValid || this.isOffsetFixed) { 6829 return [this]; 6830 } 6831 const dayMs = 86400000; 6832 const minuteMs = 60000; 6833 const localTS = objToLocalTS(this.c); 6834 const oEarlier = this.zone.offset(localTS - dayMs); 6835 const oLater = this.zone.offset(localTS + dayMs); 6836 6837 const o1 = this.zone.offset(localTS - oEarlier * minuteMs); 6838 const o2 = this.zone.offset(localTS - oLater * minuteMs); 6839 if (o1 === o2) { 6840 return [this]; 6841 } 6842 const ts1 = localTS - o1 * minuteMs; 6843 const ts2 = localTS - o2 * minuteMs; 6844 const c1 = tsToObj(ts1, o1); 6845 const c2 = tsToObj(ts2, o2); 6846 if ( 6847 c1.hour === c2.hour && 6848 c1.minute === c2.minute && 6849 c1.second === c2.second && 6850 c1.millisecond === c2.millisecond 6851 ) { 6852 return [clone(this, { ts: ts1 }), clone(this, { ts: ts2 })]; 6853 } 6854 return [this]; 6855 } 6856 6857 /** 6858 * Returns true if this DateTime is in a leap year, false otherwise 6859 * @example DateTime.local(2016).isInLeapYear //=> true 6860 * @example DateTime.local(2013).isInLeapYear //=> false 6861 * @type {boolean} 6862 */ 6863 get isInLeapYear() { 6864 return isLeapYear(this.year); 6865 } 6866 6867 /** 6868 * Returns the number of days in this DateTime's month 6869 * @example DateTime.local(2016, 2).daysInMonth //=> 29 6870 * @example DateTime.local(2016, 3).daysInMonth //=> 31 6871 * @type {number} 6872 */ 6873 get daysInMonth() { 6874 return daysInMonth(this.year, this.month); 6875 } 6876 6877 /** 6878 * Returns the number of days in this DateTime's year 6879 * @example DateTime.local(2016).daysInYear //=> 366 6880 * @example DateTime.local(2013).daysInYear //=> 365 6881 * @type {number} 6882 */ 6883 get daysInYear() { 6884 return this.isValid ? daysInYear(this.year) : NaN; 6885 } 6886 6887 /** 6888 * Returns the number of weeks in this DateTime's year 6889 * @see https://en.wikipedia.org/wiki/ISO_week_date 6890 * @example DateTime.local(2004).weeksInWeekYear //=> 53 6891 * @example DateTime.local(2013).weeksInWeekYear //=> 52 6892 * @type {number} 6893 */ 6894 get weeksInWeekYear() { 6895 return this.isValid ? weeksInWeekYear(this.weekYear) : NaN; 6896 } 6897 6898 /** 6899 * Returns the number of weeks in this DateTime's local week year 6900 * @example DateTime.local(2020, 6, {locale: 'en-US'}).weeksInLocalWeekYear //=> 52 6901 * @example DateTime.local(2020, 6, {locale: 'de-DE'}).weeksInLocalWeekYear //=> 53 6902 * @type {number} 6903 */ 6904 get weeksInLocalWeekYear() { 6905 return this.isValid 6906 ? weeksInWeekYear( 6907 this.localWeekYear, 6908 this.loc.getMinDaysInFirstWeek(), 6909 this.loc.getStartOfWeek() 6910 ) 6911 : NaN; 6912 } 6913 6914 /** 6915 * Returns the resolved Intl options for this DateTime. 6916 * This is useful in understanding the behavior of formatting methods 6917 * @param {Object} opts - the same options as toLocaleString 6918 * @return {Object} 6919 */ 6920 resolvedLocaleOptions(opts = {}) { 6921 const { locale, numberingSystem, calendar } = Formatter.create( 6922 this.loc.clone(opts), 6923 opts 6924 ).resolvedOptions(this); 6925 return { locale, numberingSystem, outputCalendar: calendar }; 6926 } 6927 6928 // TRANSFORM 6929 6930 /** 6931 * "Set" the DateTime's zone to UTC. Returns a newly-constructed DateTime. 6932 * 6933 * Equivalent to {@link DateTime#setZone}('utc') 6934 * @param {number} [offset=0] - optionally, an offset from UTC in minutes 6935 * @param {Object} [opts={}] - options to pass to `setZone()` 6936 * @return {DateTime} 6937 */ 6938 toUTC(offset = 0, opts = {}) { 6939 return this.setZone(FixedOffsetZone.instance(offset), opts); 6940 } 6941 6942 /** 6943 * "Set" the DateTime's zone to the host's local zone. Returns a newly-constructed DateTime. 6944 * 6945 * Equivalent to `setZone('local')` 6946 * @return {DateTime} 6947 */ 6948 toLocal() { 6949 return this.setZone(Settings.defaultZone); 6950 } 6951 6952 /** 6953 * "Set" the DateTime's zone to specified zone. Returns a newly-constructed DateTime. 6954 * 6955 * By default, the setter keeps the underlying time the same (as in, the same timestamp), but the new instance will report different local times and consider DSTs when making computations, as with {@link DateTime#plus}. You may wish to use {@link DateTime#toLocal} and {@link DateTime#toUTC} which provide simple convenience wrappers for commonly used zones. 6956 * @param {string|Zone} [zone='local'] - a zone identifier. As a string, that can be any IANA zone supported by the host environment, or a fixed-offset name of the form 'UTC+3', or the strings 'local' or 'utc'. You may also supply an instance of a {@link DateTime#Zone} class. 6957 * @param {Object} opts - options 6958 * @param {boolean} [opts.keepLocalTime=false] - If true, adjust the underlying time so that the local time stays the same, but in the target zone. You should rarely need this. 6959 * @return {DateTime} 6960 */ 6961 setZone(zone, { keepLocalTime = false, keepCalendarTime = false } = {}) { 6962 zone = normalizeZone(zone, Settings.defaultZone); 6963 if (zone.equals(this.zone)) { 6964 return this; 6965 } else if (!zone.isValid) { 6966 return DateTime.invalid(unsupportedZone(zone)); 6967 } else { 6968 let newTS = this.ts; 6969 if (keepLocalTime || keepCalendarTime) { 6970 const offsetGuess = zone.offset(this.ts); 6971 const asObj = this.toObject(); 6972 [newTS] = objToTS(asObj, offsetGuess, zone); 6973 } 6974 return clone(this, { ts: newTS, zone }); 6975 } 6976 } 6977 6978 /** 6979 * "Set" the locale, numberingSystem, or outputCalendar. Returns a newly-constructed DateTime. 6980 * @param {Object} properties - the properties to set 6981 * @example DateTime.local(2017, 5, 25).reconfigure({ locale: 'en-GB' }) 6982 * @return {DateTime} 6983 */ 6984 reconfigure({ locale, numberingSystem, outputCalendar } = {}) { 6985 const loc = this.loc.clone({ locale, numberingSystem, outputCalendar }); 6986 return clone(this, { loc }); 6987 } 6988 6989 /** 6990 * "Set" the locale. Returns a newly-constructed DateTime. 6991 * Just a convenient alias for reconfigure({ locale }) 6992 * @example DateTime.local(2017, 5, 25).setLocale('en-GB') 6993 * @return {DateTime} 6994 */ 6995 setLocale(locale) { 6996 return this.reconfigure({ locale }); 6997 } 6998 6999 /** 7000 * "Set" the values of specified units. Returns a newly-constructed DateTime. 7001 * You can only set units with this method; for "setting" metadata, see {@link DateTime#reconfigure} and {@link DateTime#setZone}. 7002 * 7003 * This method also supports setting locale-based week units, i.e. `localWeekday`, `localWeekNumber` and `localWeekYear`. 7004 * They cannot be mixed with ISO-week units like `weekday`. 7005 * @param {Object} values - a mapping of units to numbers 7006 * @example dt.set({ year: 2017 }) 7007 * @example dt.set({ hour: 8, minute: 30 }) 7008 * @example dt.set({ weekday: 5 }) 7009 * @example dt.set({ year: 2005, ordinal: 234 }) 7010 * @return {DateTime} 7011 */ 7012 set(values) { 7013 if (!this.isValid) return this; 7014 7015 const normalized = normalizeObject(values, normalizeUnitWithLocalWeeks); 7016 const { minDaysInFirstWeek, startOfWeek } = usesLocalWeekValues(normalized, this.loc); 7017 7018 const settingWeekStuff = 7019 !isUndefined(normalized.weekYear) || 7020 !isUndefined(normalized.weekNumber) || 7021 !isUndefined(normalized.weekday), 7022 containsOrdinal = !isUndefined(normalized.ordinal), 7023 containsGregorYear = !isUndefined(normalized.year), 7024 containsGregorMD = !isUndefined(normalized.month) || !isUndefined(normalized.day), 7025 containsGregor = containsGregorYear || containsGregorMD, 7026 definiteWeekDef = normalized.weekYear || normalized.weekNumber; 7027 7028 if ((containsGregor || containsOrdinal) && definiteWeekDef) { 7029 throw new ConflictingSpecificationError( 7030 "Can't mix weekYear/weekNumber units with year/month/day or ordinals" 7031 ); 7032 } 7033 7034 if (containsGregorMD && containsOrdinal) { 7035 throw new ConflictingSpecificationError("Can't mix ordinal dates with month/day"); 7036 } 7037 7038 let mixed; 7039 if (settingWeekStuff) { 7040 mixed = weekToGregorian( 7041 { ...gregorianToWeek(this.c, minDaysInFirstWeek, startOfWeek), ...normalized }, 7042 minDaysInFirstWeek, 7043 startOfWeek 7044 ); 7045 } else if (!isUndefined(normalized.ordinal)) { 7046 mixed = ordinalToGregorian({ ...gregorianToOrdinal(this.c), ...normalized }); 7047 } else { 7048 mixed = { ...this.toObject(), ...normalized }; 7049 7050 // if we didn't set the day but we ended up on an overflow date, 7051 // use the last day of the right month 7052 if (isUndefined(normalized.day)) { 7053 mixed.day = Math.min(daysInMonth(mixed.year, mixed.month), mixed.day); 7054 } 7055 } 7056 7057 const [ts, o] = objToTS(mixed, this.o, this.zone); 7058 return clone(this, { ts, o }); 7059 } 7060 7061 /** 7062 * Add a period of time to this DateTime and return the resulting DateTime 7063 * 7064 * Adding hours, minutes, seconds, or milliseconds increases the timestamp by the right number of milliseconds. Adding days, months, or years shifts the calendar, accounting for DSTs and leap years along the way. Thus, `dt.plus({ hours: 24 })` may result in a different time than `dt.plus({ days: 1 })` if there's a DST shift in between. 7065 * @param {Duration|Object|number} duration - The amount to add. Either a Luxon Duration, a number of milliseconds, the object argument to Duration.fromObject() 7066 * @example DateTime.now().plus(123) //~> in 123 milliseconds 7067 * @example DateTime.now().plus({ minutes: 15 }) //~> in 15 minutes 7068 * @example DateTime.now().plus({ days: 1 }) //~> this time tomorrow 7069 * @example DateTime.now().plus({ days: -1 }) //~> this time yesterday 7070 * @example DateTime.now().plus({ hours: 3, minutes: 13 }) //~> in 3 hr, 13 min 7071 * @example DateTime.now().plus(Duration.fromObject({ hours: 3, minutes: 13 })) //~> in 3 hr, 13 min 7072 * @return {DateTime} 7073 */ 7074 plus(duration) { 7075 if (!this.isValid) return this; 7076 const dur = Duration.fromDurationLike(duration); 7077 return clone(this, adjustTime(this, dur)); 7078 } 7079 7080 /** 7081 * Subtract a period of time to this DateTime and return the resulting DateTime 7082 * See {@link DateTime#plus} 7083 * @param {Duration|Object|number} duration - The amount to subtract. Either a Luxon Duration, a number of milliseconds, the object argument to Duration.fromObject() 7084 @return {DateTime} 7085 */ 7086 minus(duration) { 7087 if (!this.isValid) return this; 7088 const dur = Duration.fromDurationLike(duration).negate(); 7089 return clone(this, adjustTime(this, dur)); 7090 } 7091 7092 /** 7093 * "Set" this DateTime to the beginning of a unit of time. 7094 * @param {string} unit - The unit to go to the beginning of. Can be 'year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', or 'millisecond'. 7095 * @param {Object} opts - options 7096 * @param {boolean} [opts.useLocaleWeeks=false] - If true, use weeks based on the locale, i.e. use the locale-dependent start of the week 7097 * @example DateTime.local(2014, 3, 3).startOf('month').toISODate(); //=> '2014-03-01' 7098 * @example DateTime.local(2014, 3, 3).startOf('year').toISODate(); //=> '2014-01-01' 7099 * @example DateTime.local(2014, 3, 3).startOf('week').toISODate(); //=> '2014-03-03', weeks always start on Mondays 7100 * @example DateTime.local(2014, 3, 3, 5, 30).startOf('day').toISOTime(); //=> '00:00.000-05:00' 7101 * @example DateTime.local(2014, 3, 3, 5, 30).startOf('hour').toISOTime(); //=> '05:00:00.000-05:00' 7102 * @return {DateTime} 7103 */ 7104 startOf(unit, { useLocaleWeeks = false } = {}) { 7105 if (!this.isValid) return this; 7106 7107 const o = {}, 7108 normalizedUnit = Duration.normalizeUnit(unit); 7109 switch (normalizedUnit) { 7110 case "years": 7111 o.month = 1; 7112 // falls through 7113 case "quarters": 7114 case "months": 7115 o.day = 1; 7116 // falls through 7117 case "weeks": 7118 case "days": 7119 o.hour = 0; 7120 // falls through 7121 case "hours": 7122 o.minute = 0; 7123 // falls through 7124 case "minutes": 7125 o.second = 0; 7126 // falls through 7127 case "seconds": 7128 o.millisecond = 0; 7129 break; 7130 // no default, invalid units throw in normalizeUnit() 7131 } 7132 7133 if (normalizedUnit === "weeks") { 7134 if (useLocaleWeeks) { 7135 const startOfWeek = this.loc.getStartOfWeek(); 7136 const { weekday } = this; 7137 if (weekday < startOfWeek) { 7138 o.weekNumber = this.weekNumber - 1; 7139 } 7140 o.weekday = startOfWeek; 7141 } else { 7142 o.weekday = 1; 7143 } 7144 } 7145 7146 if (normalizedUnit === "quarters") { 7147 const q = Math.ceil(this.month / 3); 7148 o.month = (q - 1) * 3 + 1; 7149 } 7150 7151 return this.set(o); 7152 } 7153 7154 /** 7155 * "Set" this DateTime to the end (meaning the last millisecond) of a unit of time 7156 * @param {string} unit - The unit to go to the end of. Can be 'year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', or 'millisecond'. 7157 * @param {Object} opts - options 7158 * @param {boolean} [opts.useLocaleWeeks=false] - If true, use weeks based on the locale, i.e. use the locale-dependent start of the week 7159 * @example DateTime.local(2014, 3, 3).endOf('month').toISO(); //=> '2014-03-31T23:59:59.999-05:00' 7160 * @example DateTime.local(2014, 3, 3).endOf('year').toISO(); //=> '2014-12-31T23:59:59.999-05:00' 7161 * @example DateTime.local(2014, 3, 3).endOf('week').toISO(); // => '2014-03-09T23:59:59.999-05:00', weeks start on Mondays 7162 * @example DateTime.local(2014, 3, 3, 5, 30).endOf('day').toISO(); //=> '2014-03-03T23:59:59.999-05:00' 7163 * @example DateTime.local(2014, 3, 3, 5, 30).endOf('hour').toISO(); //=> '2014-03-03T05:59:59.999-05:00' 7164 * @return {DateTime} 7165 */ 7166 endOf(unit, opts) { 7167 return this.isValid 7168 ? this.plus({ [unit]: 1 }) 7169 .startOf(unit, opts) 7170 .minus(1) 7171 : this; 7172 } 7173 7174 // OUTPUT 7175 7176 /** 7177 * Returns a string representation of this DateTime formatted according to the specified format string. 7178 * **You may not want this.** See {@link DateTime#toLocaleString} for a more flexible formatting tool. For a table of tokens and their interpretations, see [here](https://moment.github.io/luxon/#/formatting?id=table-of-tokens). 7179 * Defaults to en-US if no locale has been specified, regardless of the system's locale. 7180 * @param {string} fmt - the format string 7181 * @param {Object} opts - opts to override the configuration options on this DateTime 7182 * @example DateTime.now().toFormat('yyyy LLL dd') //=> '2017 Apr 22' 7183 * @example DateTime.now().setLocale('fr').toFormat('yyyy LLL dd') //=> '2017 avr. 22' 7184 * @example DateTime.now().toFormat('yyyy LLL dd', { locale: "fr" }) //=> '2017 avr. 22' 7185 * @example DateTime.now().toFormat("HH 'hours and' mm 'minutes'") //=> '20 hours and 55 minutes' 7186 * @return {string} 7187 */ 7188 toFormat(fmt, opts = {}) { 7189 return this.isValid 7190 ? Formatter.create(this.loc.redefaultToEN(opts)).formatDateTimeFromString(this, fmt) 7191 : INVALID; 7192 } 7193 7194 /** 7195 * Returns a localized string representing this date. Accepts the same options as the Intl.DateTimeFormat constructor and any presets defined by Luxon, such as `DateTime.DATE_FULL` or `DateTime.TIME_SIMPLE`. 7196 * The exact behavior of this method is browser-specific, but in general it will return an appropriate representation 7197 * of the DateTime in the assigned locale. 7198 * Defaults to the system's locale if no locale has been specified 7199 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat 7200 * @param formatOpts {Object} - Intl.DateTimeFormat constructor options and configuration options 7201 * @param {Object} opts - opts to override the configuration options on this DateTime 7202 * @example DateTime.now().toLocaleString(); //=> 4/20/2017 7203 * @example DateTime.now().setLocale('en-gb').toLocaleString(); //=> '20/04/2017' 7204 * @example DateTime.now().toLocaleString(DateTime.DATE_FULL); //=> 'April 20, 2017' 7205 * @example DateTime.now().toLocaleString(DateTime.DATE_FULL, { locale: 'fr' }); //=> '28 août 2022' 7206 * @example DateTime.now().toLocaleString(DateTime.TIME_SIMPLE); //=> '11:32 AM' 7207 * @example DateTime.now().toLocaleString(DateTime.DATETIME_SHORT); //=> '4/20/2017, 11:32 AM' 7208 * @example DateTime.now().toLocaleString({ weekday: 'long', month: 'long', day: '2-digit' }); //=> 'Thursday, April 20' 7209 * @example DateTime.now().toLocaleString({ weekday: 'short', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }); //=> 'Thu, Apr 20, 11:27 AM' 7210 * @example DateTime.now().toLocaleString({ hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }); //=> '11:32' 7211 * @return {string} 7212 */ 7213 toLocaleString(formatOpts = DATE_SHORT, opts = {}) { 7214 return this.isValid 7215 ? Formatter.create(this.loc.clone(opts), formatOpts).formatDateTime(this) 7216 : INVALID; 7217 } 7218 7219 /** 7220 * Returns an array of format "parts", meaning individual tokens along with metadata. This is allows callers to post-process individual sections of the formatted output. 7221 * Defaults to the system's locale if no locale has been specified 7222 * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat/formatToParts 7223 * @param opts {Object} - Intl.DateTimeFormat constructor options, same as `toLocaleString`. 7224 * @example DateTime.now().toLocaleParts(); //=> [ 7225 * //=> { type: 'day', value: '25' }, 7226 * //=> { type: 'literal', value: '/' }, 7227 * //=> { type: 'month', value: '05' }, 7228 * //=> { type: 'literal', value: '/' }, 7229 * //=> { type: 'year', value: '1982' } 7230 * //=> ] 7231 */ 7232 toLocaleParts(opts = {}) { 7233 return this.isValid 7234 ? Formatter.create(this.loc.clone(opts), opts).formatDateTimeParts(this) 7235 : []; 7236 } 7237 7238 /** 7239 * Returns an ISO 8601-compliant string representation of this DateTime 7240 * @param {Object} opts - options 7241 * @param {boolean} [opts.suppressMilliseconds=false] - exclude milliseconds from the format if they're 0 7242 * @param {boolean} [opts.suppressSeconds=false] - exclude seconds from the format if they're 0 7243 * @param {boolean} [opts.includeOffset=true] - include the offset, such as 'Z' or '-04:00' 7244 * @param {boolean} [opts.extendedZone=false] - add the time zone format extension 7245 * @param {string} [opts.format='extended'] - choose between the basic and extended format 7246 * @example DateTime.utc(1983, 5, 25).toISO() //=> '1982-05-25T00:00:00.000Z' 7247 * @example DateTime.now().toISO() //=> '2017-04-22T20:47:05.335-04:00' 7248 * @example DateTime.now().toISO({ includeOffset: false }) //=> '2017-04-22T20:47:05.335' 7249 * @example DateTime.now().toISO({ format: 'basic' }) //=> '20170422T204705.335-0400' 7250 * @return {string} 7251 */ 7252 toISO({ 7253 format = "extended", 7254 suppressSeconds = false, 7255 suppressMilliseconds = false, 7256 includeOffset = true, 7257 extendedZone = false, 7258 } = {}) { 7259 if (!this.isValid) { 7260 return null; 7261 } 7262 7263 const ext = format === "extended"; 7264 7265 let c = toISODate(this, ext); 7266 c += "T"; 7267 c += toISOTime(this, ext, suppressSeconds, suppressMilliseconds, includeOffset, extendedZone); 7268 return c; 7269 } 7270 7271 /** 7272 * Returns an ISO 8601-compliant string representation of this DateTime's date component 7273 * @param {Object} opts - options 7274 * @param {string} [opts.format='extended'] - choose between the basic and extended format 7275 * @example DateTime.utc(1982, 5, 25).toISODate() //=> '1982-05-25' 7276 * @example DateTime.utc(1982, 5, 25).toISODate({ format: 'basic' }) //=> '19820525' 7277 * @return {string} 7278 */ 7279 toISODate({ format = "extended" } = {}) { 7280 if (!this.isValid) { 7281 return null; 7282 } 7283 7284 return toISODate(this, format === "extended"); 7285 } 7286 7287 /** 7288 * Returns an ISO 8601-compliant string representation of this DateTime's week date 7289 * @example DateTime.utc(1982, 5, 25).toISOWeekDate() //=> '1982-W21-2' 7290 * @return {string} 7291 */ 7292 toISOWeekDate() { 7293 return toTechFormat(this, "kkkk-'W'WW-c"); 7294 } 7295 7296 /** 7297 * Returns an ISO 8601-compliant string representation of this DateTime's time component 7298 * @param {Object} opts - options 7299 * @param {boolean} [opts.suppressMilliseconds=false] - exclude milliseconds from the format if they're 0 7300 * @param {boolean} [opts.suppressSeconds=false] - exclude seconds from the format if they're 0 7301 * @param {boolean} [opts.includeOffset=true] - include the offset, such as 'Z' or '-04:00' 7302 * @param {boolean} [opts.extendedZone=true] - add the time zone format extension 7303 * @param {boolean} [opts.includePrefix=false] - include the `T` prefix 7304 * @param {string} [opts.format='extended'] - choose between the basic and extended format 7305 * @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime() //=> '07:34:19.361Z' 7306 * @example DateTime.utc().set({ hour: 7, minute: 34, seconds: 0, milliseconds: 0 }).toISOTime({ suppressSeconds: true }) //=> '07:34Z' 7307 * @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime({ format: 'basic' }) //=> '073419.361Z' 7308 * @example DateTime.utc().set({ hour: 7, minute: 34 }).toISOTime({ includePrefix: true }) //=> 'T07:34:19.361Z' 7309 * @return {string} 7310 */ 7311 toISOTime({ 7312 suppressMilliseconds = false, 7313 suppressSeconds = false, 7314 includeOffset = true, 7315 includePrefix = false, 7316 extendedZone = false, 7317 format = "extended", 7318 } = {}) { 7319 if (!this.isValid) { 7320 return null; 7321 } 7322 7323 let c = includePrefix ? "T" : ""; 7324 return ( 7325 c + 7326 toISOTime( 7327 this, 7328 format === "extended", 7329 suppressSeconds, 7330 suppressMilliseconds, 7331 includeOffset, 7332 extendedZone 7333 ) 7334 ); 7335 } 7336 7337 /** 7338 * Returns an RFC 2822-compatible string representation of this DateTime 7339 * @example DateTime.utc(2014, 7, 13).toRFC2822() //=> 'Sun, 13 Jul 2014 00:00:00 +0000' 7340 * @example DateTime.local(2014, 7, 13).toRFC2822() //=> 'Sun, 13 Jul 2014 00:00:00 -0400' 7341 * @return {string} 7342 */ 7343 toRFC2822() { 7344 return toTechFormat(this, "EEE, dd LLL yyyy HH:mm:ss ZZZ", false); 7345 } 7346 7347 /** 7348 * Returns a string representation of this DateTime appropriate for use in HTTP headers. The output is always expressed in GMT. 7349 * Specifically, the string conforms to RFC 1123. 7350 * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 7351 * @example DateTime.utc(2014, 7, 13).toHTTP() //=> 'Sun, 13 Jul 2014 00:00:00 GMT' 7352 * @example DateTime.utc(2014, 7, 13, 19).toHTTP() //=> 'Sun, 13 Jul 2014 19:00:00 GMT' 7353 * @return {string} 7354 */ 7355 toHTTP() { 7356 return toTechFormat(this.toUTC(), "EEE, dd LLL yyyy HH:mm:ss 'GMT'"); 7357 } 7358 7359 /** 7360 * Returns a string representation of this DateTime appropriate for use in SQL Date 7361 * @example DateTime.utc(2014, 7, 13).toSQLDate() //=> '2014-07-13' 7362 * @return {string} 7363 */ 7364 toSQLDate() { 7365 if (!this.isValid) { 7366 return null; 7367 } 7368 return toISODate(this, true); 7369 } 7370 7371 /** 7372 * Returns a string representation of this DateTime appropriate for use in SQL Time 7373 * @param {Object} opts - options 7374 * @param {boolean} [opts.includeZone=false] - include the zone, such as 'America/New_York'. Overrides includeOffset. 7375 * @param {boolean} [opts.includeOffset=true] - include the offset, such as 'Z' or '-04:00' 7376 * @param {boolean} [opts.includeOffsetSpace=true] - include the space between the time and the offset, such as '05:15:16.345 -04:00' 7377 * @example DateTime.utc().toSQL() //=> '05:15:16.345' 7378 * @example DateTime.now().toSQL() //=> '05:15:16.345 -04:00' 7379 * @example DateTime.now().toSQL({ includeOffset: false }) //=> '05:15:16.345' 7380 * @example DateTime.now().toSQL({ includeZone: false }) //=> '05:15:16.345 America/New_York' 7381 * @return {string} 7382 */ 7383 toSQLTime({ includeOffset = true, includeZone = false, includeOffsetSpace = true } = {}) { 7384 let fmt = "HH:mm:ss.SSS"; 7385 7386 if (includeZone || includeOffset) { 7387 if (includeOffsetSpace) { 7388 fmt += " "; 7389 } 7390 if (includeZone) { 7391 fmt += "z"; 7392 } else if (includeOffset) { 7393 fmt += "ZZ"; 7394 } 7395 } 7396 7397 return toTechFormat(this, fmt, true); 7398 } 7399 7400 /** 7401 * Returns a string representation of this DateTime appropriate for use in SQL DateTime 7402 * @param {Object} opts - options 7403 * @param {boolean} [opts.includeZone=false] - include the zone, such as 'America/New_York'. Overrides includeOffset. 7404 * @param {boolean} [opts.includeOffset=true] - include the offset, such as 'Z' or '-04:00' 7405 * @param {boolean} [opts.includeOffsetSpace=true] - include the space between the time and the offset, such as '05:15:16.345 -04:00' 7406 * @example DateTime.utc(2014, 7, 13).toSQL() //=> '2014-07-13 00:00:00.000 Z' 7407 * @example DateTime.local(2014, 7, 13).toSQL() //=> '2014-07-13 00:00:00.000 -04:00' 7408 * @example DateTime.local(2014, 7, 13).toSQL({ includeOffset: false }) //=> '2014-07-13 00:00:00.000' 7409 * @example DateTime.local(2014, 7, 13).toSQL({ includeZone: true }) //=> '2014-07-13 00:00:00.000 America/New_York' 7410 * @return {string} 7411 */ 7412 toSQL(opts = {}) { 7413 if (!this.isValid) { 7414 return null; 7415 } 7416 7417 return `${this.toSQLDate()} ${this.toSQLTime(opts)}`; 7418 } 7419 7420 /** 7421 * Returns a string representation of this DateTime appropriate for debugging 7422 * @return {string} 7423 */ 7424 toString() { 7425 return this.isValid ? this.toISO() : INVALID; 7426 } 7427 7428 /** 7429 * Returns a string representation of this DateTime appropriate for the REPL. 7430 * @return {string} 7431 */ 7432 [Symbol.for("nodejs.util.inspect.custom")]() { 7433 if (this.isValid) { 7434 return `DateTime { ts: ${this.toISO()}, zone: ${this.zone.name}, locale: ${this.locale} }`; 7435 } else { 7436 return `DateTime { Invalid, reason: ${this.invalidReason} }`; 7437 } 7438 } 7439 7440 /** 7441 * Returns the epoch milliseconds of this DateTime. Alias of {@link DateTime#toMillis} 7442 * @return {number} 7443 */ 7444 valueOf() { 7445 return this.toMillis(); 7446 } 7447 7448 /** 7449 * Returns the epoch milliseconds of this DateTime. 7450 * @return {number} 7451 */ 7452 toMillis() { 7453 return this.isValid ? this.ts : NaN; 7454 } 7455 7456 /** 7457 * Returns the epoch seconds of this DateTime. 7458 * @return {number} 7459 */ 7460 toSeconds() { 7461 return this.isValid ? this.ts / 1000 : NaN; 7462 } 7463 7464 /** 7465 * Returns the epoch seconds (as a whole number) of this DateTime. 7466 * @return {number} 7467 */ 7468 toUnixInteger() { 7469 return this.isValid ? Math.floor(this.ts / 1000) : NaN; 7470 } 7471 7472 /** 7473 * Returns an ISO 8601 representation of this DateTime appropriate for use in JSON. 7474 * @return {string} 7475 */ 7476 toJSON() { 7477 return this.toISO(); 7478 } 7479 7480 /** 7481 * Returns a BSON serializable equivalent to this DateTime. 7482 * @return {Date} 7483 */ 7484 toBSON() { 7485 return this.toJSDate(); 7486 } 7487 7488 /** 7489 * Returns a JavaScript object with this DateTime's year, month, day, and so on. 7490 * @param opts - options for generating the object 7491 * @param {boolean} [opts.includeConfig=false] - include configuration attributes in the output 7492 * @example DateTime.now().toObject() //=> { year: 2017, month: 4, day: 22, hour: 20, minute: 49, second: 42, millisecond: 268 } 7493 * @return {Object} 7494 */ 7495 toObject(opts = {}) { 7496 if (!this.isValid) return {}; 7497 7498 const base = { ...this.c }; 7499 7500 if (opts.includeConfig) { 7501 base.outputCalendar = this.outputCalendar; 7502 base.numberingSystem = this.loc.numberingSystem; 7503 base.locale = this.loc.locale; 7504 } 7505 return base; 7506 } 7507 7508 /** 7509 * Returns a JavaScript Date equivalent to this DateTime. 7510 * @return {Date} 7511 */ 7512 toJSDate() { 7513 return new Date(this.isValid ? this.ts : NaN); 7514 } 7515 7516 // COMPARE 7517 7518 /** 7519 * Return the difference between two DateTimes as a Duration. 7520 * @param {DateTime} otherDateTime - the DateTime to compare this one to 7521 * @param {string|string[]} [unit=['milliseconds']] - the unit or array of units (such as 'hours' or 'days') to include in the duration. 7522 * @param {Object} opts - options that affect the creation of the Duration 7523 * @param {string} [opts.conversionAccuracy='casual'] - the conversion system to use 7524 * @example 7525 * var i1 = DateTime.fromISO('1982-05-25T09:45'), 7526 * i2 = DateTime.fromISO('1983-10-14T10:30'); 7527 * i2.diff(i1).toObject() //=> { milliseconds: 43807500000 } 7528 * i2.diff(i1, 'hours').toObject() //=> { hours: 12168.75 } 7529 * i2.diff(i1, ['months', 'days']).toObject() //=> { months: 16, days: 19.03125 } 7530 * i2.diff(i1, ['months', 'days', 'hours']).toObject() //=> { months: 16, days: 19, hours: 0.75 } 7531 * @return {Duration} 7532 */ 7533 diff(otherDateTime, unit = "milliseconds", opts = {}) { 7534 if (!this.isValid || !otherDateTime.isValid) { 7535 return Duration.invalid("created by diffing an invalid DateTime"); 7536 } 7537 7538 const durOpts = { locale: this.locale, numberingSystem: this.numberingSystem, ...opts }; 7539 7540 const units = maybeArray(unit).map(Duration.normalizeUnit), 7541 otherIsLater = otherDateTime.valueOf() > this.valueOf(), 7542 earlier = otherIsLater ? this : otherDateTime, 7543 later = otherIsLater ? otherDateTime : this, 7544 diffed = diff(earlier, later, units, durOpts); 7545 7546 return otherIsLater ? diffed.negate() : diffed; 7547 } 7548 7549 /** 7550 * Return the difference between this DateTime and right now. 7551 * See {@link DateTime#diff} 7552 * @param {string|string[]} [unit=['milliseconds']] - the unit or units units (such as 'hours' or 'days') to include in the duration 7553 * @param {Object} opts - options that affect the creation of the Duration 7554 * @param {string} [opts.conversionAccuracy='casual'] - the conversion system to use 7555 * @return {Duration} 7556 */ 7557 diffNow(unit = "milliseconds", opts = {}) { 7558 return this.diff(DateTime.now(), unit, opts); 7559 } 7560 7561 /** 7562 * Return an Interval spanning between this DateTime and another DateTime 7563 * @param {DateTime} otherDateTime - the other end point of the Interval 7564 * @return {Interval} 7565 */ 7566 until(otherDateTime) { 7567 return this.isValid ? Interval.fromDateTimes(this, otherDateTime) : this; 7568 } 7569 7570 /** 7571 * Return whether this DateTime is in the same unit of time as another DateTime. 7572 * Higher-order units must also be identical for this function to return `true`. 7573 * Note that time zones are **ignored** in this comparison, which compares the **local** calendar time. Use {@link DateTime#setZone} to convert one of the dates if needed. 7574 * @param {DateTime} otherDateTime - the other DateTime 7575 * @param {string} unit - the unit of time to check sameness on 7576 * @param {Object} opts - options 7577 * @param {boolean} [opts.useLocaleWeeks=false] - If true, use weeks based on the locale, i.e. use the locale-dependent start of the week; only the locale of this DateTime is used 7578 * @example DateTime.now().hasSame(otherDT, 'day'); //~> true if otherDT is in the same current calendar day 7579 * @return {boolean} 7580 */ 7581 hasSame(otherDateTime, unit, opts) { 7582 if (!this.isValid) return false; 7583 7584 const inputMs = otherDateTime.valueOf(); 7585 const adjustedToZone = this.setZone(otherDateTime.zone, { keepLocalTime: true }); 7586 return ( 7587 adjustedToZone.startOf(unit, opts) <= inputMs && inputMs <= adjustedToZone.endOf(unit, opts) 7588 ); 7589 } 7590 7591 /** 7592 * Equality check 7593 * Two DateTimes are equal if and only if they represent the same millisecond, have the same zone and location, and are both valid. 7594 * To compare just the millisecond values, use `+dt1 === +dt2`. 7595 * @param {DateTime} other - the other DateTime 7596 * @return {boolean} 7597 */ 7598 equals(other) { 7599 return ( 7600 this.isValid && 7601 other.isValid && 7602 this.valueOf() === other.valueOf() && 7603 this.zone.equals(other.zone) && 7604 this.loc.equals(other.loc) 7605 ); 7606 } 7607 7608 /** 7609 * Returns a string representation of a this time relative to now, such as "in two days". Can only internationalize if your 7610 * platform supports Intl.RelativeTimeFormat. Rounds down by default. 7611 * @param {Object} options - options that affect the output 7612 * @param {DateTime} [options.base=DateTime.now()] - the DateTime to use as the basis to which this time is compared. Defaults to now. 7613 * @param {string} [options.style="long"] - the style of units, must be "long", "short", or "narrow" 7614 * @param {string|string[]} options.unit - use a specific unit or array of units; if omitted, or an array, the method will pick the best unit. Use an array or one of "years", "quarters", "months", "weeks", "days", "hours", "minutes", or "seconds" 7615 * @param {boolean} [options.round=true] - whether to round the numbers in the output. 7616 * @param {number} [options.padding=0] - padding in milliseconds. This allows you to round up the result if it fits inside the threshold. Don't use in combination with {round: false} because the decimal output will include the padding. 7617 * @param {string} options.locale - override the locale of this DateTime
vendor: 11,479 bytes, lines 7618-7981
7618 * @param {string} options.numberingSystem - override the numberingSystem of this DateTime. The Intl system may choose not to honor this 7619 * @example DateTime.now().plus({ days: 1 }).toRelative() //=> "in 1 day" 7620 * @example DateTime.now().setLocale("es").toRelative({ days: 1 }) //=> "dentro de 1 dÃa" 7621 * @example DateTime.now().plus({ days: 1 }).toRelative({ locale: "fr" }) //=> "dans 23 heures" 7622 * @example DateTime.now().minus({ days: 2 }).toRelative() //=> "2 days ago" 7623 * @example DateTime.now().minus({ days: 2 }).toRelative({ unit: "hours" }) //=> "48 hours ago" 7624 * @example DateTime.now().minus({ hours: 36 }).toRelative({ round: false }) //=> "1.5 days ago" 7625 */ 7626 toRelative(options = {}) { 7627 if (!this.isValid) return null; 7628 const base = options.base || DateTime.fromObject({}, { zone: this.zone }), 7629 padding = options.padding ? (this < base ? -options.padding : options.padding) : 0; 7630 let units = ["years", "months", "days", "hours", "minutes", "seconds"]; 7631 let unit = options.unit; 7632 if (Array.isArray(options.unit)) { 7633 units = options.unit; 7634 unit = undefined; 7635 } 7636 return diffRelative(base, this.plus(padding), { 7637 ...options, 7638 numeric: "always", 7639 units, 7640 unit, 7641 }); 7642 } 7643 7644 /** 7645 * Returns a string representation of this date relative to today, such as "yesterday" or "next month". 7646 * Only internationalizes on platforms that supports Intl.RelativeTimeFormat. 7647 * @param {Object} options - options that affect the output 7648 * @param {DateTime} [options.base=DateTime.now()] - the DateTime to use as the basis to which this time is compared. Defaults to now. 7649 * @param {string} options.locale - override the locale of this DateTime 7650 * @param {string} options.unit - use a specific unit; if omitted, the method will pick the unit. Use one of "years", "quarters", "months", "weeks", or "days" 7651 * @param {string} options.numberingSystem - override the numberingSystem of this DateTime. The Intl system may choose not to honor this 7652 * @example DateTime.now().plus({ days: 1 }).toRelativeCalendar() //=> "tomorrow" 7653 * @example DateTime.now().setLocale("es").plus({ days: 1 }).toRelative() //=> ""mañana" 7654 * @example DateTime.now().plus({ days: 1 }).toRelativeCalendar({ locale: "fr" }) //=> "demain" 7655 * @example DateTime.now().minus({ days: 2 }).toRelativeCalendar() //=> "2 days ago" 7656 */ 7657 toRelativeCalendar(options = {}) { 7658 if (!this.isValid) return null; 7659 7660 return diffRelative(options.base || DateTime.fromObject({}, { zone: this.zone }), this, { 7661 ...options, 7662 numeric: "auto", 7663 units: ["years", "months", "days"], 7664 calendary: true, 7665 }); 7666 } 7667 7668 /** 7669 * Return the min of several date times 7670 * @param {...DateTime} dateTimes - the DateTimes from which to choose the minimum 7671 * @return {DateTime} the min DateTime, or undefined if called with no argument 7672 */ 7673 static min(...dateTimes) { 7674 if (!dateTimes.every(DateTime.isDateTime)) { 7675 throw new InvalidArgumentError("min requires all arguments be DateTimes"); 7676 } 7677 return bestBy(dateTimes, (i) => i.valueOf(), Math.min); 7678 } 7679 7680 /** 7681 * Return the max of several date times 7682 * @param {...DateTime} dateTimes - the DateTimes from which to choose the maximum 7683 * @return {DateTime} the max DateTime, or undefined if called with no argument 7684 */ 7685 static max(...dateTimes) { 7686 if (!dateTimes.every(DateTime.isDateTime)) { 7687 throw new InvalidArgumentError("max requires all arguments be DateTimes"); 7688 } 7689 return bestBy(dateTimes, (i) => i.valueOf(), Math.max); 7690 } 7691 7692 // MISC 7693 7694 /** 7695 * Explain how a string would be parsed by fromFormat() 7696 * @param {string} text - the string to parse 7697 * @param {string} fmt - the format the string is expected to be in (see description) 7698 * @param {Object} options - options taken by fromFormat() 7699 * @return {Object} 7700 */ 7701 static fromFormatExplain(text, fmt, options = {}) { 7702 const { locale = null, numberingSystem = null } = options, 7703 localeToUse = Locale.fromOpts({ 7704 locale, 7705 numberingSystem, 7706 defaultToEN: true, 7707 }); 7708 return explainFromTokens(localeToUse, text, fmt); 7709 } 7710 7711 /** 7712 * @deprecated use fromFormatExplain instead 7713 */ 7714 static fromStringExplain(text, fmt, options = {}) { 7715 return DateTime.fromFormatExplain(text, fmt, options); 7716 } 7717 7718 /** 7719 * Build a parser for `fmt` using the given locale. This parser can be passed 7720 * to {@link DateTime.fromFormatParser} to a parse a date in this format. This 7721 * can be used to optimize cases where many dates need to be parsed in a 7722 * specific format. 7723 * 7724 * @param {String} fmt - the format the string is expected to be in (see 7725 * description) 7726 * @param {Object} options - options used to set locale and numberingSystem 7727 * for parser 7728 * @returns {TokenParser} - opaque object to be used 7729 */ 7730 static buildFormatParser(fmt, options = {}) { 7731 const { locale = null, numberingSystem = null } = options, 7732 localeToUse = Locale.fromOpts({ 7733 locale, 7734 numberingSystem, 7735 defaultToEN: true, 7736 }); 7737 return new TokenParser(localeToUse, fmt); 7738 } 7739 7740 /** 7741 * Create a DateTime from an input string and format parser. 7742 * 7743 * The format parser must have been created with the same locale as this call. 7744 * 7745 * @param {String} text - the string to parse 7746 * @param {TokenParser} formatParser - parser from {@link DateTime.buildFormatParser} 7747 * @param {Object} opts - options taken by fromFormat() 7748 * @returns {DateTime} 7749 */ 7750 static fromFormatParser(text, formatParser, opts = {}) { 7751 if (isUndefined(text) || isUndefined(formatParser)) { 7752 throw new InvalidArgumentError( 7753 "fromFormatParser requires an input string and a format parser" 7754 ); 7755 } 7756 const { locale = null, numberingSystem = null } = opts, 7757 localeToUse = Locale.fromOpts({ 7758 locale, 7759 numberingSystem, 7760 defaultToEN: true, 7761 }); 7762 7763 if (!localeToUse.equals(formatParser.locale)) { 7764 throw new InvalidArgumentError( 7765 `fromFormatParser called with a locale of ${localeToUse}, ` + 7766 `but the format parser was created for ${formatParser.locale}` 7767 ); 7768 } 7769 7770 const { result, zone, specificOffset, invalidReason } = formatParser.explainFromTokens(text); 7771 7772 if (invalidReason) { 7773 return DateTime.invalid(invalidReason); 7774 } else { 7775 return parseDataToDateTime( 7776 result, 7777 zone, 7778 opts, 7779 `format ${formatParser.format}`, 7780 text, 7781 specificOffset 7782 ); 7783 } 7784 } 7785 7786 // FORMAT PRESETS 7787 7788 /** 7789 * {@link DateTime#toLocaleString} format like 10/14/1983 7790 * @type {Object} 7791 */ 7792 static get DATE_SHORT() { 7793 return DATE_SHORT; 7794 } 7795 7796 /** 7797 * {@link DateTime#toLocaleString} format like 'Oct 14, 1983' 7798 * @type {Object} 7799 */ 7800 static get DATE_MED() { 7801 return DATE_MED; 7802 } 7803 7804 /** 7805 * {@link DateTime#toLocaleString} format like 'Fri, Oct 14, 1983' 7806 * @type {Object} 7807 */ 7808 static get DATE_MED_WITH_WEEKDAY() { 7809 return DATE_MED_WITH_WEEKDAY; 7810 } 7811 7812 /** 7813 * {@link DateTime#toLocaleString} format like 'October 14, 1983' 7814 * @type {Object} 7815 */ 7816 static get DATE_FULL() { 7817 return DATE_FULL; 7818 } 7819 7820 /** 7821 * {@link DateTime#toLocaleString} format like 'Tuesday, October 14, 1983' 7822 * @type {Object} 7823 */ 7824 static get DATE_HUGE() { 7825 return DATE_HUGE; 7826 } 7827 7828 /** 7829 * {@link DateTime#toLocaleString} format like '09:30 AM'. Only 12-hour if the locale is. 7830 * @type {Object} 7831 */ 7832 static get TIME_SIMPLE() { 7833 return TIME_SIMPLE; 7834 } 7835 7836 /** 7837 * {@link DateTime#toLocaleString} format like '09:30:23 AM'. Only 12-hour if the locale is. 7838 * @type {Object} 7839 */ 7840 static get TIME_WITH_SECONDS() { 7841 return TIME_WITH_SECONDS; 7842 } 7843 7844 /** 7845 * {@link DateTime#toLocaleString} format like '09:30:23 AM EDT'. Only 12-hour if the locale is. 7846 * @type {Object} 7847 */ 7848 static get TIME_WITH_SHORT_OFFSET() { 7849 return TIME_WITH_SHORT_OFFSET; 7850 } 7851 7852 /** 7853 * {@link DateTime#toLocaleString} format like '09:30:23 AM Eastern Daylight Time'. Only 12-hour if the locale is. 7854 * @type {Object} 7855 */ 7856 static get TIME_WITH_LONG_OFFSET() { 7857 return TIME_WITH_LONG_OFFSET; 7858 } 7859 7860 /** 7861 * {@link DateTime#toLocaleString} format like '09:30', always 24-hour. 7862 * @type {Object} 7863 */ 7864 static get TIME_24_SIMPLE() { 7865 return TIME_24_SIMPLE; 7866 } 7867 7868 /** 7869 * {@link DateTime#toLocaleString} format like '09:30:23', always 24-hour. 7870 * @type {Object} 7871 */ 7872 static get TIME_24_WITH_SECONDS() { 7873 return TIME_24_WITH_SECONDS; 7874 } 7875 7876 /** 7877 * {@link DateTime#toLocaleString} format like '09:30:23 EDT', always 24-hour. 7878 * @type {Object} 7879 */ 7880 static get TIME_24_WITH_SHORT_OFFSET() { 7881 return TIME_24_WITH_SHORT_OFFSET; 7882 } 7883 7884 /** 7885 * {@link DateTime#toLocaleString} format like '09:30:23 Eastern Daylight Time', always 24-hour. 7886 * @type {Object} 7887 */ 7888 static get TIME_24_WITH_LONG_OFFSET() { 7889 return TIME_24_WITH_LONG_OFFSET; 7890 } 7891 7892 /** 7893 * {@link DateTime#toLocaleString} format like '10/14/1983, 9:30 AM'. Only 12-hour if the locale is. 7894 * @type {Object} 7895 */ 7896 static get DATETIME_SHORT() { 7897 return DATETIME_SHORT; 7898 } 7899 7900 /** 7901 * {@link DateTime#toLocaleString} format like '10/14/1983, 9:30:33 AM'. Only 12-hour if the locale is. 7902 * @type {Object} 7903 */ 7904 static get DATETIME_SHORT_WITH_SECONDS() { 7905 return DATETIME_SHORT_WITH_SECONDS; 7906 } 7907 7908 /** 7909 * {@link DateTime#toLocaleString} format like 'Oct 14, 1983, 9:30 AM'. Only 12-hour if the locale is. 7910 * @type {Object} 7911 */ 7912 static get DATETIME_MED() { 7913 return DATETIME_MED; 7914 } 7915 7916 /** 7917 * {@link DateTime#toLocaleString} format like 'Oct 14, 1983, 9:30:33 AM'. Only 12-hour if the locale is. 7918 * @type {Object} 7919 */ 7920 static get DATETIME_MED_WITH_SECONDS() { 7921 return DATETIME_MED_WITH_SECONDS; 7922 } 7923 7924 /** 7925 * {@link DateTime#toLocaleString} format like 'Fri, 14 Oct 1983, 9:30 AM'. Only 12-hour if the locale is. 7926 * @type {Object} 7927 */ 7928 static get DATETIME_MED_WITH_WEEKDAY() { 7929 return DATETIME_MED_WITH_WEEKDAY; 7930 } 7931 7932 /** 7933 * {@link DateTime#toLocaleString} format like 'October 14, 1983, 9:30 AM EDT'. Only 12-hour if the locale is. 7934 * @type {Object} 7935 */ 7936 static get DATETIME_FULL() { 7937 return DATETIME_FULL; 7938 } 7939 7940 /** 7941 * {@link DateTime#toLocaleString} format like 'October 14, 1983, 9:30:33 AM EDT'. Only 12-hour if the locale is. 7942 * @type {Object} 7943 */ 7944 static get DATETIME_FULL_WITH_SECONDS() { 7945 return DATETIME_FULL_WITH_SECONDS; 7946 } 7947 7948 /** 7949 * {@link DateTime#toLocaleString} format like 'Friday, October 14, 1983, 9:30 AM Eastern Daylight Time'. Only 12-hour if the locale is. 7950 * @type {Object} 7951 */ 7952 static get DATETIME_HUGE() { 7953 return DATETIME_HUGE; 7954 } 7955 7956 /** 7957 * {@link DateTime#toLocaleString} format like 'Friday, October 14, 1983, 9:30:33 AM Eastern Daylight Time'. Only 12-hour if the locale is. 7958 * @type {Object} 7959 */ 7960 static get DATETIME_HUGE_WITH_SECONDS() { 7961 return DATETIME_HUGE_WITH_SECONDS; 7962 } 7963} 7964 7965/** 7966 * @private 7967 */ 7968function friendlyDateTime(dateTimeish) { 7969 if (DateTime.isDateTime(dateTimeish)) { 7970 return dateTimeish; 7971 } else if (dateTimeish && dateTimeish.valueOf && isNumber(dateTimeish.valueOf())) { 7972 return DateTime.fromJSDate(dateTimeish); 7973 } else if (dateTimeish && typeof dateTimeish === "object") { 7974 return DateTime.fromObject(dateTimeish); 7975 } else { 7976 throw new InvalidArgumentError( 7977 `Unknown datetime argument: ${dateTimeish}, of type ${typeof dateTimeish}` 7978 ); 7979 } 7980} 7981
7982const VERSION = "3.5.0"; 7983 7984export { DateTime, Duration, FixedOffsetZone, IANAZone, Info, Interval, InvalidZone, Settings, SystemZone, VERSION, Zone }; 7985//# sourceMappingURL=luxon.js-241e61568d0a7bdb918f8f1f9fba6936.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.