如何计算没有任何一个月的 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 个日期之间的天数的主要内容,如果未能解决你的问题,请参考以下文章