Coptic Type Calendar Component React Native
Tôi đang cố gắng triển khai lịch không phải của Gregorian có 13 tháng. Và có hai chức năng tôi đã sử dụng để làm điều đó. Một trong số chúng
createCalendar được sử dụng để tạo một ma trận lịch cho mỗi tháng được lập chỉ mục với các ngày trong tuần
function generateCalendar(type = 'en') {
var [etYear, etMonth, etDate] = Ethiopic.toEthiopian(
state.activeDate.getFullYear(),
state.activeDate.getMonth() + 1,
state.activeDate.getDate(),
);
console.log('Month: ', etMonth);
var enYear = state.activeDate.getFullYear();
var enMonth = state.activeDate.getMonth();
var matrix = [];
if (type == 'en') {
matrix = [];
var firstDay = new Date(enYear, enMonth, 1).getDay();
var maxDays = enCalendar.en_days[enMonth];
if (enMonth == 1) {
if ((enYear % 4 == 0 && enYear % 100 != 0) || enYear % 400 == 0) {
maxDays += 1;
}
}
matrix[0] = enCalendar.en_weekDays;
var counter = 1;
for (var row = 1; row < 7; row++) {
matrix[row] = [];
for (var col = 0; col < 7; col++) {
matrix[row][col] = -1;
if (row == 1 && col >= firstDay) {
matrix[row][col] = counter++;
} else if (row > 1 && counter <= maxDays) {
matrix[row][col] = counter++;
}
}
}
} else if (type == 'et') {
matrix = [];
var startDayOfYear = Ethiopic.startDayOfEthiopian(etYear);
// var firstDay = startOfYear + (30 % startDayOfYear);
var firstDayOfYear = new Date(enYear, 8, startDayOfYear).getDay();
var firstDay =
(etMonth - 1) * 2 + firstDayOfYear > 7
? ((etMonth - 1) * 2 + firstDayOfYear) % 7
: (etMonth - 1) * 2 + firstDayOfYear;
var maxDays = etCalendar.et_days[etMonth - 1];
console.log(maxDays);
if (etMonth == 13) {
if (etYear % 4 == 3) {
maxDays += 1;
}
}
matrix[0] = etCalendar.et_weekDays;
var counter = 1;
for (var row = 1; row < 7; row++) {
matrix[row] = [];
for (var col = 0; col < 7; col++) {
matrix[row][col] = -1;
if (row == 1 && col >= firstDay) {
matrix[row][col] = counter++;
} else if (row > 1 && counter <= maxDays) {
matrix[row][col] = counter++;
}
}
}
}
return matrix;
}
Và cái còn lại là changeMonth thêm một tháng và thay đổi trạng thái do đó tạo ra một ma trận mới.
function changeMonth(n) {
setState({
activeDate: new Date(state.activeDate.setMonth(state.activeDate.getMonth() + n))
});
}
Vấn đề ở đây là lịch ethiopian có 13 tháng vì vậy tôi không thể sử dụng setmonth và tăng giảm và chuyển đổi trở lại ethiopian vì activeDate xác định số tháng là 12 cho Gregorian. Vì vậy, setmonth đặt lại sau 11 và chỉ hoạt động trong 12 tháng
Nhưng vì mỗi tháng trong lịch ethiopian là 30 ngày ngoại trừ tháng cuối cùng có 5 hoặc 6 ngày, tôi muốn làm cho nó quay vòng qua các tháng khi tăng hoặc giảm các tháng và có thể sau đó tôi có thể chuyển đổi trở lại thành Gregorian và đặt hoạt động Ngày.
Trả lời
Bạn cần giải thích các quy tắc để thêm một tháng Coptic.
Ví dụ: thêm một tháng vào các ngày trong tháng 1 đến tháng 11 có thể chỉ là thêm 30 ngày. Đối với các ngày trong tháng 12, việc thêm 30 ngày có thể đẩy ngày vượt quá tháng thứ 13 sang tháng đầu tiên của năm sau. Trong trường hợp này, ngày này có nên được giới hạn đến ngày cuối cùng của tháng 13 không? Vì vậy, việc thêm 1 tháng vào 30/12/1737 (5/9/2021) sẽ thành 13/5/1737 thay vì 25/01/1738 (30 ngày sau).
Tương tự, nên thêm một tháng vào 1/13/1737 là 1/01/1738 (tức là số cùng ngày trong tháng tiếp theo) hay 26/01/1738 (30 ngày sau)?
Với một Ngày ECMAScript gốc, bạn có thể thêm một tháng Coptic bằng cách:
- Nhận ngày Coptic tương đương
- Nếu tháng Coptic từ 1 đến 11, hãy thêm 30 ngày
- Nếu tháng Coptic là 12, hãy thêm 30 ngày và nếu ngày vượt quá cuối tháng 13, hãy đặt nó thành ngày cuối cùng của tháng 13
- Nếu tháng Coptic là 13, hãy đặt ngày đó vào cùng ngày trong tháng tiếp theo
Ví dụ
// Given a date, return an object with era, year, month
// and day properties and values for the equivalent
// Coptic date
function getCopticDate(date = new Date()) {
return new Intl.DateTimeFormat(
'en-u-ca-coptic', {
year : 'numeric',
month: '2-digit',
day : '2-digit'
}).formatToParts(date).reduce((acc, part) => {
if (part.type != 'literal') {
acc[part.type] = part.value;
}
return acc;
}, Object.create(null));
}
// Given a Date, return a string for the equivalent
// Coptic date
function printCopticDate(date = new Date()) {
let {era, year, month, day} = getCopticDate(date);
return `${day}/${month}/${year} ${era}`;
}
// Given a Date, return a Date with one Coptic month
// added to to the equivalent Coptic date
function addCopticMonth(date) {
let oDate = new Date(date);
let d = getCopticDate(oDate);
// Add 30 days, then deal with months 12 and 13
oDate.setDate(oDate.getDate() + 30)
// If month was 12 and is now not 13, set to
// last day of 13
let e = getCopticDate(oDate);
if (d.month == '12' && e.month != '13') {
oDate.setDate(oDate.getDate() - e.day);
}
// If month was 13, set to same day in next month
if (d.month == '13') {
oDate.setDate(oDate.getDate() - e.day + +d.day)
}
return oDate;
}
// Some tests
// Add 1 month to today
let d = new Date();
console.log('Today is: ' + printCopticDate(d) +
' (' + d.toDateString() + ')');
let e = addCopticMonth(d);
console.log('+1 month: ' + printCopticDate(e) +
' (' + e.toDateString() + ')');
// Add 1 month to 20/12/1737 -> last day of 13th month
let f = new Date(2021, 7, 26);
let g = addCopticMonth(f);
console.log(printCopticDate(f) + ' (' +
f.toDateString() + ') +1 month is\n' +
printCopticDate(g) + ' (' + g.toDateString() + ')');
// Add 1 month to 05/13/1737 -> same day in first month of next year
let h = addCopticMonth(g);
console.log(printCopticDate(g) + ' (' +
g.toDateString() + ') +1 month is\n' +
printCopticDate(h) + ' (' + h.toDateString() + ')');
Các đòn bẩy trên Intl.DateTimeFormat và nắp thêm một tháng duy nhất, nếu bạn muốn thêm nhiều hơn một hoặc thêm năm, có nhiều việc phải làm ... Nó thực sự chỉ để chứng minh một thuật toán chứ không phải là cung cấp một chức năng mạnh mẽ (ví dụ getCopticDate có lẽ nên được được gọi là getCopticDateParts và các giá trị phải là số không phải là chuỗi, v.v.).