Coptic Type Calendar Component React Native
Sto cercando di implementare un calendario non gregoriano che abbia 13 mesi. E c'erano due funzioni che stavo usando per farlo. Uno di loro
generateCalendar viene utilizzato per creare una matrice di calendario per ogni mese indicizzato con i giorni della settimana
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;
}
E l'altro è changeMonth che aggiunge un mese e cambia lo stato creando così una nuova matrice.
function changeMonth(n) {
setState({
activeDate: new Date(state.activeDate.setMonth(state.activeDate.getMonth() + n))
});
}
Il problema qui è che il calendario etiope ha 13 mesi, quindi non posso usare setmonth e incrementarlo o decrementarlo e riconvertirlo in etiope perché activeDate determina il numero del mese che è 12 per gregoriano. Quindi setmonth si ripristina dopo 11 e funziona solo per 12 mesi
Ma poiché ogni mese nel calendario etiope è di 30 giorni tranne l'ultimo mese che ha 5 o 6 giorni, ho voluto fare in modo che scorresse i mesi quando si incrementano o decrementano i mesi e forse poi posso riconvertire a gregoriano e impostare il activeDate.
Risposte
Devi spiegare quali sono le regole per aggiungere un mese copto.
Ad esempio, l'aggiunta di un mese alle date da 1 a 11 può significare solo aggiungere 30 giorni. Per le date nel mese 12, l'aggiunta di 30 giorni può far passare la data oltre il tredicesimo mese, quindi nel primo mese dell'anno successivo. In questo caso, la data dovrebbe essere limitata all'ultimo giorno del mese 13? In modo che l'aggiunta di 1 mese al 30/12/1737 (5 settembre 2021) vada a 5/13/1737 anziché 25/01/1738 (30 giorni dopo).
Allo stesso modo, l'aggiunta di un mese a 1/13/1737 dovrebbe essere 1/01/1738 (ovvero lo stesso numero di giorno nel mese successivo) o 26/01/1738 (30 giorni dopo)?
Data una data ECMAScript nativa, puoi aggiungere un mese copto:
- Ottieni la data copta equivalente
- Se il mese copto è compreso tra 1 e 11, aggiungi 30 giorni
- Se il mese copto è 12, aggiungi 30 giorni e se la data va oltre la fine del mese 13, impostala all'ultimo giorno del mese 13
- Se il mese copto è 13, imposta la data sullo stesso giorno del mese successivo
Per esempio
// 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() + ')');
Quanto sopra fa leva su Intl.DateTimeFormat e copre l'aggiunta di un singolo mese, se vuoi aggiungere più di uno o aggiungere anni, c'è più lavoro da fare ... È solo per dimostrare un algoritmo piuttosto che fornire una funzione robusta (ad esempio, getCopticDate dovrebbe probabilmente essere chiamato getCopticDateParts ei valori dovrebbero essere numeri non stringhe, ecc.).