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

Haskell addDays函数问题咨询:跨年度闰年适配与月份切换异常

Fixing Your Haskell addDays Function: Resolving Leap Year & Month-End Bugs

Great job refactoring your code with Dan Robertson's approach—this recursive structure directly addresses both of your original issues. Let's break down how it fixes each problem, plus a small tweak to make your code even cleaner.

Issue 1: Stuck Using Original Year's Leap Day Array After Crossing Years

Root Cause in Original Code

Your first addDays function calculated yearType once using the initial input year yy, then reused this fixed array for all subsequent calculations—even when you crossed into a new year that might be a common year (or vice versa). For example, adding 400 days to 2000-05-01 lands you in 2001, but your original code still used 2000's leap year month lengths, leading to incorrect day counts.

Fix in Refactored Code

Your refactored code solves this by:

  • Creating a reusable isLeapYear helper to check any year's leap status dynamically
  • Generating month lengths per current year with monthLength yy (we'll tweak this function to remove an unused parameter below)
  • Recursively recalculating month lengths every time you roll over to a new year (like addDays (1,1,yy+1)), ensuring you always use the correct days per month for the year you're working with.

Issue 2: Incorrect Month Switch on 30-Day Month Ends

Root Cause in Original Code

Your original code had convoluted logic for calculating daysofMonth and noofMonths, especially handling edge cases where the total days landed exactly at the end of a month. This led to off-by-one errors, like incorrectly switching months when adding days to the last day of a 30-day month.

Fix in Refactored Code

The recursive approach simplifies this entirely by breaking the problem into clear checks:

  1. First, check if days exceed the remaining days in the current year: If so, roll over to January 1 of the next year and subtract the remaining days in the current year from the total days to add.
  2. If not, check if days exceed the remaining days in the current month: For example, if you're on 2024-04-30 (a 30-day month), leftInMonth returns 1 (since there's 1 day left in the month: the 30th itself). Adding 1 day triggers this condition, so we roll over to May 1 and subtract that 1 remaining day, leaving 0 days to add—resulting in the correct date (1,5,2024).
  3. Otherwise, just add the days to the current date: No edge cases to handle here, since we've already confirmed the days fit within the current month.

Small Tweak for Cleaner Code

Your monthLength function currently takes an unused mm parameter. You can simplify it to:

monthLength :: Int -> [Int]
monthLength yy = if isLeapYear yy 
                 then [31,29,31,30,31,30,31,31,30,31,30,31] 
                 else [31,28,31,30,31,30,31,31,30,31,30,31]

Then update calls to monthLength in other helpers to pass only the year:

leftInMonth :: (Int,Int,Int) -> Int
leftInMonth (dd,mm,yy) = (monthLength yy !! (mm-1)) - dd + 1

daysSinceYearBegan :: (Int,Int,Int) -> Int
daysSinceYearBegan (dd,mm,yy) = if mm == 1 
                                then dd 
                                else dd + sum (take (mm-1) (monthLength yy))

This makes your code more readable and removes unnecessary parameters.


内容的提问来源于stack exchange,提问作者Alexia Desouza

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:43:19