Composant de calendrier de type copte React Native

Oct 20 2020

J'essaye de mettre en place un calendrier non grégorien qui a 13 mois. Et il y avait deux fonctions que j'utilisais pour faire cela. L'un d'eux

generateCalendar permet de créer une matrice de calendrier pour chaque mois indexée avec les jours de la semaine

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;
  }

Et l'autre est changeMonth qui ajoute un mois et change l'état créant ainsi une nouvelle matrice.

function changeMonth(n) {
    setState({
       activeDate: new Date(state.activeDate.setMonth(state.activeDate.getMonth() + n))
      });
  }

Le problème ici est que le calendrier éthiopien a 13 mois, donc je ne peux pas utiliser setmonth et incrémenter ou décrémenter cela et reconvertir en éthiopien car activeDate détermine le nombre de mois qui est de 12 pour le grégorien. Donc setmonth se réinitialise après 11 et ne fonctionne que pendant 12 mois

Mais comme chaque mois dans le calendrier éthiopien est de 30 jours, sauf le dernier mois qui compte 5 ou 6 jours, je voulais faire en sorte qu'il passe en revue les mois lors de l'incrémentation ou de la décrémentation des mois et peut-être que je pourrai ensuite revenir au grégorien et régler le activeDate.

Réponses

RobG Oct 21 2020 at 13:49

Vous devez expliquer quelles sont les règles pour ajouter un mois copte.

Par exemple, ajouter un mois aux dates des mois 1 à 11 peut être simplement ajouter 30 jours. Pour les dates du 12e mois, l'ajout de 30 jours peut pousser la date au-delà du 13e mois, donc dans le premier mois de l'année suivante. Dans ce cas, la date doit-elle être limitée au dernier jour du mois 13? De sorte que l'ajout d'un mois au 30/12/1737 (5 septembre 2021) passe au 13/05/1737 plutôt qu'au 25/01/1738 (30 jours plus tard).

De même, l'ajout d'un mois au 13/01/1737 devrait-il être le 1/01/1738 (c'est-à-dire le même jour le mois suivant) ou le 26/01/1738 (30 jours plus tard)?

Étant donné une date ECMAScript native, vous pouvez ajouter un mois copte par:

  1. Obtenez la date copte équivalente
  2. Si le mois copte est compris entre 1 et 11, ajoutez 30 jours
  3. Si le mois copte est 12, ajoutez 30 jours et si la date dépasse la fin du mois 13, réglez-le sur le dernier jour du mois 13
  4. Si le mois copte est 13, réglez la date sur le même jour du mois suivant

Par exemple

// 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() + ')');

Ce qui précède s'appuie sur Intl.DateTimeFormat et couvre l'ajout d'un seul mois, si vous voulez en ajouter plus d'un ou ajouter des années, il y a plus de travail à faire ... C'est vraiment juste pour démontrer un algorithme plutôt que de fournir une fonction robuste (par exemple, getCopticDate devrait probablement être appelé getCopticDateParts et les valeurs doivent être des nombres et non des chaînes, etc.).