科普特类型日历组件React Native [英] Coptic Type Calendar Component React Native

查看:40
本文介绍了科普特类型日历组件React Native的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实施一个有13个月的非公历.我使用了两个功能来做到这一点.其中之一

I'm trying to implement a non-gregorian calendar which has 13 months. And there were two functions I was using to do that. One of them

generateCalendar用于为每个以工作日索引的月份创建一个日历矩阵

generateCalendar is used to create a matrix of calendar for each month indexed with the week days

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

另一个是changeMonth,它添加一个月并更改状态,从而创建一个新矩阵.

And the other is changeMonth which adds a month and changes the state thus creating a new matrix.

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

这里的问题是埃塞俄比亚日历有13个月,所以我不能使用setmonth以及递增或递减的setmonth并转换回埃塞俄比亚,因为activeDate确定了公历为12的月份数.所以setmonth会在11点后重置,并且只能使用12个月

The problem here is the ethiopian calendar has 13 months so I can't use setmonth and increment or decrement that and convert back to ethiopian because the activeDate determines the number of month which is 12 for gregorian. So setmonth resets after 11 and only works for 12 months

但是,由于埃塞俄比亚历法中的每个月都是30天,除了上个月有5或6天,所以我想这样做,以便它在递增或递减月份时循环经过几个月,也许然后我可以转换回公历并设置activeDate.

But since every month in ethiopian calendar is 30 days except the last month which has 5 or 6 days, I wanted to make it so that it cycles through the months when incrementing or decrementing months and maybe then I can convert back to gregorian and set the activeDate.

推荐答案

您需要解释添加科普特月份的规则.

You need to explain what the rules are for adding a Coptic month.

例如,在1到11个月的日期中添加一个月可以只增加30天.对于第12个月中的日期,增加30天可能会将日期推迟到第13个月之后,因此会推迟到第二年的第一个月.在这种情况下,日期是否应限制在第13个月的最后一天?因此,将1个月添加到30/12/1737(2021年9月5日)将变为5/13/1737,而不是25/01/1738(30天后).

For example, adding a month to dates in months 1 to 11 can be just adding 30 days. For dates in month 12, adding 30 days may push the date beyond the 13th month so into the first month of the following year. In this case, should the date be limited to the last day of month 13? So that adding 1 month to 30/12/1737 (5 Sep 2021) goes to 5/13/1737 rather than 25/01/1738 (30 days later).

同样,将1/13/1737加一个月应该是1/01/1738(即下个月的同一天)还是26/01/1738(30天后)?

Similarly, should adding one month to 1/13/1737 be 1/01/1738 (i.e. same day number in the following month) or 26/01/1738 (30 days later)?

鉴于本地ECMAScript日期,您可以通过以下方式添加科普特月份:

Given a native ECMAScript Date, you can add a Coptic month by:

  1. 获取等效的科普特日期
  2. 如果科普特月是1到11,则增加30天
  3. 如果科普特月份是12月,则添加30天,如果日期超出了13月末,则将其设置为13月的最后一天
  4. 如果科普特月份是13,则将日期设置为下个月的同一天

例如

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

以上内容利用了 Intl.DateTimeFormat ,涉及添加一个月,如果要添加一个以上或添加几年,则还有更多工作要做……这实际上只是演示算法而不是提供强大的功能(例如, getCopticDate 应该被称为 getCopticDateParts ,其值应该是数字而不是字符串,等等.)

The above leverages Intl.DateTimeFormat and covers adding a single month, if you want to add more than one or add years, there's more work to do… It's really just to demonstrate an algorithm rather than provide a robust function (e.g. getCopticDate should probably be called getCopticDateParts and the values should be numbers not strings, etc.).

这篇关于科普特类型日历组件React Native的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆