diff --git a/packages/vant/src/calendar/CalendarHeader.tsx b/packages/vant/src/calendar/CalendarHeader.tsx
index 6adae946f..2f707357e 100644
--- a/packages/vant/src/calendar/CalendarHeader.tsx
+++ b/packages/vant/src/calendar/CalendarHeader.tsx
@@ -38,25 +38,33 @@ export default defineComponent({
   emits: ['clickSubtitle', 'panelChange'],
 
   setup(props, { slots, emit }) {
-    const prevMonthDisabled = computed(() => {
-      const prevMonth = getPrevMonth(props.date!);
-      return props.minDate && compareMonth(prevMonth, props.minDate) < 0;
-    });
+    const prevMonthDisabled = computed(
+      () =>
+        props.date &&
+        props.minDate &&
+        compareMonth(getPrevMonth(props.date), props.minDate) < 0,
+    );
 
-    const prevYearDisabled = computed(() => {
-      const prevYear = getPrevYear(props.date!);
-      return props.minDate && compareMonth(prevYear, props.minDate) < 0;
-    });
+    const prevYearDisabled = computed(
+      () =>
+        props.date &&
+        props.minDate &&
+        compareMonth(getPrevYear(props.date), props.minDate) < 0,
+    );
 
-    const nextMonthDisabled = computed(() => {
-      const nextMonth = getNextMonth(props.date!);
-      return props.maxDate && compareMonth(nextMonth, props.maxDate) > 0;
-    });
+    const nextMonthDisabled = computed(
+      () =>
+        props.date &&
+        props.maxDate &&
+        compareMonth(getNextMonth(props.date), props.maxDate) > 0,
+    );
 
-    const nextYearDisabled = computed(() => {
-      const nextYear = getNextYear(props.date!);
-      return props.maxDate && compareMonth(nextYear, props.maxDate) > 0;
-    });
+    const nextYearDisabled = computed(
+      () =>
+        props.date &&
+        props.maxDate &&
+        compareMonth(getNextYear(props.date), props.maxDate) > 0,
+    );
 
     const renderTitle = () => {
       if (props.showTitle) {
diff --git a/packages/vant/src/calendar/test/switch-mode.spec.ts b/packages/vant/src/calendar/test/switch-mode.spec.ts
index 8241e1b30..815bf16b3 100644
--- a/packages/vant/src/calendar/test/switch-mode.spec.ts
+++ b/packages/vant/src/calendar/test/switch-mode.spec.ts
@@ -226,3 +226,36 @@ test('should emit panelChange event', async () => {
   currentDate = getNextMonth(currentDate);
   expect(onPanelChange).toHaveBeenLastCalledWith({ date: currentDate });
 });
+
+test('correctly change the panelDate when the selected date is the last day of each month', async () => {
+  let defaultDate = new Date(2024, 4, 31);
+  const onPanelChange = vi.fn();
+  const wrapper = mount(Calendar, {
+    props: {
+      defaultDate,
+      poppable: false,
+      switchMode: 'month',
+      onPanelChange,
+    },
+  });
+
+  await later();
+  const nextMonth = wrapper.findAll('.van-calendar__header-action')[1];
+
+  await nextMonth.trigger('click');
+  let panelDate = getNextMonth(defaultDate);
+  expect(panelDate).toEqual(new Date(2024, 5, 30));
+  expect(onPanelChange).toHaveBeenLastCalledWith({ date: panelDate });
+
+  defaultDate = new Date(2024, 1, 29);
+  await wrapper.setProps({
+    defaultDate,
+    switchMode: 'year-month',
+  });
+  const nextYear = wrapper.findAll('.van-calendar__header-action')[3];
+
+  await nextYear.trigger('click');
+  panelDate = getNextYear(defaultDate);
+  expect(panelDate).toEqual(new Date(2025, 1, 28));
+  expect(onPanelChange).toHaveBeenLastCalledWith({ date: panelDate });
+});
diff --git a/packages/vant/src/calendar/utils.ts b/packages/vant/src/calendar/utils.ts
index 0da05f7c2..962b720df 100644
--- a/packages/vant/src/calendar/utils.ts
+++ b/packages/vant/src/calendar/utils.ts
@@ -46,12 +46,22 @@ export function getDayByOffset(date: Date, offset: number) {
 export function getMonthByOffset(date: Date, offset: number) {
   const cloned = cloneDate(date);
   cloned.setMonth(cloned.getMonth() + offset);
+
+  if (cloned.getDate() !== date.getDate()) {
+    cloned.setDate(0);
+  }
+
   return cloned;
 }
 
 export function getYearByOffset(date: Date, offset: number) {
   const cloned = cloneDate(date);
   cloned.setFullYear(cloned.getFullYear() + offset);
+
+  if (cloned.getDate() !== date.getDate()) {
+    cloned.setDate(0);
+  }
+
   return cloned;
 }