PageSourceSearch

https://www.tourismebretagne.com/app/dist/crt-bretagne/addons/wood…/code/es-modules/Core/Time.js

js tourismebretagne.com collected 2026-10-02 05:19:32 UTC 36,613 bytes, 960 lines download raw bytes

1/* *
2 *
3 *  (c) 2010-2024 Torstein Honsi
4 *
5 *  License: www.highcharts.com/license
6 *
7 *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
8 *
9 * */
10'use strict';
11import H from './Globals.js';
12const { pageLang, win } = H;
13import U from './Utilities.js';
14const { defined, error, extend, isNumber, isObject, isString, merge, objectEach, pad, splat, timeUnits, ucfirst } = U;
15/* *
16 *
17 *  Constants
18 *
19 * */
20// To do: Remove this when we no longer need support for Safari < v14.1
21const hasOldSafariBug = H.isSafari &&
22    win.Intl &&
23    !win.Intl.DateTimeFormat.prototype.formatRange;
24const isDateTimeFormatOptions = (obj) => obj.main === void 0;
25// We use the Spanish locale for internal weekday handling because it uses
26// unique letters for narrow weekdays
27const spanishWeekdayIndex = (weekday) => ['D', 'L', 'M', 'X', 'J', 'V', 'S'].indexOf(weekday);
28/* *
29 *
30 *  Class
31 *
32 * */
33/* eslint-disable no-invalid-this, valid-jsdoc */
34/**
35 * The Time class. Time settings are applied in general for each page using
36 * `Highcharts.setOptions`, or individually for each Chart item through the
37 * [time](https://api.highcharts.com/highcharts/time) options set.
38 *
39 * The Time object is available from {@link Highcharts.Chart#time}, which refers
40 * to  `Highcharts.time` unless individual time settings are applied for each
41 * chart.
42 *
43 * When configuring time settings for individual chart instances, be aware that
44 * using `Highcharts.dateFormat` or `Highcharts.time.dateFormat` within
45 * formatter callbacks relies on the global time object, which applies the
46 * global language and time zone settings. To ensure charts with local time
47 * settings function correctly, use `chart.time.dateFormat? instead. However,
48 * the recommended best practice is to use `setOptions` to define global time
49 * settings unless specific configurations are needed for each chart.
50 *
51 * @example
52 * // Apply time settings globally
53 * Highcharts.setOptions({
54 *     time: {
55 *         timezone: 'Europe/London'
56 *     }
57 * });
58 *
59 * // Apply time settings by instance
60 * const chart = Highcharts.chart('container', {
61 *     time: {
62 *         timezone: 'America/New_York'
63 *     },
64 *     series: [{
65 *         data: [1, 4, 3, 5]
66 *     }]
67 * });
68 *
69 * // Use the Time object of a chart instance
70 * console.log(
71 *        'Current time in New York',
72 *        chart.time.dateFormat('%Y-%m-%d %H:%M:%S', Date.now())
73 * );
74 *
75 * // Standalone use
76 * const time = new Highcharts.Time({
77 *    timezone: 'America/New_York'
78 * });
79 * const s = time.dateFormat('%Y-%m-%d %H:%M:%S', Date.UTC(2020, 0, 1));
80 * console.log(s); // => 2019-12-31 19:00:00
81 *
82 * @since 6.0.5
83 *
84 * @class
85 * @name Highcharts.Time
86 *
87 * @param {Highcharts.TimeOptions} [options] Time options as defined in
88 * [chart.options.time](/highcharts/time).
89 */
90class Time {
91    /* *
92     *
93     *  Constructors
94     *
95     * */
96    constructor(options) {
97        /* *
98         *
99         *  Properties
100         *
101         * */
102        this.options = {
103            timezone: 'UTC'
104        };
105        this.variableTimezone = false;
106        this.Date = win.Date;
107        this.update(options);
108    }
109    /* *
110     *
111     *  Functions
112     *
113     * */
114    /**
115     * Update the Time object with current options. It is called internally on
116     * initializing Highcharts, after running `Highcharts.setOptions` and on
117     * `Chart.update`.
118     *
119     * @private
120     * @function Highcharts.Time#update
121     *
122     * @param {Highcharts.TimeOptions} [options]
123     *
124     */
125    update(options = {}) {
126        this.dTLCache = {};
127        this.options = options = merge(true, this.options, options);
128        const { timezoneOffset, useUTC } = options;
129        // Allow using a different Date class
130        this.Date = options.Date || win.Date || Date;
131        // Assign the time zone. Handle the legacy, deprecated `useUTC` option.
132        let timezone = options.timezone;
133        if (defined(useUTC)) {
134            timezone = useUTC ? 'UTC' : void 0;
135        }
136        // The Etc/GMT time zones do not support offsets with half-hour
137        // resolutions
138        if (timezoneOffset && timezoneOffset % 60 === 0) {
vendor: 5,986 bytes, lines 139-304
139            timezone = 'Etc/GMT' + ((timezoneOffset > 0 ? '+' : '')) + timezoneOffset / 60;
140        }
141        /*
142         * The time object has options allowing for variable time zones, meaning
143         * the axis ticks or series data needs to consider this.
144         */
145        this.variableTimezone = timezone !== 'UTC' &&
146            timezone?.indexOf('Etc/GMT') !== 0;
147        this.timezone = timezone;
148        // Assign default time formats from locale strings
149        ['months', 'shortMonths', 'weekdays', 'shortWeekdays'].forEach((name) => {
150            const isMonth = /months/i.test(name), isShort = /short/.test(name), options = { timeZone: 'UTC' };
151            options[isMonth ? 'month' : 'weekday'] = isShort ? 'short' : 'long';
152            this[name] = (isMonth ?
153                [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] :
154                [3, 4, 5, 6, 7, 8, 9]).map((position) => this.dateFormat(options, (isMonth ? 31 : 1) * 24 * 36e5 * position));
155        });
156    }
157    /**
158     * Get a date in terms of numbers (year, month, day etc) for further
159     * processing. Takes the current `timezone` setting into account. Inverse of
160     * `makeTime` and the native `Date` constructor and `Date.UTC`.
161     *
162     * The date is returned in array format with the following indices:
163     *
164     * 0: year,
165     * 1: month (zero based),
166     * 2: day,
167     * 3: hours,
168     * 4: minutes,
169     * 5: seconds,
170     * 6: milliseconds,
171     * 7: weekday (Sunday as 0)
172     *
173     * @function Highcharts.Time#toParts
174     *
175     * @param {number|Date} [timestamp]
176     *                 The timestamp in milliseconds since January 1st 1970.
177     *                 A Date object is also accepted.
178     *
179     * @return {Array<number>} The date parts in array format.
180     */
181    toParts(timestamp) {
182        const [weekday, dayOfMonth, month, year, hours, minutes, seconds] = this.dateTimeFormat({
183            weekday: 'narrow',
184            day: 'numeric',
185            month: 'numeric',
186            year: 'numeric',
187            hour: 'numeric',
188            minute: 'numeric',
189            second: 'numeric'
190        }, timestamp, 'es')
191            .split(/(?:, |\/|:)/g);
192        return [
193            year,
194            +month - 1,
195            dayOfMonth,
196            hours,
197            minutes,
198            seconds,
199            // Milliseconds
200            Math.floor(Number(timestamp) || 0) % 1000,
201            // Weekday index
202            spanishWeekdayIndex(weekday)
203        ].map(Number);
204    }
205    /**
206     * Shorthand to get a cached `Intl.DateTimeFormat` instance.
207     */
208    dateTimeFormat(options, timestamp, locale = this.options.locale || pageLang) {
209        const cacheKey = JSON.stringify(options) + locale;
210        if (isString(options)) {
211            options = this.str2dtf(options);
212        }
213        let dTL = this.dTLCache[cacheKey];
214        if (!dTL) {
215            options.timeZone ?? (options.timeZone = this.timezone);
216            try {
217                dTL = new Intl.DateTimeFormat(locale, options);
218            }
219            catch (e) {
220                if (/Invalid time zone/i.test(e.message)) {
221                    error(34);
222                    options.timeZone = 'UTC';
223                    dTL = new Intl.DateTimeFormat(locale, options);
224                }
225                else {
226                    error(e.message, false);
227                }
228            }
229        }
230        this.dTLCache[cacheKey] = dTL;
231        return dTL?.format(timestamp) || '';
232    }
233    /**
234     * Take a locale-aware string format and return a full DateTimeFormat in
235     * object form.
236     */
237    str2dtf(s, dtf = {}) {
238        const mapping = {
239            L: { fractionalSecondDigits: 3 },
240            S: { second: '2-digit' },
241            M: { minute: 'numeric' },
242            H: { hour: '2-digit' },
243            k: { hour: 'numeric' },
244            E: { weekday: 'narrow' },
245            a: { weekday: 'short' },
246            A: { weekday: 'long' },
247            d: { day: '2-digit' },
248            e: { day: 'numeric' },
249            b: { month: 'short' },
250            B: { month: 'long' },
251            m: { month: '2-digit' },
252            o: { month: 'numeric' },
253            y: { year: '2-digit' },
254            Y: { year: 'numeric' }
255        };
256        Object.keys(mapping).forEach((key) => {
257            if (s.indexOf(key) !== -1) {
258                extend(dtf, mapping[key]);
259            }
260        });
261        return dtf;
262    }
263    /**
264     * Make a time and returns milliseconds. Similar to `Date.UTC`, but takes
265     * the current `timezone` setting into account.
266     *
267     * @function Highcharts.Time#makeTime
268     *
269     * @param {number} year
270     *        The year
271     *
272     * @param {number} month
273     *        The month. Zero-based, so January is 0.
274     *
275     * @param {number} [date=1]
276     *        The day of the month
277     *
278     * @param {number} [hours=0]
279     *        The hour of the day, 0-23.
280     *
281     * @param {number} [minutes=0]
282     *        The minutes
283     *
284     * @param {number} [seconds=0]
285     *        The seconds
286     *
287     * @return {number}
288     *         The time in milliseconds since January 1st 1970.
289     */
290    makeTime(year, month, date = 1, hours = 0, minutes, seconds, milliseconds) {
291        // eslint-disable-next-line new-cap
292        let d = this.Date.UTC(year, month, date, hours, minutes || 0, seconds || 0, milliseconds || 0);
293        if (this.timezone !== 'UTC') {
294            const offset = this.getTimezoneOffset(d);
295            d += offset;
296            // Adjustments close to DST transitions
297            if (
298            // Optimize for speed by limiting the number of calls to
299            // `getTimezoneOffset`. According to
300            // https://en.wikipedia.org/wiki/Daylight_saving_time_by_country,
301            // DST change may only occur in these months.
302            [2, 3, 8, 9, 10, 11].indexOf(month) !== -1 &&
303                // DST transitions occur only in the night-time
304                (hours < 5 || hours >
vendor: 4,215 bytes, lines 304-399
304 20)) {
305                const newOffset = this.getTimezoneOffset(d);
306                if (offset !== newOffset) {
307                    d += newOffset - offset;
308                    // A special case for transitioning from summer time to winter
309                    // time. When the clock is set back, the same time is repeated
310                    // twice, i.e. 02:30 am is repeated since the clock is set back
311                    // from 3 am to 2 am. We need to make the same time as local
312                    // Date does.
313                }
314                else if (offset - 36e5 === this.getTimezoneOffset(d - 36e5) &&
315                    !hasOldSafariBug) {
316                    d -= 36e5;
317                }
318            }
319        }
320        return d;
321    }
322    /**
323     * Parse a datetime string. Unless the string contains time zone
324     * information, apply the current `timezone` from options. If the argument
325     * is a number, return it.
326     *
327     * @function Highcharts.Time#parse
328     * @param    {string|number|undefined} s The datetime string to parse
329     * @return   {number|undefined}          Parsed JavaScript timestamp
330     */
331    parse(s) {
332        if (!isString(s)) {
333            return s ?? void 0;
334        }
335        s = s
336            // Firefox fails on YYYY/MM/DD
337            .replace(/\//g, '-')
338            // Replace some non-standard notations
339            .replace(/(GMT|UTC)/, '');
340        // Extend shorthand hour timezone offset like +02
341        // .replace(/([+-][0-9]{2})$/, '$1:00');
342        // Check if the string has time zone information
343        const hasTimezone = s.indexOf('Z') > -1 ||
344            /([+-][0-9]{2}):?[0-9]{2}$/.test(s), isYYYYMMDD = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/.test(s);
345        if (!hasTimezone && !isYYYYMMDD) {
346            s += 'Z';
347        }
348        const ts = Date.parse(s);
349        if (isNumber(ts)) {
350            // Unless the string contains time zone information, convert from
351            // the local time result of `Date.parse` via UTC into the current
352            // timezone of the time object.
353            return ts + ((!hasTimezone || isYYYYMMDD) ?
354                this.getTimezoneOffset(ts) :
355                0);
356        }
357    }
358    /**
359     * Get the time zone offset based on the current timezone information as
360     * set in the global options.
361     *
362     * @function Highcharts.Time#getTimezoneOffset
363     *
364     * @param {number} timestamp
365     *        The JavaScript timestamp to inspect.
366     *
367     * @return {number}
368     *         The timezone offset in minutes compared to UTC.
369     */
370    getTimezoneOffset(timestamp) {
371        if (this.timezone !== 'UTC') {
372            // eslint-disable-next-line @typescript-eslint/no-unused-vars
373            const [date, gmt, hours, colon, minutes = 0] = this.dateTimeFormat({ timeZoneName: 'shortOffset' }, timestamp, 'en')
374                .split(/(GMT|:)/)
375                .map(Number), offset = -(hours + minutes / 60) * 60 * 60000;
376            // Possible future NaNs stop here
377            if (isNumber(offset)) {
378                return offset;
379            }
380        }
381        return 0;
382    }
383    /**
384     * Formats a JavaScript date timestamp (milliseconds since January 1 1970)
385     * into a human readable date string.
386     *
387     * The `format` parameter accepts two types of values:
388     * - An object containing settings that are passed directly on to
389     *   [Intl.DateTimeFormat.prototype.format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/format).
390     * - A format string containing either individual or locale-aware format
391     *   keys. **Individual keys**, for example `%Y-%m-%d`, are listed below.
392     *   **Locale-aware keys** are grouped by square brackets, for example
393     *   `%[Ymd]`. The order of keys within the square bracket doesn't affect
394     *   the output, which is determined by the locale. See example below.
395     *   Internally, the locale-aware format keys are just a shorthand for the
396     *   full object formats, but are particularly practical in
397     *   [templating](https://www.highcharts.com/docs/chart-concepts/templating)
398     *   where full object definitions are not an option.
399     *
400     * The available string format keys are listed below. Additional formats can
401     * be given in the {@link Highcharts.dateFormats} hook.
402     *
403     * Supported format keys:
404     * | Key  | Description                     | Notes on locale-aware format |
405     * -------|----------------------------------------------|-------|
406     * | `%A` | Long weekday, like 'Monday'                  |       |
407     * | `%a` | Short weekday, like 'Mon'                    |       |
408     * | `%E` | Narrow weekday, single character             |       |
409     * | `%d` | Two digit day of the month, 01 to 31         |       |
410     * | `%e` | Day of the month, 1 through 31               |       |
411     * | `%w` | Day of the week, 0 through 6                 | N/A   |
412     * | `%b` | Short month, like 'Jan'                      |       |
413     * | `%B` | Long month, like 'January'                   |       |
414     * | `%m` | Two digit month number, 01 through 12        |       |
415     * | `%o` | Month number, 1 through 12                   |       |
416     * | `%y` | Two digits year, like 24 for 2024            |       |
417     * | `%Y` | Four digits year, like 2024                  |       |
418     * | `%H` | Two digits hours in 24h format, 00 through 23 | Depending on the locale, 12h format may be instered. |
419     * | `%k` | Hours in 24h format, 0 through 23            | Depending on the locale, 12h format may be instered. |
420     * | `%I` | Two digits hours in 12h format, 00 through 11 | N/A. The locale determines the hour format. |
421     * | `%l` | Hours in 12h format, 1 through 12            | N/A. The locale determines the hour format. |
422     * | `%M` | Two digits minutes, 00 through 59            |       |
423     * | `%p` | Upper case AM or PM                          | N/A. The locale determines whether to add AM and PM. |
424     * | `%P` | Lower case AM or PM                          | N/A. The locale determines whether to add AM and PM. |
425     * | `%S` | Two digits seconds, 00 through 59            |       |
426     * | `%L` | Milliseconds (naming from Ruby)              |       |
427     *
428     * @example
429     * // Object format, US English
430     * const time1 = new Highcharts.Time({ locale: 'en-US' });
431     * console.log(
432     *     time1.dateFormat({
433     *         day: 'numeric',
434     *         month: 'short',
435     *         year: 'numeric',
436     *         hour: 'numeric',
437     *         minute: 'numeric'
438     *     }, Date.UTC(2024, 11, 31))
439     * ); // => Dec 31, 2024, 12:00 AM
440     *
441     * // Object format, British English
442     * const time2 = new Highcharts.Time({ locale: 'en-GB' });
443     * console.log(
444     *     time2.dateFormat({
445     *         day: 'numeric',
446     *         month: 'short',
447     *         year: 'numeric',
448     *         hour: 'numeric',
449     *         minute: 'numeric'
450     *     }, Date.UTC(2024, 11, 31))
451     * ); // => 31 Dec 2024, 00:00
452     *
453     * // Individual key string replacement
454     * const time3 = new Highcharts.Time();
455     * console.log(
456     *     time3.dateFormat('%Y-%m-%d %H:%M:%S', Date.UTC(2024, 11, 31))
457     * ); // => 2024-12-31 00:00:00
458     *
459     * // Locale-aware keys, US English
460     * const time4 = new Highcharts.Time({ locale: 'en-US' });
461     * console.log(
462     *     time4.dateFormat('%[YebHM]', Date.UTC(2024, 11, 31))
463     * ); // => Dec 31, 2024, 12:00 AM
464     *
465     * // Locale-aware keys, British English
466     * const time5 = new Highcharts.Time({ locale: 'en-GB' });
467     * console.log(
468     *     time5.dateFormat('%[YebHM]', Date.UTC(2024, 11, 31))
469     * ); // => 31 Dec 2024, 00:00
470     *
471     * // Mixed locale-aware and individual keys
472     * console.log(
473     *     time5.dateFormat('%[Yeb], %H:%M', Date.UTC(2024, 11, 31))
474     * ); // => 31 Dec 2024, 00:00
475     *
476     * @function Highcharts.Time#dateFormat
477     *
478     * @param {string|Highcharts.DateTimeFormatOptions} format
479     *        The desired string format where various time representations are
480     *        prefixed with %, or an object representing the locale-aware format
481     *        options.
482     *
483     * @param {number} [timestamp]
484     *        The JavaScript timestamp.
485     *
486     * @param {boolean} [upperCaseFirst=false]
487     *        Upper case first letter in the return.
488     *
489     * @return {string}
490     *         The formatted date.
491     */
492    dateFormat(format, timestamp, upperCaseFirst) {
493        const lang = H.defaultOptions?.lang;
494        if (!defined(timestamp) || isNaN(timestamp)) {
vendor: 5,177 bytes, lines 495-612
495            return lang?.invalidDate || '';
496        }
497        format = format ?? '%Y-%m-%d %H:%M:%S';
498        // First, identify and replace locale-aware formats like %[Ymd]
499        if (isString(format)) {
500            const localeAwareRegex = /%\[([a-zA-Z]+)\]/g;
501            let match;
502            while ((match = localeAwareRegex.exec(format))) {
503                format = format.replace(match[0], this.dateTimeFormat(match[1], timestamp));
504            }
505        }
506        // Then, replace static formats like %Y, %m, %d etc.
507        if (isString(format) && format.indexOf('%') !== -1) {
508            const time = this, [fullYear, month, dayOfMonth, hours, minutes, seconds, milliseconds, weekday] = this.toParts(timestamp), langWeekdays = lang?.weekdays || this.weekdays, shortWeekdays = lang?.shortWeekdays || this.shortWeekdays, months = lang?.months || this.months, shortMonths = lang?.shortMonths || this.shortMonths, 
509            // List all format keys. Custom formats can be added from the
510            // outside.
511            replacements = extend({
512                // Day
513                // Short weekday, like 'Mon'
514                a: shortWeekdays ?
515                    shortWeekdays[weekday] :
516                    langWeekdays[weekday].substr(0, 3),
517                // Long weekday, like 'Monday'
518                A: langWeekdays[weekday],
519                // Two digit day of the month, 01 to 31
520                d: pad(dayOfMonth),
521                // Day of the month, 1 through 31
522                e: pad(dayOfMonth, 2, ' '),
523                // Day of the week, 0 through 6
524                w: weekday,
525                // Week (none implemented)
526                // 'W': weekNumber(),
527                // Month
528                // Short month, like 'Jan'
529                b: shortMonths[month],
530                // Long month, like 'January'
531                B: months[month],
532                // Two digit month number, 01 through 12
533                m: pad(month + 1),
534                // Month number, 1 through 12 (#8150)
535                o: month + 1,
536                // Year
537                // Two digits year, like 09 for 2009
538                y: fullYear.toString().substr(2, 2),
539                // Four digits year, like 2009
540                Y: fullYear,
541                // Time
542                // Two digits hours in 24h format, 00 through 23
543                H: pad(hours),
544                // Hours in 24h format, 0 through 23
545                k: hours,
546                // Two digits hours in 12h format, 00 through 11
547                I: pad((hours % 12) || 12),
548                // Hours in 12h format, 1 through 12
549                l: (hours % 12) || 12,
550                // Two digits minutes, 00 through 59
551                M: pad(minutes),
552                // Upper case AM or PM
553                p: hours < 12 ? 'AM' : 'PM',
554                // Lower case AM or PM
555                P: hours < 12 ? 'am' : 'pm',
556                // Two digits seconds, 00 through 59
557                S: pad(seconds),
558                // Milliseconds (naming from Ruby)
559                L: pad(milliseconds, 3)
560            }, H.dateFormats);
561            // Do the replaces
562            objectEach(replacements, function (val, key) {
563                if (isString(format)) {
564                    // Regex would do it in one line, but this is faster
565                    while (format.indexOf('%' + key) !== -1) {
566                        format = format.replace('%' + key, typeof val === 'function' ?
567                            val.call(time, timestamp) :
568                            val);
569                    }
570                }
571            });
572        }
573        else if (isObject(format)) {
574            const tzHours = (this.getTimezoneOffset(timestamp) || 0) /
575                (60000 * 60), timeZone = this.timezone || ('Etc/GMT' + (tzHours >= 0 ? '+' : '') + tzHours), { prefix = '', suffix = '' } = format;
576            format = prefix + this.dateTimeFormat(extend({ timeZone }, format), timestamp) + suffix;
577        }
578        // Optionally sentence-case the string and return
579        return upperCaseFirst ? ucfirst(format) : format;
580    }
581    /**
582     * Resolve legacy formats of dateTimeLabelFormats (strings and arrays) into
583     * an object.
584     * @private
585     * @param {string|Array<T>|Highcharts.Dictionary<T>} f
586     * General format description
587     * @return {Highcharts.Dictionary<T>}
588     * The object definition
589     */
590    resolveDTLFormat(f) {
591        if (!isObject(f, true)) { // Check for string or array
592            f = splat(f);
593            return {
594                main: f[0],
595                from: f[1],
596                to: f[2]
597            };
598        }
599        // Type-check DateTimeFormatOptions against DateTimeLabelFormatObject
600        if (isObject(f, true) && isDateTimeFormatOptions(f)) {
601            return { main: f };
602        }
603        return f;
604    }
605    /**
606     * Return an array with time positions distributed on round time values
607     * right and right after min and max. Used in datetime axes as well as for
608     * grouping data on a datetime axis.
609     *
610     * @function Highcharts.Time#getTimeTicks
611     *
612     * @param {Highcharts.TimeNormalizedObject}
612 normalizedInterval
613     *        The interval in axis values (ms) and the count
614     *
615     * @param {number} [min]
616     *        The minimum in axis values
617     *
618     * @param {number} [max]
619     *        The maximum in axis values
620     *
621     * @param {number} [startOfWeek=1]
622     *
623     * @return {Highcharts.AxisTickPositionsArray}
624     * Time positions
625     */
626    getTimeTicks(normalizedInterval, min, max, startOfWeek) {
627        const time = this, tickPositions = [], higherRanks = {}, { count = 1, unitRange } = normalizedInterval;
628        let [year, month, dayOfMonth, hours, minutes, seconds] = time.toParts(min), milliseconds = (min || 0) % 1000, variableDayLength;
629        startOfWeek ?? (startOfWeek = 1);
630        if (defined(min)) { // #1300
631            milliseconds = unitRange >= timeUnits.second ?
632                0 : // #3935
633                count * Math.floor(milliseconds / count);
634            if (unitRange >= timeUnits.second) { // Second
635                seconds = unitRange >= timeUnits.minute ?
636                    0 : // #3935
637                    count * Math.floor(seconds / count);
638            }
639            if (unitRange >= timeUnits.minute) { // Minute
640                minutes = unitRange >= timeUnits.hour ?
641                    0 :
642                    count * Math.floor(minutes / count);
643            }
644            if (unitRange >= timeUnits.hour) { // Hour
645                hours = unitRange >= timeUnits.day ?
646                    0 :
647                    count * Math.floor(hours / count);
648            }
649            if (unitRange >= timeUnits.day) { // Day
650                dayOfMonth = unitRange >= timeUnits.month ?
651                    1 :
652                    Math.max(1, count * Math.floor(dayOfMonth / count));
653            }
654            if (unitRange >= timeUnits.month) { // Month
655                month = unitRange >= timeUnits.year ? 0 :
656                    count * Math.floor(month / count);
657            }
658            if (unitRange >= timeUnits.year) { // Year
659                year -= year % count;
660            }
661            // Week is a special case that runs outside the hierarchy
662            if (unitRange === timeUnits.week) {
663                if (count) {
664                    min = time.makeTime(year, month, dayOfMonth, hours, minutes, seconds, milliseconds);
665                }
666                // Get start of current week, independent of count
667                const weekday = this.dateTimeFormat({
668                    timeZone: this.timezone,
669                    weekday: 'narrow'
670                }, min, 'es'), weekdayNo = spanishWeekdayIndex(weekday);
671                dayOfMonth += -weekdayNo + startOfWeek +
672                    // We don't want to skip days that are before
673                    // startOfWeek (#7051)
674                    (weekdayNo < startOfWeek ? -7 : 0);
675            }
676            min = time.makeTime(year, month, dayOfMonth, hours, minutes, seconds, milliseconds);
677            // Handle local timezone offset
678            if (time.variableTimezone && defined(max)) {
679                // Detect whether we need to take the DST crossover into
680                // consideration. If we're crossing over DST, the day length may
681                // be 23h or 25h and we need to compute the exact clock time for
682                // each tick instead of just adding hours. This comes at a cost,
683                // so first we find out if it is needed (#4951).
684                variableDayLength = (
685                // Long range, assume we're crossing over.
686                max - min > 4 * timeUnits.month ||
687                    // Short range, check if min and max are in different time
688                    // zones.
689                    time.getTimezoneOffset(min) !==
690                        time.getTimezoneOffset(max));
691            }
692            // Iterate and add tick positions at appropriate values
693            let t = min, i = 1;
694            while (t < max) {
695                tickPositions.push(t);
696                // Increase the years
697                if (unitRange === timeUnits.year) {
698                    t = time.makeTime(year + i * count, 0);
699                    // Increase the months
700                }
701                else if (unitRange === timeUnits.month) {
702                    t = time.makeTime(year, month + i * count);
703                    // If we're using local time, the interval is not fixed as it
704                    // jumps one hour at the DST crossover
705                }
706                else if (variableDayLength && (unitRange === timeUnits.day ||
707                    unitRange === timeUnits.week)) {
708                    t = time.makeTime(year, month, dayOfMonth +
709                        i * count * (unitRange === timeUnits.day ? 1 : 7));
710                }
711                else if (variableDayLength &&
712                    unitRange === timeUnits.hour &&
713                    count > 1) {
714                    // Make sure higher ranks are preserved across DST (#6797,
715                    // #7621)
716                    t = time.makeTime(year, month, dayOfMonth, hours + i * count);
717                    // Else, the interval is fixed and we use simple addition
718                }
719                else {
720                    t += unitRange * count;
721                }
722                i++;
723            }
724            // Push the last time
725            tickPositions.push(t);
726            // Handle higher ranks. Mark new days if the time is on midnight
727            // (#950, #1649, #1760, #3349). Use a reasonable dropout threshold
728            // to prevent looping over dense data grouping (#6156).
729            if (unitRange <= timeUnits.hour && tickPositions.length < 10000) {
730                tickPositions.forEach((t) => {
731                    if (
732                    // Speed optimization, no need to run dateFormat unless
733                    // we're on a full or half hour
734                    t % 1800000 === 0 &&
735                        // Check for local or global midnight
736                        time.dateFormat('%H%M%S%L', t) === '000000000') {
737                        higherRanks[t] = 'day';
738                    }
739                });
740            }
741        }
742        // Record information on the chosen unit - for dynamic label formatter
743        tickPositions.info = extend(normalizedInterval, {
744            higherRanks,
745            totalRange: unitRange * count
746        });
747        return tickPositions;
748    }
749    /**
750     * Get the optimal date format for a point, based on a range.
751     *
752     * @private
753     * @function Highcharts.Time#getDateFormat
754     *
755     * @param {number} range
756     *        The time range
757     *
758     * @param {number} timestamp
759     *        The timestamp of the date
760     *
761     * @param {number} startOfWeek
762     *        An integer representing the first day of the week, where 0 is
763     *        Sunday.
764     *
765     * @param {Highcharts.Dictionary<string>} dateTimeLabelFormats
766     *        A map of time units to formats.
767     *
768     * @return {string}
769     *         The optimal date format for a point.
770     */
771    getDateFormat(range, timestamp, startOfWeek, dateTimeLabelFormats) {
772        const dateStr = this.dateFormat('%m-%d %H:%M:%S.%L', timestamp), blank = '01-01 00:00:00.000', strpos = {
773            millisecond: 15,
774            second: 12,
775            minute: 9,
776            hour: 6,
777            day: 3
778        };
779        let n = 'millisecond', 
780        // For sub-millisecond data, #4223
781        lastN = n;
782        for (n in timeUnits) { // eslint-disable-line guard-for-in
783            // If the range is exactly one week and we're looking at a
784            // Sunday/Monday, go for the week format
785            if (range === timeUnits.week &&
786                +this.dateFormat('%w', timestamp) === startOfWeek &&
787                dateStr.substr(6) === blank.substr(6)) {
788                n = 'week';
789                break;
790            }
791            // The first format that is too great for the range
792            if (timeUnits[n] > range) {
793                n = lastN;
794                break;
795            }
796            // If the point is placed every day at 23:59, we need to show
797            // the minutes as well. #2637.
798            if (strpos[n] &&
799                dateStr.substr(strpos[n]) !== blank.substr(strpos[n])) {
800                break;
801            }
802            // Weeks are outside the hierarchy, only apply them on
803            // Mondays/Sundays like in the first condition
804            if (n !== 'week') {
805                lastN = n;
806            }
807        }
808        return this.resolveDTLFormat(dateTimeLabelFormats[n]).main;
809    }
810}
811/* *
812 *
813 * Default export
814 *
815 * */
816export default Time;
817/* *
818 *
819 * API Declarations
820 *
821 * */
822/**
823 * Normalized interval.
824 *
825 * @interface Highcharts.TimeNormalizedObject
826 */ /**
827* The count.
828*
829* @name Highcharts.TimeNormalizedObject#count
830* @type {number|undefined}
831*/ /**
832* The interval in axis values (ms).
833*
834* @name Highcharts.TimeNormalizedObject#unitRange
835* @type {number}
836*/
837/**
838 * Function of an additional date format specifier.
839 *
840 * @callback Highcharts.TimeFormatCallbackFunction
841 *
842 * @param {number} timestamp
843 *        The time to format.
844 *
845 * @return {string}
846 *         The formatted portion of the date.
847 */
848/**
849 * Time ticks.
850 *
851 * @interface Highcharts.AxisTickPositionsArray
852 * @extends global.Array<number>
853 */ /**
854* @name Highcharts.AxisTickPositionsArray#info
855* @type {Highcharts.TimeTicksInfoObject|undefined}
856*/
857/**
858 * A callback to return the time zone offset for a given datetime. It
859 * takes the timestamp in terms of milliseconds since January 1 1970,
860 * and returns the timezone offset in minutes. This provides a hook
861 * for drawing time based charts in specific time zones using their
862 * local DST crossover dates, with the help of external libraries.
863 *
864 * @callback Highcharts.TimezoneOffsetCallbackFunction
865 *
866 * @param {number} timestamp
867 * Timestamp in terms of milliseconds since January 1 1970.
868 *
869 * @return {number}
870 * Timezone offset in minutes.
871 */
872/**
873 * Options for formatting dates and times using the [Intl.DateTimeFormat](
874 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat
875 * ) API, and extended with some custom options for Highcharts.
876 *
877 * @interface Highcharts.DateTimeFormatOptions
878 */ /**
879* The locale matching algorithm to use.
880*
881* @name Highcharts.DateTimeFormatOptions#localeMatcher
882* @type {string|undefined}
883*/ /**
884* The time zone to use. The default is the browser's default time zone.
885*
886* @name Highcharts.DateTimeFormatOptions#timeZone
887* @type {string|undefined}
888*/ /**
889* Whether to use 12-hour time (as opposed to 24-hour time).
890*
891* @name Highcharts.DateTimeFormatOptions#hour12
892* @type {'auto'|'always'|'never'|undefined}
893*/ /**
894* The format matching algorithm to use.
895*
896* @name Highcharts.DateTimeFormatOptions#formatMatcher
897* @type {string|undefined}
898*/ /**
899* The representation of the weekday.
900*
901* @name Highcharts.DateTimeFormatOptions#weekday
902* @type {'narrow'|'short'|'long'|undefined}
903*/ /**
904* The representation of the era.
905*
906* @name Highcharts.DateTimeFormatOptions#era
907* @type {'narrow'|'short'|'long'|undefined}
908*/ /**
909* The representation of the year.
910*
911* @name Highcharts.DateTimeFormatOptions#year
912* @type {'numeric'|'2-digit'|undefined}
913*/ /**
914* The representation of the month.
915* "narrow", "short", "long".
916*
917* @name Highcharts.DateTimeFormatOptions#month
918* @type {'numeric'|'2-digit'|'narrow'|'short'|'long'|undefined}
919*/ /**
920* The representation of the day.
921*
922* @name Highcharts.DateTimeFormatOptions#day
923* @type {'numeric'|'2-digit'|undefined}
924*/ /**
925* The representation of the hour.
926*
927* @name Highcharts.DateTimeFormatOptions#hour
928* @type {'numeric'|'2-digit'|undefined}
929*/ /**
930* The representation of the minute.
931*
932* @name Highcharts.DateTimeFormatOptions#minute
933* @type {'numeric'|'2-digit'|undefined}
934*/ /**
935* The representation of the second.
936*
937* @name Highcharts.DateTimeFormatOptions#second
938* @type {'numeric'|'2-digit'|undefined}
939*/ /**
940* The number of fractional digits to use. 3 means milliseconds.
941*
942* @name Highcharts.DateTimeFormatOptions#fractionalSecondDigits
943* @type {number|undefined}
944*/ /**
945* The representation of the time zone name.
946*
947* @name Highcharts.DateTimeFormatOptions#timeZoneName
948* @type {'short'|'long'|undefined}
949*/ /**
950* A prefix for the time string. Custom Highcharts option.
951*
952* @name Highcharts.DateTimeFormatOptions#prefix
953* @type {'string'|undefined}
954*/ /**
955* A suffix for the time string. Custom Highcharts option.
956*
957* @name Highcharts.DateTimeFormatOptions#suffix
958* @type {'string'|undefined}
959*/
960''; // Keeps doclets above in JS file

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.