本月的第一天和最后一天迅速


78

我正在设法迅速获得每月的第一天和最后一天。

到目前为止,我有以下内容:

let dateFormatter = NSDateFormatter()
let date = NSDate()
dateFormatter.dateFormat = "yyyy-MM-dd"
let calendar = NSCalendar.currentCalendar()
let components = calendar.components([.Year, .Month, .Day, .Hour, .Minute, .Second], fromDate: date)

let month = components.month
let year = components.year

let startOfMonth = ("\(year)-\(month)-01")

但是我不确定如何获得最后的约会。我是否缺少内置方法?显然,它必须考虑leap年等。



@FattiKhan快速版本?
user2363025

1
试试github.com/malcommac/SwiftDate 这个库有方法:.endOfMonth()//返回代表发件人日期月份的最后一天的日期
buxik 2015年

无需图书馆,如今这很简单-我在下面输入了2017
Fattie

Answers:


105

您只需使用以下命令即可获得每月的第一天

let components = calendar.components([.Year, .Month], fromDate: date)
let startOfMonth = calendar.dateFromComponents(components)!
print(dateFormatter.stringFromDate(startOfMonth)) // 2015-11-01

要获得该月的最后一天,请添加一个月并减去一天:

let comps2 = NSDateComponents()
comps2.month = 1
comps2.day = -1
let endOfMonth = calendar.dateByAddingComponents(comps2, toDate: startOfMonth, options: [])!
print(dateFormatter.stringFromDate(endOfMonth)) // 2015-11-30

或者,使用rangeOfUnit为您提供开始时间和月份长度的方法:

var startOfMonth : NSDate?
var lengthOfMonth : NSTimeInterval = 0
calendar.rangeOfUnit(.Month, startDate: &startOfMonth, interval: &lengthOfMonth, forDate: date)

对于月份的最后一天的日期,请加上月份的长度减去一秒:

let endOfMonth = startOfMonth!.dateByAddingTimeInterval(lengthOfMonth - 1)

为Swift5更新:

extension Date {
    var startOfDay: Date {
        return Calendar.current.startOfDay(for: self)
    }

    var startOfMonth: Date {

        let calendar = Calendar(identifier: .gregorian)
        let components = calendar.dateComponents([.year, .month], from: self)

        return  calendar.date(from: components)!
    }

    var endOfDay: Date {
        var components = DateComponents()
        components.day = 1
        components.second = -1
        return Calendar.current.date(byAdding: components, to: startOfDay)!
    }

    var endOfMonth: Date {
        var components = DateComponents()
        components.month = 1
        components.second = -1
        return Calendar(identifier: .gregorian).date(byAdding: components, to: startOfMonth)!
    }

    func isMonday() -> Bool {
        let calendar = Calendar(identifier: .gregorian)
        let components = calendar.dateComponents([.weekday], from: self)
        return components.weekday == 2
    }
}

@Martin,如何通过按钮操作获取上一个和下个月[swift]
iDeveloper

@iDeveloper:对不起,但这是一个完全不同的问题,不能简单地在评论中回答。
Martin R

@MartinR:您是否在12月份测试过此代码?
Dhiru

1
FWIW(这可能是新的,不确定)我想您要comps2.day = 0而不是comps2.day = -1天= 1->月初,天= 0->上个月的最后一天,天= -1 ->上个月的第二天到最后一天。还是其他什么东西是错误的,我的代码,但变化-1 - > 0固定事¯\ _(ツ)_ /¯
nickneedsaname

2
@Maks:对于支票“是这个月的日期”,我将计算本月的开始和下个月的开始,而不减去任何东西。然后与if date >= startDate && date < endDate
Martin R

134

Swift 3和4插件扩展

这实际上得到了很多更容易斯威夫特3+:

  1. 您可以在没有保护的情况下进行操作(如果需要,可以这样做,但是由于DateComponents现在是非可选类型,因此不再需要)。
  2. 使用iOS 8 startOfDayForDate(现在为startOfDay),您无需手动将时间设置为12pm,除非您在跨时区进行了一些非常疯狂的日历计算。

值得一提的是,其他一些答案声称您可以通过使用来简化此操作Calendar.current.date(byAdding: .month, value: 0, to: Date())!,但是如果失败,那就是它实际上并没有将一天归零,也不能考虑时区的差异。

干得好:

extension Date {
    func startOfMonth() -> Date {
        return Calendar.current.date(from: Calendar.current.dateComponents([.year, .month], from: Calendar.current.startOfDay(for: self)))!
    }
    
    func endOfMonth() -> Date {
        return Calendar.current.date(byAdding: DateComponents(month: 1, day: -1), to: self.startOfMonth())!
    }
}

print(Date().startOfMonth())     // "2018-02-01 08:00:00 +0000\n"
print(Date().endOfMonth())       // "2018-02-28 08:00:00 +0000\n"

在Swift 3.0中产生警告。 Non-optional expression of type 'Calendar' used in a check for optionals。有什么建议?
Allreadyhome

2
已为Swift 3更新
brandonscript

2
顺便说一句,它给了我增加的意愿,DateComponents(month: 1, day: -1)因为您依赖的是month之前未记录的行为day。例如,如果今天是5月15日,则本月的开始日期是5月1日,如果减去前一天的日期,则会得到5月30日而不是5月31日。在两个单独的操作中执行+1月和-1日似乎更安全。或calendar.range(of:in:for:)改为使用。
罗布

8
月初对我不起作用。它给了我前一天的22:00(所以是上个月的最后一天)。如果我也使用day组件,那么它会起作用: Calendar.current.date(from: Calendar.current.dateComponents([.year, .month, .day], from: Calendar.current.startOfDay(for: self)))!
giorgos.nl

1
对我来说正确的是DateComponents(month:1,second:-1),否则,使用day:-1,您将获得最后一天的开始。您希望最后一天结束。
erickva '19

38

随着斯威夫特3和iOS 10,我发现这样做的最简单的方法是CalendardateInterval(of:for:)

guard let interval = calendar.dateInterval(of: .month, for: Date()) else { return }

然后interval.start,您可以使用和interval.end获取所需的日期。


值得注意的是,此功能仅在iOS 10及更高版本上可用。
哈里·布鲁姆

2
到目前为止,每个人都应该使用iOS10 +,这是迄今为止最好的答案
iSpain17

23

迅捷3

许多日期的示例:

最近6个月最近3个月昨天,最近7天,最近30天,上个月, 本月开始和结束,上个月开始和结束日期

let startDate = dateFormatter.string(from: Date().getThisMonthStart()!)
let endDate = dateFormatter.string(from: Date().getThisMonthEnd()!)

extension Date {

func getLast6Month() -> Date? {
    return Calendar.current.date(byAdding: .month, value: -6, to: self)
}

func getLast3Month() -> Date? {
    return Calendar.current.date(byAdding: .month, value: -3, to: self)
}

func getYesterday() -> Date? {
    return Calendar.current.date(byAdding: .day, value: -1, to: self)
}

func getLast7Day() -> Date? {
    return Calendar.current.date(byAdding: .day, value: -7, to: self)
}
func getLast30Day() -> Date? {
    return Calendar.current.date(byAdding: .day, value: -30, to: self)
}

func getPreviousMonth() -> Date? {
    return Calendar.current.date(byAdding: .month, value: -1, to: self)
}

// This Month Start
func getThisMonthStart() -> Date? {
    let components = Calendar.current.dateComponents([.year, .month], from: self)
    return Calendar.current.date(from: components)!
}

func getThisMonthEnd() -> Date? {
    let components:NSDateComponents = Calendar.current.dateComponents([.year, .month], from: self) as NSDateComponents
    components.month += 1
    components.day = 1
    components.day -= 1
    return Calendar.current.date(from: components as DateComponents)!
}

//Last Month Start
func getLastMonthStart() -> Date? {
    let components:NSDateComponents = Calendar.current.dateComponents([.year, .month], from: self) as NSDateComponents
    components.month -= 1
    return Calendar.current.date(from: components as DateComponents)!
}

//Last Month End
func getLastMonthEnd() -> Date? {
    let components:NSDateComponents = Calendar.current.dateComponents([.year, .month], from: self) as NSDateComponents
    components.day = 1
    components.day -= 1
    return Calendar.current.date(from: components as DateComponents)!
}

}

9

斯威夫特4

如果只需要顺序的一天:

func lastDay(ofMonth m: Int, year y: Int) -> Int {
    let cal = Calendar.current
    var comps = DateComponents(calendar: cal, year: y, month: m)
    comps.setValue(m + 1, for: .month)
    comps.setValue(0, for: .day)
    let date = cal.date(from: comps)!
    return cal.component(.day, from: date)
}

lastDay(ofMonth: 2, year: 2018)  // 28
lastDay(ofMonth: 2, year: 2020)  // 29

5

2017 ...

首先,获取您需要的月份:

    let cal = Calendar.current
    let d = Calendar.current.date(byAdding: .month, value: 0, to: Date())!
    
    // for "last month" just use -1, for "next month" just use 1, etc
    

要获取每月第一天的星期几,请执行以下操作:

    let c = cal.dateComponents([.year, .month], from: d)
    let FDOM = cal.date(from: c)!
    let dowFDOM = cal.component(.weekday, from: FDOM)

    print("the day-of-week on the 1st is ... \(dowFDOM)")
    // so, that's 1=Sunday, 2=Monday, etc.
    

要获取一个月中的天数:

    let r = cal.range(of: .day, in: .month, for: d)!
    let kDays = r.count

    print("the number of days is ... \(kDays)")

FDOM是错误的,它获取上个月的最后一天,而不是当前月份的第一天。
温琴佐

3

这是最简单的解决方案:

extension Date {

func startOfMonth() -> Date {
    let interval = Calendar.current.dateInterval(of: .month, for: self)
    return (interval?.start.toLocalTime())! // Without toLocalTime it give last months last date
}

func endOfMonth() -> Date {
    let interval = Calendar.current.dateInterval(of: .month, for: self)
    return interval!.end
}

// Convert UTC (or GMT) to local time
func toLocalTime() -> Date {
    let timezone    = TimeZone.current
    let seconds     = TimeInterval(timezone.secondsFromGMT(for: self))
    return Date(timeInterval: seconds, since: self)
}}

然后使用日期实例调用它们:

print(Date().startOfMonth())
print(Date().endOfMonth())

2

使用Swift 3,您可以选择以下两个模式之一来检索一个月的第一天和最后一天。


#1 使用Calendar dateComponents(_:from:)date(from:)date(byAdding:to:wrappingComponents:)方法

使用此模式,您首先要获得一个月的第一天的日期,然后添加一个月并从中删除一天,以便获得该月的最后一天的日期。以下Playground代码显示了如何进行设置:

import Foundation

// Set calendar and date 
let calendar = Calendar.current
let date = calendar.date(byAdding: DateComponents(day: -10), to: Date())!

// Get first day of month
let firstDayComponents = calendar.dateComponents([.year, .month], from: date)
let firstDay = calendar.date(from: firstDayComponents)!

// Get last day of month
let lastDayComponents = DateComponents(month: 1, day: -1)
let lastDay = calendar.date(byAdding: lastDayComponents, to: firstDay)!

// Set date formatter
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_UK")
dateFormatter.dateStyle = .long
dateFormatter.timeStyle = .long

// Print results
print(dateFormatter.string(from: date)) // Prints: 22 March 2017 at 18:07:15 CET
print(dateFormatter.string(from: firstDay)) // Prints: 1 March 2017 at 00:00:00 CET
print(dateFormatter.string(from: lastDay)) // Prints: 31 March 2017 at 00:00:00 CEST

#2。使用Calendar range(of:in:for:)dateComponents(_:from:)并且date(from:)和方法

使用这种模式,您可以在一个月中获得一系列的绝对日值,然后从中获取该月的第一天和最后一天的日期。下面的Playground代码显示了如何进行设置:

import Foundation

// Set calendar and date
let calendar = Calendar.current
let date = calendar.date(byAdding: DateComponents(day: -10), to: Date())!

// Get range of days in month
let range = calendar.range(of: .day, in: .month, for: date)! // Range(1..<32)

// Get first day of month
var firstDayComponents = calendar.dateComponents([.year, .month], from: date)
firstDayComponents.day = range.lowerBound
let firstDay = calendar.date(from: firstDayComponents)!

// Get last day of month
var lastDayComponents = calendar.dateComponents([.year, .month], from: date)
lastDayComponents.day = range.upperBound - 1
//lastDayComponents.day = range.count // also works
let lastDay = calendar.date(from: lastDayComponents)!

// Set date formatter
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_UK")
dateFormatter.dateStyle = .long
dateFormatter.timeStyle = .long

// Print results
print(dateFormatter.string(from: date)) // prints: 22 March 2017 at 18:07:15 CET
print(dateFormatter.string(from: firstDay)) // prints: 1 March 2017 at 00:00:00 CET
print(dateFormatter.string(from: lastDay)) // prints: 31 March 2017 at 00:00:00 CEST

2

在swift 3中,如果将0设置为day组件,则可以获取该月的最后一天。有一个示例代码:

 public func isMoreDays(date: Date, asc: Bool)->Bool{
    //components
    var dayComponents = self.getDateComponents(date: date)
    //asc is true if ascendant or false if descendant
    dayComponents.day = asc ?  0 : 1
    //plus 1 to month 'cos if you set up day to 0 you are going to the previous month
    dayComponents.month = asc ? dayComponents.month! + 1 : dayComponents.month

    //instantiate calendar and get the date
    let calendar : Calendar = NSCalendar.current
    let day = calendar.date(from: dayComponents)

    //date comparison
    if(day?.compare(date) == .orderedSame){
        return false
    }
    return true
}

1
虽然这很“讨厌”,但我不能支持它。它是不确定的,并且-仅要测试它是否可以正确包装多年-会花费很多工作。请注意,今天,这很容易做到,您只需使用“范围”来获取月份的最后日期。
Fattie

@Fattie当您使用范围获取月份的第一天时,您能举个例子吗?
Alfredo Luco G

ciao @alfredo,我的意思是本月的最后一天:无论如何,我回答了!我只是担心您的“ 0”解决方案很危险,当您包装时知道吗?
Fattie

2

这是我找到的最简单的方法(Swift 5+):

extension Date {

    func getStart(of component: Calendar.Component, calendar: Calendar = Calendar.current) -> Date? {
        return calendar.dateInterval(of: component, for: self)?.start
    }

    func getEnd(of component: Calendar.Component, calendar: Calendar = Calendar.current) -> Date? {
        return calendar.dateInterval(of: component, for: self)?.end
    }
}

-1
/**
      Get last day of month..
 */
private func getLastDay(year:Int, month:Int) -> Int
{
    var ret:Int = -1
    
    switch month {
    case 1:
        ret = 31
        break
    case 2:
         break
    case 3:
        ret = 31
        break
    case 4:
        ret = 30
        break
    case 5:
        ret = 31
        break
    case 6:
        ret = 30
        break
    case 7:
        ret = 31
        break
    case 8:
        ret = 31
        break
    case 9:
        ret = 30
        break
    case 10:
        ret = 31
        break
    case 11:
        ret = 30
        break
    case 12:
        ret = 31
        break
    default:
        print("bad num")
    }
    
    if(month == 2)
    {
        ret = 28
        
        let t4 = year % 4
        let l100 = year % 100
        let l400 = year % 400
        
        if(t4 == 0 && l100 != 0)
        {
            ret = 29
        }
        
        if(l400 == 0)
        {
            ret = 29
        }
    }
    
    
    return ret
    
}

不建议使用仅代码的答案,请在答案中添加一些说明。
pawello2222
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.