react-native-switch-month-week
Version:
react native calendar with a week and month view
345 lines (312 loc) • 9.98 kB
text/typescript
import XDate from 'xdate'
import moment from 'moment';
import { DATE_FORMAT, NUMBER_OF_PAGES, dayNamesFormatCN, dayNamesFormatHK, dayNamesFormatTW, DayNamesShort } from '../Constants';
import type { Locale } from '../Constants/type';
import type { MarkedDates } from '../MonthWeekCalendar/type';
import _ from 'lodash';
const latinNumbersPattern = /[0-9]/g;
function isValidXDate(date: Date) {
return date && (date instanceof XDate);
}
export const chunkRight = (arr: any[], size: number) => {
const rm = arr.length % size;
return rm ?
[arr.slice(0, rm), ..._.chunk(arr.slice(rm), size)]
:
_.chunk(arr, size);
};
export const getYearMonthLocale = (date: string, locale: Locale) => {
const d = moment(date);
switch (locale) {
case 'en':
return d.isSame(moment(), 'year') ? d.format('MMMM') : `${d.format('MMMM')} ${d.format('YYYY')}`;
case 'cn':
return d.isSame(moment(), 'year') ? d.format('M') + '月' : d.format('yyyy年MM月');
case 'hk':
return d.isSame(moment(), 'year') ? d.format('M') + '月' : d.format('yyyy年MM月');
case 'tw':
return d.isSame(moment(), 'year') ? d.format('M') + '月' : d.format('yyyy年MM月');
default:
return '';
}
}
export const getRangeWeekLocale = (date: string, locale: Locale) => {
const d = moment(date);
const endWeek = moment(date).add(6, 'day');
switch (locale) {
case 'en':
return `Week ${d.week()}, ${d.format('MMM D')} - ${endWeek.format('MMM D')}`;
case 'cn':
return `第 ${d.week()} 周, ${d.format('M 月 D 日')} - ${endWeek.format('M 月 D 日')}`;
case 'hk':
return `第 ${d.week()} 週, ${d.format('M 月 D 日')} - ${endWeek.format('M 月 D 日')}`;
case 'tw':
return `第 ${d.week()} 週, ${d.format('M 月 D 日')} - ${endWeek.format('M 月 D 日')}`;
default:
return '';
}
}
export const generateDates = (date: string, firstDay: number = 0) => {
const d = moment(date).subtract(NUMBER_OF_PAGES, 'month').startOf('month');
const array: string[] = [];
const weekArray: string[] = []
for (let index = 0; index < NUMBER_OF_PAGES * 2 + 1; index++) {
const newDate = d.add(index > 0 ? 1 : 0, 'month').format('YYYY-MM-DD')
array.push(newDate)
}
// week
let dayOfTheWeek = moment(array[0]).day();
if (dayOfTheWeek < firstDay && firstDay > 0) {
dayOfTheWeek = 7 + dayOfTheWeek;
}
const startWeek: any = moment(array[0]).subtract(Math.abs(firstDay - dayOfTheWeek), 'day')
const endWeek: any = moment(array[array.length - 1])
const weekLength = endWeek.diff(startWeek, 'week') + 6;
for (let index = 0; index < weekLength; index++) {
if (!index) {
weekArray.push(startWeek.format('YYYY-MM-DD'))
continue;
}
weekArray.push(startWeek.add(1, 'week').format('YYYY-MM-DD'))
}
return [array, weekArray];
}
export function sameMonth(date1: string, date2: string) {
return moment(date1).isSame(date2, 'month');
}
export function sameWeek(a: string, b: string, firstDayOfWeek: number = 0) {
const weekDates = getWeekDates(a, firstDayOfWeek, 'yyyy-MM-dd');
const element = weekDates instanceof XDate ? new XDate(b) : b;
return weekDates?.includes(element);
}
export const getCol = (date: string) => {
return moment(date).day()
}
export const getMonthRows = (dateStr: string) => {
// 周几
const day = moment(dateStr).startOf('month').day();
const endDay = moment(dateStr).endOf('month').date();
return Math.ceil((day + endDay) / 7)
}
export const beforeDayOfWeek = (dayOfTheWeek: number, firstDayOfWeek: number) => {
if (dayOfTheWeek < firstDayOfWeek && firstDayOfWeek > 0) {
dayOfTheWeek = 7 + dayOfTheWeek;
}
return Math.abs(firstDayOfWeek - dayOfTheWeek);
}
export const getRowAboveTheWeek = (dateStr: string, firstDay: number = 0) => {
const day = moment(dateStr).startOf('month').day();
const beforeDay = beforeDayOfWeek(day, firstDay)
const endDay = moment(dateStr).date();
return Math.ceil((beforeDay + endDay) / 7) - 1;
}
export const getRowPrevMonthLastDay = (dateStr: string, firstDay: number = 0) => {
const day = moment(dateStr).subtract(1, 'month').endOf('month').format(DATE_FORMAT)
return getRowAboveTheWeek(day, firstDay)
}
export const getRowInPage = (dateStr: string, firstDay: number = 0) => {
return getRowPrevMonthLastDay(dateStr, firstDay) + getRowAboveTheWeek(dateStr, firstDay)
}
export function sameDate(a, b) {
if (!isValidXDate(a) || !isValidXDate(b)) {
return false;
}
else {
return a?.getFullYear() === b?.getFullYear() && a?.getMonth() === b?.getMonth() && a?.getDate() === b?.getDate();
}
}
export function isPastDate(date) {
const today = new XDate();
const d = new XDate(date);
if (today.getFullYear() > d.getFullYear()) {
return true;
}
if (today.getFullYear() === d.getFullYear()) {
if (today.getMonth() > d.getMonth()) {
return true;
}
if (today.getMonth() === d.getMonth()) {
if (today.getDate() > d.getDate()) {
return true;
}
}
}
return false;
}
export function isToday(date) {
const d = date instanceof XDate ? date : new XDate(date);
return sameDate(d, XDate.today());
}
export function isGTE(a, b) {
return b.diffDays(a) > -1;
}
export function isLTE(a, b) {
return a.diffDays(b) > -1;
}
export function formatNumbers(date) {
const numbers = getLocale().numbers;
return numbers ? date.toString().replace(latinNumbersPattern, (char) => numbers[+char]) : date;
}
function fromTo(a: Date, b: Date) {
const days = [];
let from = +a;
const to = +b;
for (; from <= to; from = new XDate(from, true).addDays(1).getTime()) {
days.push(new XDate(from, true));
}
return days;
}
export function month(date) {
const year = date.getFullYear(), month = date.getMonth();
const days = new XDate(year, month + 1, 0).getDate();
const firstDay = new XDate(year, month, 1, 0, 0, 0, true);
const lastDay = new XDate(year, month, days, 0, 0, 0, true);
return fromTo(firstDay, lastDay);
}
export function weekDayNames(firstDayOfWeek = 0, locale = 'en') {
let weekDaysNames = DayNamesShort[locale as Locale];
const dayShift = firstDayOfWeek % 7;
if (dayShift) {
weekDaysNames = weekDaysNames.slice(dayShift).concat(weekDaysNames.slice(0, dayShift));
}
return weekDaysNames;
}
export function getMonthDates(date: string, firstDayOfWeek = 0, showSixWeeks = false) {
//days [1-31]
const d = new XDate(date);
const days = month(d);
let before: any = [];
let after: any = [];
const fdow = (7 + firstDayOfWeek) % 7 || 7;
const ldow = (fdow + 6) % 7;
firstDayOfWeek = firstDayOfWeek || 0;
const from = days[0].clone();
const daysBefore = from.getDay();
if (from.getDay() !== fdow) {
from.addDays(-(from.getDay() + 7 - fdow) % 7);
}
const to = days[days.length - 1].clone();
const day = to.getDay();
if (day !== ldow) {
to.addDays((ldow + 7 - day) % 7);
}
if (showSixWeeks) {
to.addDays(7);
// console.log('daysBefore :>> ',firstDayOfWeek, date, daysBefore, days.length);
if (
daysBefore === firstDayOfWeek &&
days.length === 28
) {
to.addDays(7);
}
}
if (isLTE(from, days[0])) {
before = fromTo(from, days[0]);
}
if (isGTE(to, days[days.length - 1])) {
after = fromTo(days[days.length - 1], to);
}
return before.concat(days.slice(1, days.length - 1), after);
}
export function isDateNotInRange(date, minDate, maxDate) {
return (minDate && !isGTE(date, new XDate(minDate))) || (maxDate && !isLTE(date, new XDate(maxDate)));
}
export function getWeekDates(date, firstDay = 0, format) {
const d = new XDate(date);
if (date && d.valid()) {
const daysArray = [d];
let dayOfTheWeek = d.getDay() - firstDay;
if (dayOfTheWeek < 0) {
// to handle firstDay > 0
dayOfTheWeek = 7 + dayOfTheWeek;
}
let newDate = d;
let index = dayOfTheWeek - 1;
while (index >= 0) {
newDate = newDate.clone().addDays(-1);
daysArray.unshift(newDate);
index -= 1;
}
newDate = d;
index = dayOfTheWeek + 1;
while (index < 7) {
newDate = newDate.clone().addDays(1);
daysArray.push(newDate);
index += 1;
}
if (format) {
return daysArray.map(d => d.toString(format));
}
return daysArray;
}
}
export function getPartialWeekDates(date, numberOfDays = 7) {
let index = 0;
const partialWeek = [];
while (index < numberOfDays) {
partialWeek.push(generateDay(date || new XDate(), index));
index++;
}
return partialWeek;
}
export function generateDay(originDate, daysOffset = 0) {
const baseDate = originDate instanceof XDate ? originDate : new XDate(originDate);
return toMarkingFormat(baseDate.clone().addDays(daysOffset));
}
export function getLocale() {
return XDate.locales[XDate.defaultLocale];
}
export function padNumber(n) {
if (n < 10) {
return '0' + n;
}
return n;
}
export function xdateToData(date) {
const d = date instanceof XDate ? date : new XDate(date);
const dateString = toMarkingFormat(d);
return {
year: d.getFullYear(),
month: d.getMonth() + 1,
day: d.getDate(),
timestamp: new XDate(dateString, true).getTime(),
dateString: dateString
};
}
export function parseDate(d) {
if (!d) {
return;
}
else if (d.timestamp) {
// conventional data timestamp
return new XDate(d.timestamp, true);
}
else if (d instanceof XDate) {
// xdate
return new XDate(toMarkingFormat(d), true);
}
else if (d.getTime) {
// javascript date
const dateString = d.getFullYear() + '-' + padNumber(d.getMonth() + 1) + '-' + padNumber(d.getDate());
return new XDate(dateString, true);
}
else if (d.year) {
const dateString = d.year + '-' + padNumber(d.month) + '-' + padNumber(d.day);
return new XDate(dateString, true);
}
else if (d) {
// timestamp number or date formatted as string
return new XDate(d, true);
}
}
export function toMarkingFormat(d) {
if (!isNaN(d.getTime())) {
const year = `${d.getFullYear()}`;
const month = d.getMonth() + 1;
const doubleDigitMonth = month < 10 ? `0${month}` : `${month}`;
const day = d.getDate();
const doubleDigitDay = day < 10 ? `0${day}` : `${day}`;
return year + '-' + doubleDigitMonth + '-' + doubleDigitDay;
}
return 'Invalid Date';
}