/* * @Author: 疯狂秀才(Lucas Huang) * @Date: 2019-09-04 07:40:04 * @LastEditors: 疯狂秀才(Lucas Huang) * @LastEditTime: 2019-09-04 15:21:46 * @QQ: 1055818239 * @Version: v0.0.1 */ import { Injectable } from '@angular/core'; import { IMyDateModel, IMySingleDateModel, IMyDateRangeModel, IMyDate, IMyDateRange, IMyMonth, IMyMonthLabels, IMyMarkedDates, IMyMarkedDate, IMyDateFormat, IMyOptions } from '../interfaces/public-api'; import { KeyCode, KeyName, ShowType } from '../enums/public-api'; import { D, DD, M, MM, MMM, YYYY, SU, MO, TU, WE, TH, FR, SA, ZERO_STR, EMPTY_STR } from '../constants/constants'; @Injectable() export class UtilService { weekDays: Array = [SU, MO, TU, WE, TH, FR, SA]; isDateValid(dateStr: string, options: IMyOptions, isReturn = false): IMyDate { // tslint:disable-next-line:one-variable-per-declaration let _dateStr: string, hour = 0, minute = 0, second = 0; const returnDate: IMyDate = this.resetDate(); if (!dateStr || !dateStr.length) { return returnDate; } const { dateFormat, minYear, maxYear, monthLabels, showTime, returnFormat, showType } = options; let _st = showTime; let formatStr = dateFormat; if (isReturn) { formatStr = returnFormat.replace(/[年,月]/g, '-').replace(/[日]/, '').replace(/[时,分]/g, ':').replace(/[秒]/g, ''); dateStr = dateStr.replace(/[年,月]/g, '-').replace(/[日]/, '').replace(/[时,分]/g, ':').replace(/[秒]/g, ''); if (dateStr[dateStr.length - 1] === '-' || dateStr[dateStr.length - 1] === ':') { dateStr = dateStr.substring(0, dateStr.length - 1); } if (!showTime && returnFormat.toLocaleLowerCase().indexOf('hh:mm') > -1) { _st = true; } } const daysInMonth: Array = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; const isMonthStr: boolean = formatStr.indexOf(MMM) !== -1; let delimeters: Array = formatStr.match(/[^(DdMmYy)]{1,}/g); if (_st && dateStr) { _dateStr = dateStr.split(' ')[0]; Object.assign(returnDate, { hour: 0, minute: 0, second: 0 }); const timeStr = dateStr.split(' ')[1]; if (timeStr) { const _timer = timeStr.replace('时', ':').replace('分', ':').replace('秒', '').split(':'); if (_timer[0]) { hour = Number(_timer[0].substr(0, 2)); hour = isNaN(hour) ? 0 : hour; } if (_timer[1]) { minute = Number(_timer[1].substr(0, 2)); minute = isNaN(minute) ? 0 : minute; } if (_timer[2]) { second = Number(_timer[2].substr(0, 2)); second = isNaN(second) ? 0 : second; } } else { delimeters = undefined; const reg = /^\d{1,}$/; if (reg.test(dateStr)) { // 验证传入的格式为 yyyyMMddHHmmss const df = formatStr; _dateStr = dateStr.substr(0, 8); let _timer = dateStr.substr(8); if (_timer) { if (df.includes('HH')) { if (_timer) { hour = +_timer.slice(0, 2); _timer = _timer.slice(2); } } if (df.includes('mm')) { if (_timer) { minute = +_timer.slice(0, 2); _timer = _timer.slice(2); } } if (df.includes('ss')) { if (_timer) { second = +_timer.slice(0, 2); } } } } } } else { _dateStr = dateStr ? dateStr.split(' ')[0] : ''; } const dateValue: Array = this.getDateValue(_dateStr, formatStr, delimeters); const year: number = this.getNumberByValue(dateValue[0]); const month: number = isMonthStr ? this.getMonthNumberByMonthName(dateValue[1], monthLabels) : this.getNumberByValue(dateValue[1]); const day: number = this.getNumberByValue(dateValue[2]); if (showType === ShowType.noDateAndMonth) { return { year, month: 1, day: 1 }; } if (month !== -1 && day !== -1 && year !== -1) { if (year < minYear || year > maxYear || month < 1 || month > 12) { return returnDate; } const date: IMyDate = _st ? { year, month, day, hour, minute, second } : { year, month, day }; if (this.isDisabledDate(date, options)) { return returnDate; } if (year % 400 === 0 || (year % 100 !== 0 && year % 4 === 0)) { daysInMonth[1] = 29; } if (day < 1 || day > daysInMonth[month - 1]) { return returnDate; } // Valid date if (options.showType === ShowType.noDate) { return { year: date.year, month: date.month }; } else if (options.showType === ShowType.noDateAndMonth) { return { year: date.year }; } else { return date; } } return returnDate; } isDateValidDateRange(dateRangeStr: string, options: IMyOptions): IMyDateRange { let dateRange: IMyDateRange = { begin: this.resetDate(), end: this.resetDate() }; if (dateRangeStr && dateRangeStr.length) { const dates: Array = dateRangeStr.split(options.dateRangeDatesDelimiter); if (dates && dates.length === 2) { const [beginDate, endDate] = dates; const begin: IMyDate = this.isDateValid(beginDate, options, true); if (this.isInitializedDate(begin)) { const end: IMyDate = this.isDateValid(endDate, options, true); if (this.isInitializedDate(end) && this.isDateSameOrEarlier(begin, end)) { dateRange = { begin, end }; } } } } return dateRange; } getDateValue(dateStr: string, dateFormat: string, delimeters: Array): Array { const da: Array = []; if (delimeters) { let del: string = delimeters[0]; if (delimeters[0] !== delimeters[1]) { del = delimeters[0] + delimeters[1]; if (delimeters[2] && delimeters[1] !== delimeters[2]) { del = del + delimeters[2]; } } const re: any = new RegExp('[' + del + ']'); const ds: Array = dateStr.split(re); const df: Array = dateFormat.split(re); for (let i = 0; i < df.length; i++) { if (df[i].indexOf(YYYY) !== -1) { da[0] = { value: ds[i], format: df[i] }; } if (df[i].indexOf(M) !== -1) { da[1] = ds[i] === undefined ? { value: '1', format: df[i] } : { value: ds[i], format: df[i] }; } if (df[i].indexOf(D) !== -1) { da[2] = ds[i] === undefined ? { value: '1', format: df[i] } : { value: ds[i], format: df[i] }; } } } else { const yearIndex = (dateFormat + '').indexOf(YYYY); const monthIndex = (dateFormat + '').indexOf(MM); const dayIndex = (dateFormat + '').indexOf(DD); if (yearIndex >= 0) { da[0] = { value: dateStr.substring(yearIndex, yearIndex + 4), format: dateFormat.substring(yearIndex, yearIndex + 4) }; } if (monthIndex >= 0) { da[1] = { value: dateStr.substring(monthIndex, monthIndex + 2), format: dateFormat.substring(monthIndex, monthIndex + 2) }; } if (dayIndex >= 0) { da[2] = { value: dateStr.substring(dayIndex, dayIndex + 2), format: dateFormat.substring(dayIndex, dayIndex + 2) }; } } return da; } getMonthNumberByMonthName(df: IMyDateFormat, monthLabels: IMyMonthLabels): number { if (df.value) { for (let key = 1; key <= 12; key++) { if (df.value.toLowerCase() === monthLabels[key].toLowerCase()) { return key; } } } return -1; } getNumberByValue(df: IMyDateFormat): number { if (!df) { return 1; } if (!/^\d+$/.test(df.value)) { return -1; } let nbr: number = Number(df.value); if ( (df.format.length === 1 && df.value.length !== 1 && nbr < 10) || (df.format.length === 1 && df.value.length !== 2 && nbr >= 10) ) { nbr = -1; } else if (df.format.length === 2 && df.value.length > 2) { nbr = -1; } return nbr; } parseDefaultMonth(monthString: string): IMyMonth { const month: IMyMonth = { monthTxt: EMPTY_STR, monthNbr: 0, year: 0 }; if (monthString !== EMPTY_STR) { const split = monthString.split(monthString.match(/[^0-9]/)[0]); month.monthNbr = split[0].length === 2 ? Number(split[0]) : Number(split[1]); month.year = split[0].length === 2 ? Number(split[1]) : Number(split[0]); } return month; } isDisabledDate(date: IMyDate, options: IMyOptions): boolean { const { minYear, maxYear, disableUntil, disableSince, disableWeekends, disableDates, disableDateRanges, disableWeekdays, enableDates } = options; // for (const d of enableDates) { // if ( // (d.year === 0 || d.year === date.year) && // (d.month === 0 || d.month === date.month) && // d.day === date.day // ) { // return false; // } // } if ((date.year < minYear && date.month === 12) || (date.year > maxYear && date.month === 1)) { return true; } const dateMs: number = this.getTimeInMilliseconds(date); if (this.isInitializedDate(disableUntil) && (dateMs + 24 * 60 * 60 * 1000 - 1) < this.getTimeInMilliseconds(disableUntil)) { return true; } if (this.isInitializedDate(disableSince) && dateMs > this.getTimeInMilliseconds(disableSince)) { return true; } if (disableWeekends) { const dayNbr = this.getDayNumber(date); if (dayNbr === 0 || dayNbr === 6) { return true; } } const dn = this.getDayNumber(date); if (disableWeekdays.length > 0) { for (const wd of disableWeekdays) { if (dn === this.getWeekdayIndex(wd)) { return true; } } } for (const d of disableDates) { if ( (d.year === 0 || d.year === date.year) && (d.month === 0 || d.month === date.month) && d.day === date.day ) { return true; } } for (const d of disableDateRanges) { if ( this.isInitializedDate(d.begin) && this.isInitializedDate(d.end) && dateMs >= this.getTimeInMilliseconds(d.begin) && dateMs <= this.getTimeInMilliseconds(d.end) ) { return true; } } return false; } isMarkedDate(date: IMyDate, markedDates: Array, markWeekends: IMyMarkedDate): IMyMarkedDate { for (const md of markedDates) { for (const d of md.dates) { if ( (d.year === 0 || d.year === date.year) && (d.month === 0 || d.month === date.month) && d.day === date.day ) { return { marked: true, color: md.color }; } } } if (markWeekends && markWeekends.marked) { const dayNbr = this.getDayNumber(date); if (dayNbr === 0 || dayNbr === 6) { return { marked: true, color: markWeekends.color }; } } return { marked: false, color: EMPTY_STR }; } isHighlightedDate( date: IMyDate, sunHighlight: boolean, satHighlight: boolean, highlightDates: Array ): boolean { const dayNbr: number = this.getDayNumber(date); if ((sunHighlight && dayNbr === 0) || (satHighlight && dayNbr === 6)) { return true; } for (const d of highlightDates) { if ( (d.year === 0 || d.year === date.year) && (d.month === 0 || d.month === date.month) && d.day === date.day ) { return true; } } return false; } getWeekNumber(date: IMyDate): number { const d: Date = new Date(date.year, date.month - 1, date.day, 0, 0, 0, 0); d.setDate(d.getDate() + (d.getDay() === 0 ? -3 : 4 - d.getDay())); return Math.round((d.getTime() - new Date(d.getFullYear(), 0, 4).getTime()) / 86400000 / 7) + 1; } getNowWeekTime(date: Date): IMyDateRange { date.setDate(date.getDate() - ((date.getDay() + 6) % 7)); const begin = { year: date.getFullYear(), month: date.getMonth() + 1, day: date.getDate() }; date.setDate(date.getDate() + 6); const end = { year: date.getFullYear(), month: date.getMonth() + 1, day: date.getDate() }; return { begin, end }; } isMonthDisabledByDisableUntil(date: IMyDate, disableUntil: IMyDate): boolean { return ( this.isInitializedDate(disableUntil) && this.getTimeInMilliseconds(date) <= this.getTimeInMilliseconds(disableUntil) ); } isMonthDisabledByDisableSince(date: IMyDate, disableSince: IMyDate): boolean { return ( this.isInitializedDate(disableSince) && this.getTimeInMilliseconds(date) >= this.getTimeInMilliseconds(disableSince) ); } getDateModel( date: IMyDate, dateRange: IMyDateRange, dateFormat: string, monthLabels: IMyMonthLabels, rangeDelimiter: string, returnFormat: string, dateStr: string = EMPTY_STR ): IMyDateModel { let singleDateModel: IMySingleDateModel = null; let dateRangeModel: IMyDateRangeModel = null; if (date) { singleDateModel = { date, jsDate: this.getDate2(date), formatted: dateStr.length ? dateStr : this.formatDate(date, dateFormat, monthLabels), returnFormatted: this.formatDate(date, returnFormat, monthLabels), epoc: this.getEpocTime(date) }; } else { dateRangeModel = { beginDate: dateRange.begin, beginJsDate: this.getDate(dateRange.begin), beginEpoc: this.getEpocTime(dateRange.begin), endDate: dateRange.end, endJsDate: this.getDate(dateRange.end), endEpoc: this.getEpocTime(dateRange.end), formatted: this.formatDate(dateRange.begin, dateFormat, monthLabels) + rangeDelimiter + this.formatDate(dateRange.end, dateFormat, monthLabels), returnFormatted: this.formatDate(dateRange.begin, returnFormat, monthLabels) + rangeDelimiter + this.formatDate(dateRange.end, returnFormat, monthLabels), }; } return { isRange: date === null, singleDate: singleDateModel, dateRange: dateRangeModel }; } formatDate(date: IMyDate, dateFormat: string, monthLabels: IMyMonthLabels): string { if (!date.month && dateFormat.indexOf(MM) === -1) { dateFormat = this.delete(dateFormat, MM); } if (!date.day && dateFormat.indexOf(DD) === -1) { dateFormat = this.delete(dateFormat, DD); } let formatted: string = dateFormat.replace(YYYY, String(date.year)); if (dateFormat.indexOf(M) === -1) { formatted = formatted.replace(MM, '01'); } else { if (dateFormat.indexOf(MMM) !== -1) { formatted = formatted.replace(MMM, monthLabels[date.month]); } else if (dateFormat.indexOf(MM) !== -1) { formatted = formatted.replace(MM, this.preZero(date.month || 1)); } else { formatted = formatted.replace(M, String(date.month || 1)); } } if (dateFormat.indexOf(DD) === -1) { formatted = formatted.replace(DD, '01'); } else if (dateFormat.indexOf(DD) !== -1) { formatted = formatted.replace(DD, this.preZero(date.day || 1)); } else { formatted = formatted.replace(D, String(date.day || 1)); } formatted = formatted.replace('MM', 'mm').replace('HH', this.preZero(date.hour || 0)) .replace('mm', this.preZero(date.minute || 0)) .replace('ss', this.preZero(date.second || 0)); return formatted && formatted.length > 2 ? formatted : ''; } delete(format: string, delStr: string) { const re = format.match(/[^(DdMmYy)]{1,}/g); const index = format.indexOf(delStr); if (index < 0) { return format; } else if (index === 0) { if (re) { return format.substring(3); } else { return format.substring(2); } } else if (index + 2 === format.length) { if (re) { return format.substring(0, format.length - 3); } else { return format.substring(0, format.length - 2); } } else { if (re) { return format.substring(0, index) + format.substring(index + 3); } else { return format.substring(0, index) + format.substring(index + 2); } } } getFormattedDate(model: IMyDateModel): string { return !model.isRange ? model.singleDate.formatted : model.dateRange.formatted; } preZero(val: number): string { return val < 10 ? ZERO_STR + Number(val) : String(val); } isInitializedDate(date: IMyDate): boolean { return date && date.year !== 0 && date.month !== 0 && date.day !== 0; } isInitializedMonth(date: IMyDate): boolean { return date && date.year !== 0 && date.month !== 0; } isInitializedYear(date: IMyDate): boolean { return date && date.year !== 0; } isDateEarlier(firstDate: IMyDate, secondDate: IMyDate): boolean { return this.getTimeInMilliseconds(firstDate) < this.getTimeInMilliseconds(secondDate); } isDateSameOrEarlier(firstDate: IMyDate, secondDate: IMyDate): boolean { return this.getTimeInMilliseconds(firstDate) <= this.getTimeInMilliseconds(secondDate); } isDateSame(firstDate: IMyDate, secondDate: IMyDate): boolean { return this.getTimeInMilliseconds(firstDate) === this.getTimeInMilliseconds(secondDate); } isDateRangeBeginOrEndSame(dateRange: IMyDateRange, date: IMyDate): boolean { const dateMs: number = this.getTimeInMilliseconds(date); return ( this.getTimeInMilliseconds(dateRange.begin) === dateMs || this.getTimeInMilliseconds(dateRange.end) === dateMs ); } isDateInRange(date: IMyDate, dateRange: IMyDateRange): boolean { if (!this.isInitializedDate(dateRange.begin) || !this.isInitializedDate(dateRange.end)) { return false; } return this.isDateSameOrEarlier(dateRange.begin, date) && this.isDateSameOrEarlier(date, dateRange.end); } resetDate(): IMyDate { return { year: 0, month: 0, day: 0 }; } getTimeInMilliseconds(date: IMyDate): number { return this.getDate(date).getTime(); } getDate2(date: IMyDate): Date { const now = new Date(); if (!date.year) { date.year = now.getFullYear(); } if (!date.month) { date.month = now.getMonth() + 1; } if (!date.day) { date.day = 1; } return new Date( date.year, date.month - 1, date.day, date.hour ? date.hour : 0, date.minute ? date.minute : 0, date.second ? date.second : 0, 0 ); } getDate(date: IMyDate): Date { return new Date( date.year || 0, date.month ? date.month - 1 : 0, date.day || 0, date.hour ? date.hour : 0, date.minute ? date.minute : 0, date.second ? date.second : 0, 0 ); } getDayNumber(date: IMyDate): number { return new Date( date.year, date.month - 1, date.day, date.hour ? date.hour : 0, date.minute ? date.minute : 0, date.second ? date.second : 0, 0 ).getDay(); } getWeekdayIndex(wd: string) { return this.weekDays.indexOf(wd); } getEpocTime(date: IMyDate): number { return Math.round(this.getTimeInMilliseconds(date) / 1000.0); } getKeyCodeFromEvent(event: any): number { const key: any = event.key || event.keyCode; if (key === KeyName.enter || key === KeyCode.enter) { return KeyCode.enter; } else if (key === KeyName.esc || key === KeyCode.esc) { return KeyCode.esc; } else if (key === KeyName.space || key === KeyCode.space) { return KeyCode.space; } else if (key === KeyName.leftArrow || key === KeyCode.leftArrow) { return KeyCode.leftArrow; } else if (key === KeyName.upArrow || key === KeyCode.upArrow) { return KeyCode.upArrow; } else if (key === KeyName.rightArrow || key === KeyCode.rightArrow) { return KeyCode.rightArrow; } else if (key === KeyName.downArrow || key === KeyCode.downArrow) { return KeyCode.downArrow; } else if (key === KeyName.tab || key === KeyCode.tab) { return KeyCode.tab; } else if (key === KeyName.shift || key === KeyCode.shift) { return KeyCode.shift; } else { return null; } } getNearDate(now: IMyDate, min: IMyDate, max: IMyDate) { const minMilliseconds = this.getTimeInMilliseconds(min) const maxMilliseconds = this.getTimeInMilliseconds(max) const nowMilliseconds = this.getTimeInMilliseconds(now) if (maxMilliseconds - nowMilliseconds > nowMilliseconds - minMilliseconds) { return min; } else { return max; } } // 禁用时间对应的小时 // 选中日期等于左区间日期时,禁用左端点的左部分[0,minHour) // 选中日期等于右区间日期时,禁用右端点的右部分(maxHour,23] disabledHours(min: IMyDate, max: IMyDate, currentDate: IMyDate) { let minHour = min.hour; let maxHour = max.hour; let res = []; if (this.isDateSame({ year: currentDate.year, month: currentDate.month, day: currentDate.day }, { year: min.year, month: min.month, day: min.day })) { while (minHour-- >= 0) { res.push(minHour); } } else if (this.isDateSame({ year: currentDate.year, month: currentDate.month, day: currentDate.day }, { year: max.year, month: max.month, day: max.day })) { while (maxHour++ < 24) { res.push(maxHour); } } return res; } //禁用时间对应的分钟 //选中日期等于左区间日期时,禁用左端点的左部分[0,minMinute) //选中日期等于右区间日期时,禁用右端点的右部分(maxMinute,59] disabledMinutes(min: IMyDate, max: IMyDate, _hour: number, currentDate: IMyDate) { let maxHour = max.hour; let maxMinute = max.minute; let minHour = min.hour; let minMinute = min.minute; let res = []; if (this.isDateSame({ year: currentDate.year, month: currentDate.month, day: currentDate.day }, { year: min.year, month: min.month, day: min.day })) { if (_hour == minHour) { while (minMinute-- >= 0) { res.push(minMinute); } } } else if (this.isDateSame({ year: currentDate.year, month: currentDate.month, day: currentDate.day }, { year: max.year, month: max.month, day: max.day })) { if (_hour == maxHour) { while (maxMinute++ < 60) { res.push(maxMinute); } } } return res; } //禁用时间对应的秒 //选中日期等于左区间日期时,禁用左端点的左部分[0,minSecond) //选中日期等于右区间日期时,禁用右端点的右部分(maxSecond,59] disabledSeconds(min: IMyDate, max: IMyDate, _hour: number, _minute: number, currentDate: IMyDate) { let maxHour = max.hour; let maxMinute = max.minute; let maxSecond = max.second; let minHour = min.hour; let minMinute = min.minute; let minSecond = min.second; let res = []; if (this.isDateSame({ year: currentDate.year, month: currentDate.month, day: currentDate.day }, { year: min.year, month: min.month, day: min.day })) { if (_hour == minHour && _minute == minMinute) { while (minSecond-- >= 0) { res.push(minSecond); } } } else if (this.isDateSame({ year: currentDate.year, month: currentDate.month, day: currentDate.day }, { year: max.year, month: max.month, day: max.day })) { if (_hour == maxHour && _minute == maxMinute) { while (maxSecond++ < 60) { res.push(maxSecond); } } } return res; } }