如何计算两个日期之间没有任何月份的第31天的天数

时间:2017-02-26 22:06:53

标签: ios swift nsdatecomponents

主要目标:

我想根据每个月的30天计算工资

月份为31,最多可计入30天

let monthlyWage = someValue
let perDay : Double = Double(monthlyWage/30)
let components = calendar.dateComponents([.day], from:startDateDay, to: currentDateDay)
let daysPassed = Double(components.day! + 1)
let componentsForStatement = calendar.dateComponents([.day, .month], from: currentDateDay)
if ((componentsForStatement.month == 01) || 
    (componentsForStatement.month == 03) ||
    (componentsForStatement.month == 05) || 
    (componentsForStatement.month == 07) || 
    (componentsForStatement.month == 08) || 
    (componentsForStatement.month == 10) || 
    (componentsForStatement.month == 12)
   ) && componentsForStatement.day == 31 {
          daysPassed -= 1
        }
let currentMoney = Double(lround(perDay * daysPassed))

2 个答案:

答案 0 :(得分:0)

(我将原始问题更新为评论中的答案)

2016年

10.01.16 Jan ?? (max 31) 21 
   02.16 Feb +1 (max 29) 30
   03.16 Mar -1 (max 31) 30
   04.16 Apr +0 (max 30) 30
12.05.16 May +0 (max 31) 12

或2017年

10.01.17 Jan ?? (max 31) 21 
   02.17 Feb +2 (max 28) 30
   03.17 Mar -1 (max 31) 30
   04.17 Apr +0 (max 30) 30
12.05.17 May +0 (max 31) 12

我用这种方式实现了它:

  • 检查是否在结束前开始
  • 检查同月是否 - >用平均值计算工作天数
  • 否则:在/上个月之间提取第一个月/月并加在一起

这是代码:

import Foundation

func day(_ dateString:String) -> Date {
    let dateStringFormatter = DateFormatter()
    dateStringFormatter.dateFormat = "yyyy-MM-dd"
    let d = dateStringFormatter.date(from: dateString)!
    return Date(timeInterval:0, since:d)
}


func createDate(day: Int, month: Int, year: Int) -> Date {
    let userCalendar = Calendar.current

    var dateComponents = DateComponents()
    dateComponents.day = day
    dateComponents.month = month
    dateComponents.year = year
    return userCalendar.date(from: dateComponents)!
}

func printDate(date: Date) -> String {
    let formatter = DateFormatter()
    formatter.dateStyle = .short
    formatter.timeStyle = .none
    return formatter.string(from: date)
}

func check(from startDate: String, to endDate: String, expected: Int){
    let days = daysBeetweenMax30(from: day(startDate), to: day(endDate))
    let ok = expected == days ? "OK" : "!!"
    let error = expected == days ? "" : "(current: \(days) expected: \(expected))"
    print(" \(ok): \(startDate) -> \(endDate) => \(days)  \(error)")
}

func daysInMonth(of date: Date) -> Int {
    let userCalendar = Calendar.current
    return userCalendar.range(of: .day, in: .month, for: date)!.count
}

func setDayInDate(day: Int, of date: Date) -> Date {
    let userCalendar = Calendar.current
    var components = userCalendar.dateComponents([.day, .month, .year], from: date)
    components.day = day
    return userCalendar.date(from: components)!
}

func daysBeetweenMax30(from startDate: Date, to endDate: Date) -> Int {

//    print("start: \(printDate(date: startDate)) ende:\(printDate(date: endDate))")

    let userCalendar = Calendar.current

    // check order
    guard userCalendar.compare(startDate, to: endDate, toGranularity: .day) != .orderedDescending else {
        print("startDate should be before endDate")
        return 0
    }

    // check if in same month
    guard userCalendar.compare(startDate, to: endDate, toGranularity: .month) != .orderedSame else {
        let components = userCalendar.dateComponents([.day], from:startDate, to: endDate)

        let days = (components.day ?? 0) + 1
        let calculatedDays = Double(30.0 * Double(days) / Double(daysInMonth(of: startDate)))
        let averageDays = Int(calculatedDays.rounded(.toNearestOrAwayFromZero))

//        print("same month")
//        print("daysInMonth: \(daysInMonth(of: startDate))")
//        print("days: \(days)")
//        print( "calculatedDays: \(calculatedDays)")

        return averageDays

//        maximum 30 days - but need to adjust for february .....
//        return min((components.day ?? 0) + 1,30)

    }


    let startDateEnd = setDayInDate(day: daysInMonth(of: startDate), of: startDate)
    let startMonthDays = daysBeetweenMax30(from: startDate, to: startDateEnd)

    let endDateStart = setDayInDate(day: 1, of: endDate)
    let endMonthDays = daysBeetweenMax30(from: endDateStart, to: endDate)

    let components = userCalendar.dateComponents([.month], from:startDateEnd, to: endDateStart)
    let monthBetween = components.month ?? 0
//    print("monthBetween: \(monthBetween)")
    return startMonthDays + monthBetween*30 + endMonthDays
}

检查:

check(from: "2017-05-01", to: "2017-04-01", expected: 0)
print("----")
check(from: "2017-05-01", to: "2017-05-10", expected: 10)
check(from: "2017-05-05", to: "2017-05-09", expected: 5)
check(from: "2017-05-16", to: "2017-05-20", expected: 5)
check(from: "2017-05-30", to: "2017-05-31", expected: 2)
print("----")
check(from: "2017-05-01", to: "2017-05-31", expected: 30)
check(from: "2017-02-01", to: "2017-02-28", expected: 30)
print("----")
check(from: "2017-02-01", to: "2017-02-27", expected: 29)
check(from: "2017-02-01", to: "2017-02-02", expected: 2)
check(from: "2017-02-01", to: "2017-02-13", expected: 14)
check(from: "2017-02-01", to: "2017-02-14", expected: 15)
check(from: "2017-02-01", to: "2017-02-18", expected: 19)
check(from: "2017-02-26", to: "2017-02-28", expected: 3)
print("----")
check(from: "2017-05-30", to: "2017-06-02", expected: 2+2)
check(from: "2017-02-26", to: "2017-03-03", expected: 3+3)
check(from: "2017-05-30", to: "2017-07-02", expected: 2+1*30+2)
check(from: "2017-05-30", to: "2017-08-02", expected: 2+2*30+2)
print("----")
check(from: "2017-01-10", to: "2017-01-31", expected: 21)
check(from: "2017-02-01", to: "2017-02-28", expected: 30)
check(from: "2017-03-01", to: "2017-03-31", expected: 30)
check(from: "2017-04-01", to: "2017-04-30", expected: 30)
check(from: "2017-05-01", to: "2017-05-12", expected: 12)
print("----")
check(from: "2017-01-10", to: "2017-05-12", expected: 123)
check(from: "2017-01-10", to: "2017-05-12", expected: 21+3*30+12)
check(from: "2016-01-10", to: "2016-05-12", expected: 123) // 2016 with leap year
print("    ----")
check(from: "2016-01-10", to: "2017-05-12", expected: 21+(12+3)*30+12)

结果:

startDate should be before endDate
OK: 2017-05-01 -> 2017-04-01 => 0  
----
OK: 2017-05-01 -> 2017-05-10 => 10  
OK: 2017-05-05 -> 2017-05-09 => 5  
OK: 2017-05-16 -> 2017-05-20 => 5  
OK: 2017-05-30 -> 2017-05-31 => 2  
----
OK: 2017-05-01 -> 2017-05-31 => 30  
OK: 2017-02-01 -> 2017-02-28 => 30  
----
OK: 2017-02-01 -> 2017-02-27 => 29  
OK: 2017-02-01 -> 2017-02-02 => 2  
OK: 2017-02-01 -> 2017-02-13 => 14  
OK: 2017-02-01 -> 2017-02-14 => 15  
OK: 2017-02-01 -> 2017-02-18 => 19  
OK: 2017-02-26 -> 2017-02-28 => 3  
----
OK: 2017-05-30 -> 2017-06-02 => 4  
OK: 2017-02-26 -> 2017-03-03 => 6  
OK: 2017-05-30 -> 2017-07-02 => 34  
OK: 2017-05-30 -> 2017-08-02 => 64  
----
OK: 2017-01-10 -> 2017-01-31 => 21  
OK: 2017-02-01 -> 2017-02-28 => 30  
OK: 2017-03-01 -> 2017-03-31 => 30  
OK: 2017-04-01 -> 2017-04-30 => 30  
OK: 2017-05-01 -> 2017-05-12 => 12  
----
OK: 2017-01-10 -> 2017-05-12 => 123  
OK: 2017-01-10 -> 2017-05-12 => 123  
OK: 2016-01-10 -> 2016-05-12 => 123  
----
OK: 2016-01-10 -> 2017-05-12 => 483  

答案 1 :(得分:0)

感谢@muescha的想法,我觉得这个代码很好,不计算一个月的31天:

let components = calendar.dateComponents([.day], from:startContractDateDay, to: currentDateDay)
var daysPassed = Double(components.day! + 1)
var startDay = startContractDateDay
while startDay <= currentDateDay {
    let startDayComponent = calendar.component(.day, from: startDay)
    if startDayComponent == 31 {
       daysPassed -= 1
    }
startDay = calendar.date(byAdding: .day, value: 1, to: startDay)!
}