如何计算没有任何一个月的 31 日的 2 个日期之间的天数

Posted

技术标签:

【中文标题】如何计算没有任何一个月的 31 日的 2 个日期之间的天数【英文标题】:How to calculate the days between 2 dates without 31st of any month 【发布时间】:2017-02-26 22:06:53 【问题描述】:

主要目标:

我想按每个月的 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))

【问题讨论】:

如果您更新您的问题以包含您实际尝试使用此代码解决的问题,您可能会获得更好的帮助。可能有更好的解决方案。 谢谢,改了,可能现在会更好 我还是不明白你的问题。以及您尝试做的事情。我错过了daysPassed 的定义。 您可以将您的 if 语句缩短为:if (componentsForStatement.day == 31 daysPassed -= 1,因为在其他飞蛾中,.day == 31 永远不会正确 请描述你的大目标——为什么你需要这个代码 sn-p? 【参考方案1】:

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

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  

【讨论】:

请检查我的答案【参考方案2】:

感谢@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)!

【讨论】:

如果从月中开始,则在第一个月,如果是在 31 天的月份,则您切断一天。 2月没有规定实施 还有一个问题是,如果开始和结束日期在一个月的第 31 天的同一个月内 @muescha 我检查了实践,它非常完美。对于 2 月,逻辑相同 +=2 表示 2 月 28 日,然后 -=1 表示 2 月 29 日(如果存在) 但不在您的代码 sn-p 中 - 我在那里看不到 2 月的计算

以上是关于如何计算没有任何一个月的 31 日的 2 个日期之间的天数的主要内容,如果未能解决你的问题,请参考以下文章

如何在目标c中获得该月的第n个星期日日期?

合同终止日期是怎么算

过去 13 个完整月的 SQL WHERE 子句

dateserial是啥意思

java 怎么获取一个月的日期

查询两个日期相差的月数和剩下的天数