You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React版FullCalendar中添加希吉拉日历(Hijri Calendar)并设置其为起始日期(支持月视图与列表月视图)

Hey there! I've worked through similar requirements for integrating Hijri calendar support with FullCalendar in React, so let's walk through exactly how to make your month and listMonth views follow Hijri start dates instead of Gregorian.

Step 1: Install a Hijri Date Conversion Library

First, we need a reliable way to convert between Gregorian and Hijri dates. I recommend hijri-date-converter for its simplicity and lightweight footprint:

npm install hijri-date-converter
# or
yarn add hijri-date-converter
Step 2: Build Utility Functions for Date Conversion

Create helper functions to map Hijri months to their corresponding Gregorian date ranges—this is the core of making FullCalendar respect Hijri start/end dates:

import { toHijri, toGregorian } from 'hijri-date-converter';

// Get the Gregorian start/end dates for a given Hijri year/month
const getHijriMonthGregorianRange = (hijriYear, hijriMonth) => {
  // Convert Hijri month's first day to Gregorian
  const firstDayGreg = toGregorian(hijriYear, hijriMonth, 1);
  // Calculate last day by getting next month's first day and subtracting 1
  const nextHijriMonth = hijriMonth === 12 ? 1 : hijriMonth + 1;
  const nextHijriYear = hijriMonth === 12 ? hijriYear + 1 : hijriYear;
  const lastDayGreg = toGregorian(nextHijriYear, nextHijriMonth, 1);
  lastDayGreg.setDate(lastDayGreg.getDate() - 1);

  // FullCalendar uses exclusive end dates, so add 1 day to the last Gregorian day
  return {
    start: new Date(firstDayGreg.getFullYear(), firstDayGreg.getMonth(), firstDayGreg.getDate()),
    end: new Date(lastDayGreg.getFullYear(), lastDayGreg.getMonth(), lastDayGreg.getDate() + 1)
  };
};

// Get the current Hijri year/month based on today's Gregorian date
const getCurrentHijriYearMonth = () => {
  const today = new Date();
  const hijriToday = toHijri(today.getFullYear(), today.getMonth() + 1, today.getDate());
  return { year: hijriToday.year, month: hijriToday.month };
};
Step 3: Configure FullCalendar with Hijri-Controlled Views

Now, we'll set up the FullCalendar component to use our Hijri-derived date ranges for dayGridMonth and listMonth views. We'll manage the current Hijri year/month with React state:

import React, { useState } from 'react';
import FullCalendar from '@fullcalendar/react';
import dayGridPlugin from '@fullcalendar/daygrid';
import listPlugin from '@fullcalendar/list';

const HijriCalendar = () => {
  const [currentHijri, setCurrentHijri] = useState(getCurrentHijriYearMonth());
  const { start, end } = getHijriMonthGregorianRange(currentHijri.year, currentHijri.month);

  // Customize day cell content to display both Hijri and Gregorian dates
  const dayCellContent = (info) => {
    const gregDate = info.date;
    const hijriDate = toHijri(gregDate.getFullYear(), gregDate.getMonth() + 1, gregDate.getDate());
    return (
      <div className="calendar-day">
        <span className="hijri-day">{hijriDate.day}</span>
        <span className="gregorian-day">{info.dayText}</span>
      </div>
    );
  };

  return (
    <div className="hijri-calendar-container">
      {/* Custom Navigation (replace FullCalendar's default Gregorian navigation) */}
      <div className="calendar-nav">
        <button onClick={() => {
          setCurrentHijri(prev => ({
            year: prev.month === 1 ? prev.year - 1 : prev.year,
            month: prev.month === 1 ? 12 : prev.month - 1
          }));
        }}>← Previous Hijri Month</button>
        <h3>{`${currentHijri.year} AH, Month ${currentHijri.month}`}</h3>
        <button onClick={() => {
          setCurrentHijri(prev => ({
            year: prev.month === 12 ? prev.year + 1 : prev.year,
            month: prev.month === 12 ? 1 : prev.month + 1
          }));
        }}>Next Hijri Month →</button>
      </div>

      <FullCalendar
        plugins={[dayGridPlugin, listPlugin]}
        initialView="dayGridMonth"
        // Force views to use our Hijri-derived Gregorian range
        views={{
          dayGridMonth: {
            type: 'dayGridMonth',
            visibleRange: { start, end }
          },
          listMonth: {
            type: 'listMonth',
            visibleRange: { start, end }
          }
        }}
        dayCellContent={dayCellContent}
        // Hide default navigation (we're using our custom one)
        headerToolbar={{
          left: '',
          center: '',
          right: 'dayGridMonth,listMonth'
        }}
        // Optional: Customize event rendering if needed
        eventContent={(info) => (
          <div>{info.event.title}</div>
        )}
      />
    </div>
  );
};

export default HijriCalendar;
Step 4: Add Basic Styling

Add some CSS to make the Hijri date display clean:

.calendar-day {
  text-align: center;
}

.hijri-day {
  font-size: 0.8rem;
  color: #666;
  display: block;
}

.gregorian-day {
  font-size: 1rem;
  font-weight: 600;
}

.calendar-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
  padding: 0.5rem;
}

.calendar-nav button {
  padding: 0.5rem 1rem;
  cursor: pointer;
}
Step 5: Handle Events with Hijri Dates

If your events are stored as Hijri dates, convert them to Gregorian before passing to FullCalendar:

// Example: Convert Hijri events to Gregorian
const hijriEvents = [
  { title: 'Eid al-Fitr', hijriYear: 1445, hijriMonth: 10, hijriDay: 1 }
];

const gregorianEvents = hijriEvents.map(event => {
  const gregDate = toGregorian(event.hijriYear, event.hijriMonth, event.hijriDay);
  return {
    title: event.title,
    start: new Date(gregDate.getFullYear(), gregDate.getMonth(), gregDate.getDate())
  };
});

// Then pass gregorianEvents to FullCalendar's `events` prop
Key Notes to Keep in Mind
  • FullCalendar operates natively in Gregorian, so we're essentially "tricking" it into displaying Hijri months by mapping them to Gregorian date ranges.
  • The custom navigation ensures users move between Hijri months, not Gregorian ones.
  • Always test edge cases (like Hijri months with 29 vs 30 days) to ensure date ranges are accurate.

内容的提问来源于stack exchange,提问作者zahra honarvar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 04:08:11