первый и последний день текущего месяца в Swift

Я пытаюсь получить первый и последний день месяца в Swift.

пока у меня есть следующие:

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")

но я не уверен, как получить последнюю дату. Есть ли встроенный метод, которого мне не хватает? Очевидно, что он должен учитывать високосные годы и т. д.

8 ответов


вы получаете первый день месяца, просто с

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)

Swift 3 и 4 выпадающие расширения

это на самом деле получает большое проще с Swift 3+:

  1. вы можете сделать это без охраны (вы могли бы, если захотели, а потому что DateComponents теперь необязательный тип, он больше не нужен).
  2. использование iOS 8 startOfDayForDate (ныне startOfDay), вам не нужно вручную устанавливать время до 12 вечера, если вы не делаете некоторые действительно сумасшедшие вычисления календаря во времени зоны.

стоит отметить, что некоторые из других ответов утверждают, что вы можете сократить это, используя 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 и iOS 10 Самый простой способ я нашел, чтобы сделать это Calendar ' s dateInterval(of:for:):

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

затем вы можете использовать interval.start и interval.end чтобы получить нужные даты.


Swift 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)!
}

}

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)")

С Swift 3 Вы можете выбрать один из двух следующих паттеров, чтобы получить первые и последние дни месяца.


#1. Используя Calendar dateComponents(_:from:), date(from:) и date(byAdding:to:wrappingComponents:) методы

С помощью этого шаблона вы сначала получаете дату первого дня месяца, затем добавляете месяц и удаляете из него день, чтобы получить дату последнего дня месяца. Код игровой площадки ниже показывает, как установите его:

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:) и методы

С помощью этого шаблона вы получаете диапазон абсолютных значений дня в месяц, а затем извлекаете из него даты первого и последнего дня месяца. Код игровой площадки ниже показывает, как его установить:

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

в swift 3, Если вы поместите компонент 0 в день, Вы можете получить последний день месяца. Вот пример кода:

 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
}

Swift 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