ng-zorro-antd-core-time.mjs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. import { startOfWeek, startOfMonth, setYear, addYears, setMonth, addMonths, setDay, getQuarter, setQuarter, isSameDay, isSameSecond, isSameMinute, isSameHour, isSameMonth, isSameQuarter, isSameYear, differenceInCalendarDays, differenceInSeconds, differenceInMinutes, differenceInHours, differenceInCalendarMonths, differenceInCalendarQuarters, differenceInCalendarYears, isToday, isValid, isFirstDayOfMonth, isLastDayOfMonth } from 'date-fns';
  2. import { warn } from 'ng-zorro-antd/core/logger';
  3. import { getLocaleDayPeriods, FormStyle, TranslationWidth } from '@angular/common';
  4. import { isNotNil } from 'ng-zorro-antd/core/util';
  5. /**
  6. * Use of this source code is governed by an MIT-style license that can be
  7. * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
  8. */
  9. function wrongSortOrder(rangeValue) {
  10. const [start, end] = rangeValue;
  11. return !!start && !!end && end.isBeforeDay(start);
  12. }
  13. function normalizeRangeValue(value, hasTimePicker, type = 'month', activePart = 'left') {
  14. const [start, end] = value;
  15. let newStart = start || new CandyDate();
  16. let newEnd = end || (hasTimePicker ? newStart : newStart.add(1, type));
  17. if (start && !end) {
  18. newStart = start;
  19. newEnd = hasTimePicker ? start : start.add(1, type);
  20. }
  21. else if (!start && end) {
  22. newStart = hasTimePicker ? end : end.add(-1, type);
  23. newEnd = end;
  24. }
  25. else if (start && end && !hasTimePicker) {
  26. if (start.isSame(end, type)) {
  27. newEnd = newStart.add(1, type);
  28. }
  29. else {
  30. if (activePart === 'left') {
  31. newEnd = newStart.add(1, type);
  32. }
  33. else {
  34. newStart = newEnd.add(-1, type);
  35. }
  36. }
  37. }
  38. return [newStart, newEnd];
  39. }
  40. function cloneDate(value) {
  41. if (Array.isArray(value)) {
  42. return value.map(v => (v instanceof CandyDate ? v.clone() : null));
  43. }
  44. else {
  45. return value instanceof CandyDate ? value.clone() : null;
  46. }
  47. }
  48. /**
  49. * Wrapping kind APIs for date operating and unify
  50. * NOTE: every new API return new CandyDate object without side effects to the former Date object
  51. * NOTE: most APIs are based on local time other than customized locale id (this needs tobe support in future)
  52. * TODO: support format() against to angular's core API
  53. */
  54. class CandyDate {
  55. nativeDate;
  56. // locale: string; // Custom specified locale ID
  57. constructor(date) {
  58. if (date) {
  59. if (date instanceof Date) {
  60. this.nativeDate = date;
  61. }
  62. else if (typeof date === 'string' || typeof date === 'number') {
  63. warn('The string type is not recommended for date-picker, use "Date" type');
  64. this.nativeDate = new Date(date);
  65. }
  66. else {
  67. throw new Error('The input date type is not supported ("Date" is now recommended)');
  68. }
  69. }
  70. else {
  71. this.nativeDate = new Date();
  72. }
  73. }
  74. calendarStart(options) {
  75. return new CandyDate(startOfWeek(startOfMonth(this.nativeDate), options));
  76. }
  77. // ---------------------------------------------------------------------
  78. // | Native shortcuts
  79. // -----------------------------------------------------------------------------\
  80. getYear() {
  81. return this.nativeDate.getFullYear();
  82. }
  83. getMonth() {
  84. return this.nativeDate.getMonth();
  85. }
  86. getDay() {
  87. return this.nativeDate.getDay();
  88. }
  89. getTime() {
  90. return this.nativeDate.getTime();
  91. }
  92. getDate() {
  93. return this.nativeDate.getDate();
  94. }
  95. getHours() {
  96. return this.nativeDate.getHours();
  97. }
  98. getMinutes() {
  99. return this.nativeDate.getMinutes();
  100. }
  101. getSeconds() {
  102. return this.nativeDate.getSeconds();
  103. }
  104. getMilliseconds() {
  105. return this.nativeDate.getMilliseconds();
  106. }
  107. // ---------------------------------------------------------------------
  108. // | New implementing APIs
  109. // ---------------------------------------------------------------------
  110. clone() {
  111. return new CandyDate(new Date(this.nativeDate));
  112. }
  113. setHms(hour, minute, second) {
  114. const newDate = new Date(this.nativeDate.setHours(hour, minute, second));
  115. return new CandyDate(newDate);
  116. }
  117. setYear(year) {
  118. return new CandyDate(setYear(this.nativeDate, year));
  119. }
  120. addYears(amount) {
  121. return new CandyDate(addYears(this.nativeDate, amount));
  122. }
  123. // NOTE: month starts from 0
  124. // NOTE: Don't use the native API for month manipulation as it not restrict the date when it overflows, eg. (new Date('2018-7-31')).setMonth(1) will be date of 2018-3-03 instead of 2018-2-28
  125. setMonth(month) {
  126. return new CandyDate(setMonth(this.nativeDate, month));
  127. }
  128. addMonths(amount) {
  129. return new CandyDate(addMonths(this.nativeDate, amount));
  130. }
  131. setDay(day, options) {
  132. return new CandyDate(setDay(this.nativeDate, day, options));
  133. }
  134. setDate(amount) {
  135. const date = new Date(this.nativeDate);
  136. date.setDate(amount);
  137. return new CandyDate(date);
  138. }
  139. getQuarter() {
  140. return getQuarter(this.nativeDate);
  141. }
  142. setQuarter(quarter) {
  143. return new CandyDate(setQuarter(this.nativeDate, quarter));
  144. }
  145. addDays(amount) {
  146. return this.setDate(this.getDate() + amount);
  147. }
  148. add(amount, mode) {
  149. switch (mode) {
  150. case 'decade':
  151. return this.addYears(amount * 10);
  152. case 'year':
  153. return this.addYears(amount);
  154. case 'month':
  155. return this.addMonths(amount);
  156. default:
  157. return this.addMonths(amount);
  158. }
  159. }
  160. isSame(date, grain = 'day') {
  161. let fn;
  162. switch (grain) {
  163. case 'decade':
  164. fn = (pre, next) => Math.abs(pre.getFullYear() - next.getFullYear()) < 11;
  165. break;
  166. case 'year':
  167. fn = isSameYear;
  168. break;
  169. case 'quarter':
  170. fn = isSameQuarter;
  171. break;
  172. case 'month':
  173. fn = isSameMonth;
  174. break;
  175. case 'day':
  176. fn = isSameDay;
  177. break;
  178. case 'hour':
  179. fn = isSameHour;
  180. break;
  181. case 'minute':
  182. fn = isSameMinute;
  183. break;
  184. case 'second':
  185. fn = isSameSecond;
  186. break;
  187. default:
  188. fn = isSameDay;
  189. break;
  190. }
  191. return fn(this.nativeDate, this.toNativeDate(date));
  192. }
  193. isSameYear(date) {
  194. return this.isSame(date, 'year');
  195. }
  196. isSameQuarter(date) {
  197. return this.isSame(date, 'quarter');
  198. }
  199. isSameMonth(date) {
  200. return this.isSame(date, 'month');
  201. }
  202. isSameDay(date) {
  203. return this.isSame(date, 'day');
  204. }
  205. isSameHour(date) {
  206. return this.isSame(date, 'hour');
  207. }
  208. isSameMinute(date) {
  209. return this.isSame(date, 'minute');
  210. }
  211. isSameSecond(date) {
  212. return this.isSame(date, 'second');
  213. }
  214. isBefore(date, grain = 'day') {
  215. if (date === null) {
  216. return false;
  217. }
  218. let fn;
  219. switch (grain) {
  220. case 'year':
  221. fn = differenceInCalendarYears;
  222. break;
  223. case 'quarter':
  224. fn = differenceInCalendarQuarters;
  225. break;
  226. case 'month':
  227. fn = differenceInCalendarMonths;
  228. break;
  229. case 'day':
  230. fn = differenceInCalendarDays;
  231. break;
  232. case 'hour':
  233. fn = differenceInHours;
  234. break;
  235. case 'minute':
  236. fn = differenceInMinutes;
  237. break;
  238. case 'second':
  239. fn = differenceInSeconds;
  240. break;
  241. default:
  242. fn = differenceInCalendarDays;
  243. break;
  244. }
  245. return fn(this.nativeDate, this.toNativeDate(date)) < 0;
  246. }
  247. isBeforeYear(date) {
  248. return this.isBefore(date, 'year');
  249. }
  250. isBeforeQuarter(date) {
  251. return this.isBefore(date, 'quarter');
  252. }
  253. isBeforeMonth(date) {
  254. return this.isBefore(date, 'month');
  255. }
  256. isBeforeDay(date) {
  257. return this.isBefore(date, 'day');
  258. }
  259. // Equal to today accurate to "day"
  260. isToday() {
  261. return isToday(this.nativeDate);
  262. }
  263. isValid() {
  264. return isValid(this.nativeDate);
  265. }
  266. isFirstDayOfMonth() {
  267. return isFirstDayOfMonth(this.nativeDate);
  268. }
  269. isLastDayOfMonth() {
  270. return isLastDayOfMonth(this.nativeDate);
  271. }
  272. toNativeDate(date) {
  273. return date instanceof CandyDate ? date.nativeDate : date;
  274. }
  275. }
  276. /**
  277. * Use of this source code is governed by an MIT-style license that can be
  278. * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
  279. */
  280. const timeUnits = [
  281. ['Y', 1000 * 60 * 60 * 24 * 365], // years
  282. ['M', 1000 * 60 * 60 * 24 * 30], // months
  283. ['D', 1000 * 60 * 60 * 24], // days
  284. ['H', 1000 * 60 * 60], // hours
  285. ['m', 1000 * 60], // minutes
  286. ['s', 1000], // seconds
  287. ['S', 1] // million seconds
  288. ];
  289. /**
  290. * Use of this source code is governed by an MIT-style license that can be
  291. * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
  292. */
  293. // from https://github.com/hsuanxyz/ng-time-parser
  294. class NgTimeParser {
  295. format;
  296. localeId;
  297. regex = null;
  298. matchMap = {
  299. hour: null,
  300. minute: null,
  301. second: null,
  302. periodNarrow: null,
  303. periodWide: null,
  304. periodAbbreviated: null
  305. };
  306. constructor(format, localeId) {
  307. this.format = format;
  308. this.localeId = localeId;
  309. this.genRegexp();
  310. }
  311. toDate(str) {
  312. const result = this.getTimeResult(str);
  313. const time = new Date();
  314. if (isNotNil(result?.hour)) {
  315. time.setHours(result.hour);
  316. }
  317. if (isNotNil(result?.minute)) {
  318. time.setMinutes(result.minute);
  319. }
  320. if (isNotNil(result?.second)) {
  321. time.setSeconds(result.second);
  322. }
  323. if (result?.period === 1 && time.getHours() < 12) {
  324. time.setHours(time.getHours() + 12);
  325. }
  326. return time;
  327. }
  328. getTimeResult(str) {
  329. const match = this.regex.exec(str);
  330. let period = null;
  331. if (match) {
  332. if (isNotNil(this.matchMap.periodNarrow)) {
  333. period = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Narrow).indexOf(match[this.matchMap.periodNarrow + 1]);
  334. }
  335. if (isNotNil(this.matchMap.periodWide)) {
  336. period = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Wide).indexOf(match[this.matchMap.periodWide + 1]);
  337. }
  338. if (isNotNil(this.matchMap.periodAbbreviated)) {
  339. period = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Abbreviated).indexOf(match[this.matchMap.periodAbbreviated + 1]);
  340. }
  341. return {
  342. hour: isNotNil(this.matchMap.hour) ? Number.parseInt(match[this.matchMap.hour + 1], 10) : null,
  343. minute: isNotNil(this.matchMap.minute) ? Number.parseInt(match[this.matchMap.minute + 1], 10) : null,
  344. second: isNotNil(this.matchMap.second) ? Number.parseInt(match[this.matchMap.second + 1], 10) : null,
  345. period
  346. };
  347. }
  348. else {
  349. return null;
  350. }
  351. }
  352. genRegexp() {
  353. let regexStr = this.format.replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$&');
  354. const hourRegex = /h{1,2}/i;
  355. const minuteRegex = /m{1,2}/;
  356. const secondRegex = /s{1,2}/;
  357. const periodNarrow = /aaaaa/;
  358. const periodWide = /aaaa/;
  359. const periodAbbreviated = /a{1,3}/;
  360. const hourMatch = hourRegex.exec(this.format);
  361. const minuteMatch = minuteRegex.exec(this.format);
  362. const secondMatch = secondRegex.exec(this.format);
  363. const periodNarrowMatch = periodNarrow.exec(this.format);
  364. let periodWideMatch = null;
  365. let periodAbbreviatedMatch = null;
  366. if (!periodNarrowMatch) {
  367. periodWideMatch = periodWide.exec(this.format);
  368. }
  369. if (!periodWideMatch && !periodNarrowMatch) {
  370. periodAbbreviatedMatch = periodAbbreviated.exec(this.format);
  371. }
  372. const matchs = [hourMatch, minuteMatch, secondMatch, periodNarrowMatch, periodWideMatch, periodAbbreviatedMatch]
  373. .filter(m => !!m)
  374. .sort((a, b) => a.index - b.index);
  375. matchs.forEach((match, index) => {
  376. switch (match) {
  377. case hourMatch:
  378. this.matchMap.hour = index;
  379. regexStr = regexStr.replace(hourRegex, '(\\d{1,2})');
  380. break;
  381. case minuteMatch:
  382. this.matchMap.minute = index;
  383. regexStr = regexStr.replace(minuteRegex, '(\\d{1,2})');
  384. break;
  385. case secondMatch:
  386. this.matchMap.second = index;
  387. regexStr = regexStr.replace(secondRegex, '(\\d{1,2})');
  388. break;
  389. case periodNarrowMatch: {
  390. this.matchMap.periodNarrow = index;
  391. const periodsNarrow = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Narrow).join('|');
  392. regexStr = regexStr.replace(periodNarrow, `(${periodsNarrow})`);
  393. break;
  394. }
  395. case periodWideMatch: {
  396. this.matchMap.periodWide = index;
  397. const periodsWide = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Wide).join('|');
  398. regexStr = regexStr.replace(periodWide, `(${periodsWide})`);
  399. break;
  400. }
  401. case periodAbbreviatedMatch: {
  402. this.matchMap.periodAbbreviated = index;
  403. const periodsAbbreviated = getLocaleDayPeriods(this.localeId, FormStyle.Format, TranslationWidth.Abbreviated).join('|');
  404. regexStr = regexStr.replace(periodAbbreviated, `(${periodsAbbreviated})`);
  405. break;
  406. }
  407. }
  408. });
  409. this.regex = new RegExp(regexStr);
  410. }
  411. }
  412. /**
  413. * Use of this source code is governed by an MIT-style license that can be
  414. * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
  415. */
  416. /**
  417. * Generated bundle index. Do not edit.
  418. */
  419. export { CandyDate, cloneDate, normalizeRangeValue, timeUnits, wrongSortOrder, NgTimeParser as ɵNgTimeParser };
  420. //# sourceMappingURL=ng-zorro-antd-core-time.mjs.map