konzen commented on code in PR #21739:
URL: https://github.com/apache/echarts/pull/21739#discussion_r3807451165


##########
src/util/time.ts:
##########
@@ -409,117 +480,545 @@ export function getUnitFromValue(
     }
 }
 
-// export function getUnitValue(
-//     value: number | Date,
-//     unit: TimeUnit,
-//     isUTC: boolean
-// ) : number {
-//     const date = zrUtil.isNumber(value)
-//         ? numberUtil.parseDate(value)
-//         : value;
-//     unit = unit || getUnitFromValue(value, isUTC);
-
-//     switch (unit) {
-//         case 'year':
-//             return date[fullYearGetterName(isUTC)]();
-//         case 'half-year':
-//             return date[monthGetterName(isUTC)]() >= 6 ? 1 : 0;
-//         case 'quarter':
-//             return Math.floor((date[monthGetterName(isUTC)]() + 1) / 4);
-//         case 'month':
-//             return date[monthGetterName(isUTC)]();
-//         case 'day':
-//             return date[dateGetterName(isUTC)]();
-//         case 'half-day':
-//             return date[hoursGetterName(isUTC)]() / 24;
-//         case 'hour':
-//             return date[hoursGetterName(isUTC)]();
-//         case 'minute':
-//             return date[minutesGetterName(isUTC)]();
-//         case 'second':
-//             return date[secondsGetterName(isUTC)]();
-//         case 'millisecond':
-//             return date[millisecondsGetterName(isUTC)]();
-//     }
-// }
-
 /**
  * e.g.,
  * If timeUnit is 'year', return the Jan 1st 00:00:00 000 of that year.
  * If timeUnit is 'day', return the 00:00:00 000 of that day.
  *
  * @return The input date.
  */
-export function roundTime(date: Date, timeUnit: PrimaryTimeUnit, isUTC: 
boolean): Date {
-    switch (timeUnit) {
-        case 'year':
-            date[monthSetterName(isUTC)](0);
-        case 'month':
-            date[dateSetterName(isUTC)](1);
-        case 'day':
-            date[hoursSetterName(isUTC)](0);
-        case 'hour':
-            date[minutesSetterName(isUTC)](0);
-        case 'minute':
-            date[secondsSetterName(isUTC)](0);
-        case 'second':
-            date[millisecondsSetterName(isUTC)](0);
+export function roundTime(
+    date: Date,
+    timeUnit: PrimaryTimeUnit,
+    timeZone: string
+): Date;
+/**
+ * @deprecated Pass a time zone string instead of the legacy `isUTC` boolean.
+ */
+export function roundTime(
+    date: Date,
+    timeUnit: PrimaryTimeUnit,
+    isUTC: boolean
+): Date;
+export function roundTime(
+    date: Date,
+    timeUnit: PrimaryTimeUnit,
+    timeZoneOrUTC: string | boolean
+): Date {
+    if (__DEV__ && typeof timeZoneOrUTC === 'boolean') {
+        deprecateReplaceLog('isUTC boolean parameter', 'timeZone string 
parameter', 'echarts.time.roundTime');
     }
+    date.setTime(roundTimeInTimeZone(
+        date.getTime(), timeUnit, normalizeTimeZone(timeZoneOrUTC)
+    ));
     return date;
 }
 
+function normalizeTimeZone(timeZoneOrUTC: string | boolean): string {
+    return typeof timeZoneOrUTC === 'string'
+        ? timeZoneOrUTC
+        : timeZoneOrUTC ? 'UTC' : getSystemTimeZone();
+}
+
+/**
+ * @deprecated Use `getTimeZoneParts` to read values in a specific time zone.
+ */
 export function fullYearGetterName(isUTC: boolean) {
     return isUTC ? 'getUTCFullYear' : 'getFullYear';
 }
 
+/**
+ * @deprecated Use `getTimeZoneParts` to read values in a specific time zone.
+ */
 export function monthGetterName(isUTC: boolean) {
     return isUTC ? 'getUTCMonth' : 'getMonth';
 }
 
+/**
+ * @deprecated Use `getTimeZoneParts` to read values in a specific time zone.
+ */
 export function dateGetterName(isUTC: boolean) {
     return isUTC ? 'getUTCDate' : 'getDate';
 }
 
+/**
+ * @deprecated Use `getTimeZoneParts` to read values in a specific time zone.
+ */
 export function hoursGetterName(isUTC: boolean) {
     return isUTC ? 'getUTCHours' : 'getHours';
 }
 
+/**
+ * @deprecated Use `getTimeZoneParts` to read values in a specific time zone.
+ */
 export function minutesGetterName(isUTC: boolean) {
     return isUTC ? 'getUTCMinutes' : 'getMinutes';
 }
 
+/**
+ * @deprecated Use `getTimeZoneParts` to read values in a specific time zone.
+ */
 export function secondsGetterName(isUTC: boolean) {
     return isUTC ? 'getUTCSeconds' : 'getSeconds';
 }
 
+/**
+ * @deprecated Use `getTimeZoneParts` to read values in a specific time zone.
+ */
 export function millisecondsGetterName(isUTC: boolean) {
     return isUTC ? 'getUTCMilliseconds' : 'getMilliseconds';
 }
 
+/**
+ * @deprecated Use time-zone-aware utilities instead of selecting a local/UTC 
`Date` setter.
+ */
 export function fullYearSetterName(isUTC: boolean) {
     return isUTC ? 'setUTCFullYear' : 'setFullYear';
 }
 
+/**
+ * @deprecated Use time-zone-aware utilities instead of selecting a local/UTC 
`Date` setter.
+ */
 export function monthSetterName(isUTC: boolean) {
     return isUTC ? 'setUTCMonth' : 'setMonth';
 }
 
+/**
+ * @deprecated Use time-zone-aware utilities instead of selecting a local/UTC 
`Date` setter.
+ */
 export function dateSetterName(isUTC: boolean) {
     return isUTC ? 'setUTCDate' : 'setDate';
 }
 
+/**
+ * @deprecated Use time-zone-aware utilities instead of selecting a local/UTC 
`Date` setter.
+ */
 export function hoursSetterName(isUTC: boolean) {
     return isUTC ? 'setUTCHours' : 'setHours';
 }
 
+/**
+ * @deprecated Use time-zone-aware utilities instead of selecting a local/UTC 
`Date` setter.
+ */
 export function minutesSetterName(isUTC: boolean) {
     return isUTC ? 'setUTCMinutes' : 'setMinutes';
 }
 
+/**
+ * @deprecated Use time-zone-aware utilities instead of selecting a local/UTC 
`Date` setter.
+ */
 export function secondsSetterName(isUTC: boolean) {
     return isUTC ? 'setUTCSeconds' : 'setSeconds';
 }
 
+/**
+ * @deprecated Use time-zone-aware utilities instead of selecting a local/UTC 
`Date` setter.
+ */
 export function millisecondsSetterName(isUTC: boolean) {
     return isUTC ? 'setUTCMilliseconds' : 'setMilliseconds';
 }
+
+interface TimeZoneDateParts {
+    year: number;
+    // Calendar month, from 1 (January) to 12 (December), matching 
Intl/Temporal.
+    month: number;
+    day: number;
+    dayOfWeek: number;
+    hours: number;
+    minutes: number;
+    seconds: number;
+    milliseconds: number;
+    // Same sign as an ISO offset: UTC-05:00 is -300 and UTC+05:30 is 330.
+    offsetMinutes: number;
+}
+
+type TimeZoneWallTimeParts = Omit<TimeZoneDateParts, 'dayOfWeek' | 
'offsetMinutes'>;
+
+interface TimeZoneDayInfo {
+    offsetBefore: number;
+    transitionTimestamp?: number;
+    offsetAfter: number;
+}
+
+interface TimeZoneDayCache {
+    dayStartOffsets: zrUtil.HashMap<number, number>;
+    days: zrUtil.HashMap<TimeZoneDayInfo, number>;
+}
+
+// Required for IANA time zones. Legacy environments can provide an Intl 
polyfill.
+// eslint-disable-next-line no-restricted-globals
+const intl = Intl;
+type TimeZoneFormatter = ReturnType<typeof intl.DateTimeFormat>;
+type TimeZoneFormatterOptions = NonNullable<Parameters<typeof 
intl.DateTimeFormat>[1]>;
+
+const MINUTES_PER_DAY = ONE_DAY / ONE_MINUTE;
+const formatterCache = zrUtil.createHashMap<TimeZoneFormatter, string>();
+const timeZoneDayCaches = zrUtil.createHashMap<TimeZoneDayCache, string>();

Review Comment:
   Fixed in 438a10760. Formatters now use a 32-entry LRU, and per-day time-zone 
results use a flat 4096-entry LRU. Sequential day calculations still reuse 
neighboring cached offsets.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to