日期算术

时间:2018-01-18 10:29:25

标签: haskell

addDays :: (Int,Int,Int) -> Int -> (Int,Int,Int)
addDays (dd,mm,yy) daystoadd =
    let yearType =  if((yy `mod` 4 ==0) && ((yy `mod` 100 /=0)||(yy `mod` 400 ==0)))
                        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]
        sumYear = (sum yearType)
        daysGone =sum ( (take (mm-1) ) yearType ) + dd
        totalDays = daysGone   + daystoadd
        yearsOverflow = totalDays `div` sumYear                                                  
        totalDays1 = totalDays `mod` sumYear


    year = yy+yearsOverflow
    monthsGone =last ( takeWhile (\x -> sum x <=totalDays1) ((inits(yearType) ) ) )


    daysofMonth = if (totalDays1 - (sum monthsGone) == 0) 
                        then ( yearType!!(mm-1) ) 
                  else if (totalDays1 <= (yearType!!(mm-1)) )                  
                        then totalDays1 
                  else (totalDays1 - (sum monthsGone) )

    noofMonths = if (monthsGone/= [])
                    then if ( ((length monthsGone) )>12) 
                            then ((length monthsGone)+1-12 ) 
                        else if( (last monthsGone) == daysofMonth )
                            then ( (length monthsGone) )                                                                                                                                                                                           --then ( (length monthsGone)+2 )
                        else ( (length monthsGone)+1 )                               
                 else  (length monthsGone) +1                                                 

in (daysofMonth,noofMonths, year)

我已编写此功能以添加日期的天数。但是,如果我想从2000年5月1日起增加400天,那么每当它超过31日时,就会使用相同月份的闰年。如何再次使用非闰年?

我面临的另一个问题是月份有30天,月份会在下个月的月末发生变化。

有什么建议吗?

Dan Robertson解释道 我做了这个

import Data.List



isLeapYear :: Int -> Bool
isLeapYear x = ((x `mod` 4 ==0) && ((x `mod` 100 /=0)||(x `mod` 400 ==0)))



yearLength :: Int -> Int
yearLength n = if (isLeapYear n) then 366 else 365


monthLength :: Int -> Int -> [Int]
monthLength mm yy =  
let months = 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]
in months


leftInMonth :: (Int,Int,Int) -> Int
leftInMonth (dd,mm,yy) = ( (monthLength mm 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 mm yy) ) 



leftInYear :: (Int,Int,Int) -> Int
leftInYear (dd,mm,yy) = yearLength (yy) - (daysSinceYearBegan (dd,mm,yy) ) +1



addDays :: (Int,Int,Int) -> Int -> (Int,Int,Int)
addDays (dd,mm,yy) days =  
                        if ( days >= leftInYear (dd,mm,yy))
                            then addDays (1,1,(yy+1)) (days- (leftInYear (dd,mm,yy)) )                            
                        else if ( days >= leftInMonth (dd,mm,yy)  )
                                then if((mm)<=12 ) 
                                        then addDays (dd,mm+1,yy) (days- (leftInMonth (dd,mm,yy) ) )
                                      else addDays (1,1,yy+1) (days- (leftInMonth (dd,mm,yy) ) )                                     
                        else ( (dd + days),mm,yy)

1 个答案:

答案 0 :(得分:2)

这是如何解决问题的草图。我们将坚持公历(所以像闰年这样的事情以及月份是固定的)。

我们需要一个日期的数据类型。

data Date = Date {year :: Int, month :: Int, day :: Int }

您可以在月份和日期使用较小的类型,但我认为没有充分理由限制年限。您还可以使用具有1月,2月等变体的月份类型。我们将从1到12编号。

一年中有多少天?

leapYear n = n `mod` 4 == 0 && (n `mod` 100 /= 0 || n `mod` 400 == 0)
yearLength n = if leapYear n then 366 else 365

一个月有多少天?

monthLength year month = months !! month where
  months = if leapYear year then months2 else months1
  months1 = [31,28,31,30,31,30,31,31,30,31,30,31]
  months2 = [31,29,31,30,31,30,31,31,30,31,30,31]

现在我们如何添加一些日期? 首先,我们计算出要继续前进多少年。然后多少个月。然后多少天。所以我们想知道一个月或一年剩下多少天。

leftInMonth (Date year month day) = monthLength year month - day + 1
daysSinceYearBegan (Date year month day) = previousMonths + day - 1 where
 previousMonths = sum [monthLength m | m <- [1..month - 1]]
leftInYear date = yearLength (year date) - daysSinceYearBegan date

现在添加天数:

addDays date 0 = date
addDays (Date year 1 1) days
  | days < 0 = undefined
  | days >= yearLength year = addDays (Date (year+1) 1 1) (days - yearLength year)
addDays d@(Date year month day) days
  | days < 0 = undefined
  | days >= leftInYear d = addDays (Date (year+1) month day) (days - leftInYear d)
  | days >= leftInMonth year month = addDays (if month == 12 then Date (year+1) 1 1) else Date year (month+1) 1) (days - leftInMonth year month)
  | otherwise = Date year month (day + days)

我不确定它是否完美,但应该给你一些更合理的工作