【问题标题】:Coptic Type Calendar Component React Native科普特类型日历组件 React Native
【发布时间】:2020-10-20 18:19:01
【问题描述】:

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

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

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,它增加一个月并改变状态,从而创建一个新矩阵。

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

这里的问题是埃塞俄比亚历有 13 个月,所以我不能使用 setmonth 并增加或减少它并转换回埃塞俄比亚历,因为 activeDate 决定了公历的月份数为 12。所以 setmonth 在 11 之后重置,并且只工作 12 个月

但是由于埃塞俄比亚历中的每个月都是 30 天,除了最后一个月有 5 天或 6 天,我想让它在增加或减少月份时循环通过月份,也许然后我可以转换回公历并设置活动日期。

【问题讨论】:

  • 您可以考虑利用 toLocaleString 的功能来使用不同的日历,例如科普特日历中的今天日期由:new Date().toLocaleString('en-GB-u-ca-coptic') 给出。 Date.prototypemonthyear 函数是基于公历的,对于任何其他日历,您必须自己弄清楚. :-)
  • 有没有办法扩展 Date.prototype 让它可以多出一个月?
  • 是的,但这不是一个好主意。

标签: javascript reactjs react-native date


【解决方案1】:

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

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

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

给定原生 ECMAScript 日期,您可以通过以下方式添加科普特月份:

  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 并且值应该是数字而不是字符串等)。

【讨论】:

  • 非常感谢,这对您很有帮助
猜你喜欢
  • 2021-07-20
  • 1970-01-01
  • 2017-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-30
  • 2015-03-30
相关资源
最近更新 更多