erster und letzter Tag des laufenden Monats in Kürze

74

Ich versuche, den ersten und letzten Tag des Monats schnell zu erreichen.

Bisher habe ich folgendes:

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

Aber ich bin mir nicht sicher, wie ich das letzte Date bekommen soll. Gibt es eine eingebaute Methode, die mir fehlt? Offensichtlich muss es Schaltjahre usw. berücksichtigen.

user2363025
quelle
@ FattiKhan schnelle Version?
user2363025
1
try github.com/malcommac/SwiftDate Diese Bibliothek hat die Methode: .endOfMonth () // gebe das Datum zurück, das den letzten Tag des Monats des Absenderdatums darstellt
buxik
Keine Notwendigkeit für eine Bibliothek, heutzutage ist es sehr einfach - ich habe unten eine aktuelle Antwort für 2017 eingegeben
Fattie

Antworten:

99

Sie erhalten den ersten Tag des Monats einfach mit

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

Um den letzten Tag des Monats zu erhalten, addieren Sie einen Monat und subtrahieren Sie einen Tag:

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

Alternativ können Sie die rangeOfUnitMethode verwenden, mit der Sie den Beginn und die Länge des Monats angeben:

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

Addieren Sie für ein Datum am letzten Tag des Monats die Länge des Monats minus eine Sekunde:

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

Aktualisiert für 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 R.
quelle
@ Martin, wie man vorherigen und nächsten Monat durch Knopfdruck [schnell]
erhält
@iDeveloper: Sorry, aber das ist eine ganz andere Frage, die nicht einfach in einem Kommentar beantwortet werden kann.
Martin R
@MartinR: Haben Sie diesen Code für den Dezember-Monat getestet?
Dhiru
1
FWIW (Dies ist möglicherweise neu, nicht sicher) Ich denke, Sie möchten comps2.day = 0, nicht comps2.day = -1 Tag = 1 -> Erster des Monats, Tag = 0 -> letzter Tag des Vormonats, Tag = -1 -> 2. bis letzter Tag des Vormonats. Oder etwas anderes stimmt nicht in meinem Code, aber ändern Sie -1 -> 0 feste Dinge ¯ \ _ (ツ) _ / ¯
nickneedsaname
2
@Maks: Für eine Überprüfung "ist das Datum in diesem Monat" würde ich den Beginn dieses Monats und den Beginn des nächsten Monats berechnen, ohne etwas abzuziehen. Dann vergleiche mitif date >= startDate && date < endDate
Martin R
134

Schnelle Drop-In-Erweiterungen für 3 und 4

Mit Swift 3+ wird dies tatsächlich viel einfacher:

  1. Sie können dies ohne Schutz tun (Sie können es, wenn Sie möchten, aber da DateComponentses sich jetzt um einen nicht optionalen Typ handelt, ist er nicht mehr erforderlich).
  2. Unter Verwendung von iOS 8 startOfDayForDate(jetzt startOfDay) müssen Sie die Zeit nicht manuell auf 12 Uhr einstellen, es sei denn, Sie führen einige wirklich verrückte Kalenderberechnungen über Zeitzonen hinweg durch.

Es ist erwähnenswert, dass einige der anderen Antworten behaupten, Sie könnten dies mit verwenden Calendar.current.date(byAdding: .month, value: 0, to: Date())!, aber wenn dies fehlschlägt, ist es, dass es den Tag nicht auf Null setzt oder Unterschiede in den Zeitzonen berücksichtigt.

Bitte schön:

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"
Brandonscript
quelle
Erzeugt Warnungen in Swift 3.0. Non-optional expression of type 'Calendar' used in a check for optionals. Irgendwelche Vorschläge?
Allreadyhome
2
Aktualisiert für Swift 3
Brandonscript
2
Abgesehen davon gibt es mir die Willenskraft, etwas hinzuzufügen, DateComponents(month: 1, day: -1)weil Sie sich auf undokumentiertes Verhalten verlassen, wobei dies monthvorher der Fall ist day. Wenn heute beispielsweise der 15. Mai ist, ist der Monatsanfang der 1. Mai, und wenn er Tag vor Monat abgezogen wird, erhalten Sie den 30. Mai anstelle des 31. Mai. Es scheint sicherer zu sein, Monat +1 und Tag -1 in zwei getrennten Operationen auszuführen. Oder verwenden Sie calendar.range(of:in:for:)stattdessen.
Rob
8
Der Monatsanfang funktioniert bei mir nicht. Es gibt mir den vorherigen Tag um 22:00 Uhr (also den letzten Tag des vorherigen Monats). Wenn ich auch die Calendar.current.date(from: Calendar.current.dateComponents([.year, .month, .day], from: Calendar.current.startOfDay(for: self)))!
Tageskomponente verwende,
1
Das richtige für mich wäre DateComponents (Monat: 1, Sekunde: -1), andernfalls erhalten Sie mit Tag: -1 den Anfang des letzten Tages. Du willst das Ende des letzten Tages.
Erickva
38

Mit Swift 3 & iOS 10 der einfachste Weg , fand ich , dies zu tun ist Calendar‚s dateInterval(of:for:):

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

Sie können dann interval.startund verwenden interval.end, um die Daten zu erhalten, die Sie benötigen.

LuisCien
quelle
Es ist erwähnenswert, dass dies nur unter iOS 10 und höher verfügbar ist.
Harry Bloom
2
Jeder sollte jetzt auf iOS10 + sein, diese Antwort ist bei weitem die beste
iSpain17
22

Swift 3

Viele Datumsbeispiele für:

Letzte 6 Monate , letzte 3 Monate , gestern, letzte 7 Tage, letzte 30 Tage, vorheriger Monat, Beginn und Ende des aktuellen Monats, Start und Ende des letzten Monats

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

}
Bhadresh Kathiriya
quelle
8

Swift 4

Wenn Sie nur den Ordnungszeitpunkt benötigen:

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
Miguel Gallego
quelle
5

2017 ...

Holen Sie sich zuerst den Monat, den Sie brauchen:

    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
    

So erhalten Sie den Wochentag für den ersten Tag des Monats:

    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.
    

So ermitteln Sie die Anzahl der Tage im Monat:

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

    print("the number of days is ... \(kDays)")
Fattie
quelle
FDOM ist falsch, es wird der letzte Tag des Vormonats, nicht der erste des aktuellen Monats.
Vincenzo
3

Hier ist die einfachste Lösung:

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

und rufen Sie diese dann mit Ihrer Datumsinstanz auf:

print(Date().startOfMonth())
print(Date().endOfMonth())
Zulqarnain
quelle
2

Mit Swift 3 können Sie eines der beiden folgenden Muster auswählen, um den ersten und den letzten Tag eines Monats abzurufen.


# 1. Unter Verwendung Calendar dateComponents(_:from:), date(from:)und date(byAdding:to:wrappingComponents:)Methoden

Mit diesem Muster erhalten Sie zuerst das Datum des ersten Tages eines Monats, fügen dann einen Monat hinzu und entfernen einen Tag daraus, um das Datum des letzten Tages des Monats zu erhalten. Der folgende Spielplatzcode zeigt, wie Sie ihn einstellen:

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. Unter Verwendung Calendar range(of:in:for:), dateComponents(_:from:)und date(from:)und Methoden

Mit diesem Muster erhalten Sie einen Bereich von absoluten Tageswerten in einem Monat und rufen dann die Daten des ersten Tages und des letzten Tages des Monats ab. Der folgende Spielplatzcode zeigt, wie Sie ihn einstellen:

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
Imanou Petit
quelle
2

Wenn Sie in Swift 3 die Komponente 0 auf Tag setzen, können Sie den letzten Tag des Monats abrufen. Es gibt einen Beispielcode:

 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
}
Alfredo Luco G.
quelle
1
Obwohl dies "natty" ist, kann ich es nicht unterstützen. Es ist undefiniert und würde - nur um zu testen, ob es sich über Jahre hinweg richtig verpackt - viel Arbeit kosten. Beachten Sie, dass dies heute sehr einfach ist. Verwenden Sie einfach "Bereich", um das letzte Datum des Monats abzurufen.
Fattie
@Fattie Können Sie mir ein Beispiel geben, wenn Sie Range verwenden, um das erste Datum des Monats zu erhalten?
Alfredo Luco G
ciao @alfredo, ich meinte für den letzten Tag des Monats: trotzdem habe ich eine Antwort eingegeben! Ich mache mir nur Sorgen, dass Ihre "0" -Lösung gefährlich ist, wenn Sie einwickeln, wissen Sie?!
Fattie
2

Dies ist der einfachste Weg, den ich gefunden habe (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
    }
}
rubik
quelle
-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
    
}
BlazejK
quelle
Von Nur-Code-Antworten wird abgeraten. Bitte fügen Sie Ihrer Antwort eine Erklärung hinzu.
pawello2222