time.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. /**
  20. * AUTO-GENERATED FILE. DO NOT MODIFY.
  21. */
  22. /*
  23. * Licensed to the Apache Software Foundation (ASF) under one
  24. * or more contributor license agreements. See the NOTICE file
  25. * distributed with this work for additional information
  26. * regarding copyright ownership. The ASF licenses this file
  27. * to you under the Apache License, Version 2.0 (the
  28. * "License"); you may not use this file except in compliance
  29. * with the License. You may obtain a copy of the License at
  30. *
  31. * http://www.apache.org/licenses/LICENSE-2.0
  32. *
  33. * Unless required by applicable law or agreed to in writing,
  34. * software distributed under the License is distributed on an
  35. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  36. * KIND, either express or implied. See the License for the
  37. * specific language governing permissions and limitations
  38. * under the License.
  39. */
  40. import * as zrUtil from 'zrender/lib/core/util.js';
  41. import * as numberUtil from './number.js';
  42. import { getDefaultLocaleModel, getLocaleModel, SYSTEM_LANG } from '../core/locale.js';
  43. import Model from '../model/Model.js';
  44. import { getScaleBreakHelper } from '../scale/break.js';
  45. export var ONE_SECOND = 1000;
  46. export var ONE_MINUTE = ONE_SECOND * 60;
  47. export var ONE_HOUR = ONE_MINUTE * 60;
  48. export var ONE_DAY = ONE_HOUR * 24;
  49. export var ONE_YEAR = ONE_DAY * 365;
  50. var primaryTimeUnitFormatterMatchers = {
  51. year: /({yyyy}|{yy})/,
  52. month: /({MMMM}|{MMM}|{MM}|{M})/,
  53. day: /({dd}|{d})/,
  54. hour: /({HH}|{H}|{hh}|{h})/,
  55. minute: /({mm}|{m})/,
  56. second: /({ss}|{s})/,
  57. millisecond: /({SSS}|{S})/
  58. };
  59. var defaultFormatterSeed = {
  60. year: '{yyyy}',
  61. month: '{MMM}',
  62. day: '{d}',
  63. hour: '{HH}:{mm}',
  64. minute: '{HH}:{mm}',
  65. second: '{HH}:{mm}:{ss}',
  66. millisecond: '{HH}:{mm}:{ss} {SSS}'
  67. };
  68. var defaultFullFormatter = '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss} {SSS}';
  69. var fullDayFormatter = '{yyyy}-{MM}-{dd}';
  70. export var fullLeveledFormatter = {
  71. year: '{yyyy}',
  72. month: '{yyyy}-{MM}',
  73. day: fullDayFormatter,
  74. hour: fullDayFormatter + ' ' + defaultFormatterSeed.hour,
  75. minute: fullDayFormatter + ' ' + defaultFormatterSeed.minute,
  76. second: fullDayFormatter + ' ' + defaultFormatterSeed.second,
  77. millisecond: defaultFullFormatter
  78. };
  79. // Order must be ensured from big to small.
  80. export var primaryTimeUnits = ['year', 'month', 'day', 'hour', 'minute', 'second', 'millisecond'];
  81. export var timeUnits = ['year', 'half-year', 'quarter', 'month', 'week', 'half-week', 'day', 'half-day', 'quarter-day', 'hour', 'minute', 'second', 'millisecond'];
  82. export function parseTimeAxisLabelFormatter(formatter) {
  83. // Keep the logic the same with function `leveledFormat`.
  84. return !zrUtil.isString(formatter) && !zrUtil.isFunction(formatter) ? parseTimeAxisLabelFormatterDictionary(formatter) : formatter;
  85. }
  86. /**
  87. * The final generated dictionary is like:
  88. * generated_dict = {
  89. * year: {
  90. * year: ['{yyyy}', ...<higher_levels_if_any>]
  91. * },
  92. * month: {
  93. * year: ['{yyyy} {MMM}', ...<higher_levels_if_any>],
  94. * month: ['{MMM}', ...<higher_levels_if_any>]
  95. * },
  96. * day: {
  97. * year: ['{yyyy} {MMM} {d}', ...<higher_levels_if_any>],
  98. * month: ['{MMM} {d}', ...<higher_levels_if_any>],
  99. * day: ['{d}', ...<higher_levels_if_any>]
  100. * },
  101. * ...
  102. * }
  103. *
  104. * In echarts option, users can specify the entire dictionary or typically just:
  105. * {formatter: {
  106. * year: '{yyyy}', // Or an array of leveled templates: `['{yyyy}', '{bold1|{yyyy}}', ...]`,
  107. * // corresponding to `[level0, level1, level2, ...]`.
  108. * month: '{MMM}',
  109. * day: '{d}',
  110. * hour: '{HH}:{mm}',
  111. * second: '{HH}:{mm}',
  112. * ...
  113. * }}
  114. * If any time unit is not specified in echarts option, the default template is used,
  115. * such as `['{yyyy}', {primary|{yyyy}']`.
  116. *
  117. * The `tick.level` is only used to read string from each array, meaning the style type.
  118. *
  119. * Let `lowerUnit = getUnitFromValue(tick.value)`.
  120. * The non-break axis ticks only use `generated_dict[lowerUnit][lowerUnit][level]`.
  121. * The break axis ticks may use `generated_dict[lowerUnit][upperUnit][level]`, because:
  122. * Consider the case: the non-break ticks are `16th, 23th, Feb, 7th, ...`, where `Feb` is in the break
  123. * range and pruned by breaks, and the break ends might be in lower time unit than day. e.g., break start
  124. * is `Jan 25th 18:00`(in unit `hour`) and break end is `Feb 6th 18:30` (in unit `minute`). Thus the break
  125. * label prefers `Jan 25th 18:00` and `Feb 6th 18:30` rather than only `18:00` and `18:30`, otherwise it
  126. * causes misleading.
  127. * In this case, the tick of the break start and end will both be:
  128. * `{level: 1, lowerTimeUnit: 'minute', upperTimeUnit: 'month'}`
  129. * And get the final template by `generated_dict[lowerTimeUnit][upperTimeUnit][level]`.
  130. * Note that the time unit can not be calculated directly by a single tick value, since the two breaks have
  131. * to be at the same time unit to avoid awkward appearance. i.e., `Jan 25th 18:00` is in the time unit "hour"
  132. * but we need it to be "minute", following `Feb 6th 18:30`.
  133. */
  134. function parseTimeAxisLabelFormatterDictionary(dictOption) {
  135. dictOption = dictOption || {};
  136. var dict = {};
  137. // Currently if any template is specified by user, it may contain rich text tag,
  138. // such as `'{my_bold|{YYYY}}'`, thus we do add highlight style to it.
  139. // (Note that nested tag (`'{some|{some2|xxx}}'`) in rich text is not supported yet.)
  140. var canAddHighlight = true;
  141. zrUtil.each(primaryTimeUnits, function (lowestUnit) {
  142. canAddHighlight && (canAddHighlight = dictOption[lowestUnit] == null);
  143. });
  144. zrUtil.each(primaryTimeUnits, function (lowestUnit, lowestUnitIdx) {
  145. var upperDictOption = dictOption[lowestUnit];
  146. dict[lowestUnit] = {};
  147. var lowerTpl = null;
  148. for (var upperUnitIdx = lowestUnitIdx; upperUnitIdx >= 0; upperUnitIdx--) {
  149. var upperUnit = primaryTimeUnits[upperUnitIdx];
  150. var upperDictItemOption = zrUtil.isObject(upperDictOption) && !zrUtil.isArray(upperDictOption) ? upperDictOption[upperUnit] : upperDictOption;
  151. var tplArr = void 0;
  152. if (zrUtil.isArray(upperDictItemOption)) {
  153. tplArr = upperDictItemOption.slice();
  154. lowerTpl = tplArr[0] || '';
  155. } else if (zrUtil.isString(upperDictItemOption)) {
  156. lowerTpl = upperDictItemOption;
  157. tplArr = [lowerTpl];
  158. } else {
  159. if (lowerTpl == null) {
  160. lowerTpl = defaultFormatterSeed[lowestUnit];
  161. }
  162. // Generate the dict by the rule as follows:
  163. // If the user specify (or by default):
  164. // {formatter: {
  165. // year: '{yyyy}',
  166. // month: '{MMM}',
  167. // day: '{d}',
  168. // ...
  169. // }}
  170. // Concat them to make the final dictionary:
  171. // {formatter: {
  172. // year: {year: ['{yyyy}']},
  173. // month: {year: ['{yyyy} {MMM}'], month: ['{MMM}']},
  174. // day: {year: ['{yyyy} {MMM} {d}'], month: ['{MMM} {d}'], day: ['{d}']}
  175. // ...
  176. // }}
  177. // And then add `{primary|...}` to each array if from default template.
  178. // This strategy is convinient for user configurating and works for most cases.
  179. // If bad cases encountered, users can specify the entire dictionary themselves
  180. // instead of going through this logic.
  181. else if (!primaryTimeUnitFormatterMatchers[upperUnit].test(lowerTpl)) {
  182. lowerTpl = dict[upperUnit][upperUnit][0] + " " + lowerTpl;
  183. }
  184. tplArr = [lowerTpl];
  185. if (canAddHighlight) {
  186. tplArr[1] = "{primary|" + lowerTpl + "}";
  187. }
  188. }
  189. dict[lowestUnit][upperUnit] = tplArr;
  190. }
  191. });
  192. return dict;
  193. }
  194. export function pad(str, len) {
  195. str += '';
  196. return '0000'.substr(0, len - str.length) + str;
  197. }
  198. export function getPrimaryTimeUnit(timeUnit) {
  199. switch (timeUnit) {
  200. case 'half-year':
  201. case 'quarter':
  202. return 'month';
  203. case 'week':
  204. case 'half-week':
  205. return 'day';
  206. case 'half-day':
  207. case 'quarter-day':
  208. return 'hour';
  209. default:
  210. // year, minutes, second, milliseconds
  211. return timeUnit;
  212. }
  213. }
  214. export function isPrimaryTimeUnit(timeUnit) {
  215. return timeUnit === getPrimaryTimeUnit(timeUnit);
  216. }
  217. export function getDefaultFormatPrecisionOfInterval(timeUnit) {
  218. switch (timeUnit) {
  219. case 'year':
  220. case 'month':
  221. return 'day';
  222. case 'millisecond':
  223. return 'millisecond';
  224. default:
  225. // Also for day, hour, minute, second
  226. return 'second';
  227. }
  228. }
  229. export function format(
  230. // Note: The result based on `isUTC` are totally different, which can not be just simply
  231. // substituted by the result without `isUTC`. So we make the param `isUTC` mandatory.
  232. time, template, isUTC, lang) {
  233. var date = numberUtil.parseDate(time);
  234. var y = date[fullYearGetterName(isUTC)]();
  235. var M = date[monthGetterName(isUTC)]() + 1;
  236. var q = Math.floor((M - 1) / 3) + 1;
  237. var d = date[dateGetterName(isUTC)]();
  238. var e = date['get' + (isUTC ? 'UTC' : '') + 'Day']();
  239. var H = date[hoursGetterName(isUTC)]();
  240. var h = (H - 1) % 12 + 1;
  241. var m = date[minutesGetterName(isUTC)]();
  242. var s = date[secondsGetterName(isUTC)]();
  243. var S = date[millisecondsGetterName(isUTC)]();
  244. var a = H >= 12 ? 'pm' : 'am';
  245. var A = a.toUpperCase();
  246. var localeModel = lang instanceof Model ? lang : getLocaleModel(lang || SYSTEM_LANG) || getDefaultLocaleModel();
  247. var timeModel = localeModel.getModel('time');
  248. var month = timeModel.get('month');
  249. var monthAbbr = timeModel.get('monthAbbr');
  250. var dayOfWeek = timeModel.get('dayOfWeek');
  251. var dayOfWeekAbbr = timeModel.get('dayOfWeekAbbr');
  252. return (template || '').replace(/{a}/g, a + '').replace(/{A}/g, A + '').replace(/{yyyy}/g, y + '').replace(/{yy}/g, pad(y % 100 + '', 2)).replace(/{Q}/g, q + '').replace(/{MMMM}/g, month[M - 1]).replace(/{MMM}/g, monthAbbr[M - 1]).replace(/{MM}/g, pad(M, 2)).replace(/{M}/g, M + '').replace(/{dd}/g, pad(d, 2)).replace(/{d}/g, d + '').replace(/{eeee}/g, dayOfWeek[e]).replace(/{ee}/g, dayOfWeekAbbr[e]).replace(/{e}/g, e + '').replace(/{HH}/g, pad(H, 2)).replace(/{H}/g, H + '').replace(/{hh}/g, pad(h + '', 2)).replace(/{h}/g, h + '').replace(/{mm}/g, pad(m, 2)).replace(/{m}/g, m + '').replace(/{ss}/g, pad(s, 2)).replace(/{s}/g, s + '').replace(/{SSS}/g, pad(S, 3)).replace(/{S}/g, S + '');
  253. }
  254. export function leveledFormat(tick, idx, formatter, lang, isUTC) {
  255. var template = null;
  256. if (zrUtil.isString(formatter)) {
  257. // Single formatter for all units at all levels
  258. template = formatter;
  259. } else if (zrUtil.isFunction(formatter)) {
  260. var extra = {
  261. time: tick.time,
  262. level: tick.time.level
  263. };
  264. var scaleBreakHelper = getScaleBreakHelper();
  265. if (scaleBreakHelper) {
  266. scaleBreakHelper.makeAxisLabelFormatterParamBreak(extra, tick["break"]);
  267. }
  268. template = formatter(tick.value, idx, extra);
  269. } else {
  270. var tickTime = tick.time;
  271. if (tickTime) {
  272. var leveledTplArr = formatter[tickTime.lowerTimeUnit][tickTime.upperTimeUnit];
  273. template = leveledTplArr[Math.min(tickTime.level, leveledTplArr.length - 1)] || '';
  274. } else {
  275. // tick may be from customTicks or timeline therefore no tick.time.
  276. var unit = getUnitFromValue(tick.value, isUTC);
  277. template = formatter[unit][unit][0];
  278. }
  279. }
  280. return format(new Date(tick.value), template, isUTC, lang);
  281. }
  282. export function getUnitFromValue(value, isUTC) {
  283. var date = numberUtil.parseDate(value);
  284. var M = date[monthGetterName(isUTC)]() + 1;
  285. var d = date[dateGetterName(isUTC)]();
  286. var h = date[hoursGetterName(isUTC)]();
  287. var m = date[minutesGetterName(isUTC)]();
  288. var s = date[secondsGetterName(isUTC)]();
  289. var S = date[millisecondsGetterName(isUTC)]();
  290. var isSecond = S === 0;
  291. var isMinute = isSecond && s === 0;
  292. var isHour = isMinute && m === 0;
  293. var isDay = isHour && h === 0;
  294. var isMonth = isDay && d === 1;
  295. var isYear = isMonth && M === 1;
  296. if (isYear) {
  297. return 'year';
  298. } else if (isMonth) {
  299. return 'month';
  300. } else if (isDay) {
  301. return 'day';
  302. } else if (isHour) {
  303. return 'hour';
  304. } else if (isMinute) {
  305. return 'minute';
  306. } else if (isSecond) {
  307. return 'second';
  308. } else {
  309. return 'millisecond';
  310. }
  311. }
  312. // export function getUnitValue(
  313. // value: number | Date,
  314. // unit: TimeUnit,
  315. // isUTC: boolean
  316. // ) : number {
  317. // const date = zrUtil.isNumber(value)
  318. // ? numberUtil.parseDate(value)
  319. // : value;
  320. // unit = unit || getUnitFromValue(value, isUTC);
  321. // switch (unit) {
  322. // case 'year':
  323. // return date[fullYearGetterName(isUTC)]();
  324. // case 'half-year':
  325. // return date[monthGetterName(isUTC)]() >= 6 ? 1 : 0;
  326. // case 'quarter':
  327. // return Math.floor((date[monthGetterName(isUTC)]() + 1) / 4);
  328. // case 'month':
  329. // return date[monthGetterName(isUTC)]();
  330. // case 'day':
  331. // return date[dateGetterName(isUTC)]();
  332. // case 'half-day':
  333. // return date[hoursGetterName(isUTC)]() / 24;
  334. // case 'hour':
  335. // return date[hoursGetterName(isUTC)]();
  336. // case 'minute':
  337. // return date[minutesGetterName(isUTC)]();
  338. // case 'second':
  339. // return date[secondsGetterName(isUTC)]();
  340. // case 'millisecond':
  341. // return date[millisecondsGetterName(isUTC)]();
  342. // }
  343. // }
  344. /**
  345. * e.g.,
  346. * If timeUnit is 'year', return the Jan 1st 00:00:00 000 of that year.
  347. * If timeUnit is 'day', return the 00:00:00 000 of that day.
  348. *
  349. * @return The input date.
  350. */
  351. export function roundTime(date, timeUnit, isUTC) {
  352. switch (timeUnit) {
  353. case 'year':
  354. date[monthSetterName(isUTC)](0);
  355. case 'month':
  356. date[dateSetterName(isUTC)](1);
  357. case 'day':
  358. date[hoursSetterName(isUTC)](0);
  359. case 'hour':
  360. date[minutesSetterName(isUTC)](0);
  361. case 'minute':
  362. date[secondsSetterName(isUTC)](0);
  363. case 'second':
  364. date[millisecondsSetterName(isUTC)](0);
  365. }
  366. return date;
  367. }
  368. export function fullYearGetterName(isUTC) {
  369. return isUTC ? 'getUTCFullYear' : 'getFullYear';
  370. }
  371. export function monthGetterName(isUTC) {
  372. return isUTC ? 'getUTCMonth' : 'getMonth';
  373. }
  374. export function dateGetterName(isUTC) {
  375. return isUTC ? 'getUTCDate' : 'getDate';
  376. }
  377. export function hoursGetterName(isUTC) {
  378. return isUTC ? 'getUTCHours' : 'getHours';
  379. }
  380. export function minutesGetterName(isUTC) {
  381. return isUTC ? 'getUTCMinutes' : 'getMinutes';
  382. }
  383. export function secondsGetterName(isUTC) {
  384. return isUTC ? 'getUTCSeconds' : 'getSeconds';
  385. }
  386. export function millisecondsGetterName(isUTC) {
  387. return isUTC ? 'getUTCMilliseconds' : 'getMilliseconds';
  388. }
  389. export function fullYearSetterName(isUTC) {
  390. return isUTC ? 'setUTCFullYear' : 'setFullYear';
  391. }
  392. export function monthSetterName(isUTC) {
  393. return isUTC ? 'setUTCMonth' : 'setMonth';
  394. }
  395. export function dateSetterName(isUTC) {
  396. return isUTC ? 'setUTCDate' : 'setDate';
  397. }
  398. export function hoursSetterName(isUTC) {
  399. return isUTC ? 'setUTCHours' : 'setHours';
  400. }
  401. export function minutesSetterName(isUTC) {
  402. return isUTC ? 'setUTCMinutes' : 'setMinutes';
  403. }
  404. export function secondsSetterName(isUTC) {
  405. return isUTC ? 'setUTCSeconds' : 'setSeconds';
  406. }
  407. export function millisecondsSetterName(isUTC) {
  408. return isUTC ? 'setUTCMilliseconds' : 'setMilliseconds';
  409. }