Zastanawiam się, czy jest jakaś nowa i niesamowita możliwość uzyskania liczby dni między dwoma NSDates w Swift / „nowym” Cocoa?
Np. Jak w Rubim zrobiłbym:
(end_date - start_date).to_i
Zastanawiam się, czy jest jakaś nowa i niesamowita możliwość uzyskania liczby dni między dwoma NSDates w Swift / „nowym” Cocoa?
Np. Jak w Rubim zrobiłbym:
(end_date - start_date).to_i
Odpowiedzi:
Musisz również wziąć pod uwagę różnicę czasu. Na przykład, jeśli porównasz daty 2015-01-01 10:00
i 2015-01-02 09:00
, dni między tymi datami zostaną zwrócone jako 0 (zero), ponieważ różnica między tymi datami jest mniejsza niż 24 godziny (to 23 godziny).
Jeśli Twoim celem jest uzyskanie dokładnej liczby dni między dwiema datami, możesz obejść ten problem w następujący sposób:
// Assuming that firstDate and secondDate are defined
// ...
let calendar = NSCalendar.currentCalendar()
// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDayForDate(firstDate)
let date2 = calendar.startOfDayForDate(secondDate)
let flags = NSCalendarUnit.Day
let components = calendar.components(flags, fromDate: date1, toDate: date2, options: [])
components.day // This will return the number of day(s) between dates
let calendar = Calendar.current
// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDay(for: firstDate)
let date2 = calendar.startOfDay(for: secondDate)
let components = calendar.dateComponents([.day], from: date1, to: date2)
calendar.date(bySettingHour: 12, minute: 00, second: 00, of: calendar.startOfDay(for: firstDate))
startOfDay()
wydaje się być niepotrzebne) calendar.date(bySettingHour: 12, minute: 0, second: 0, of: firstDate)
.
Oto moja odpowiedź na Swift 2:
func daysBetweenDates(startDate: NSDate, endDate: NSDate) -> Int
{
let calendar = NSCalendar.currentCalendar()
let components = calendar.components([.Day], fromDate: startDate, toDate: endDate, options: [])
return components.day
}
today
itomorrow
Widzę kilka odpowiedzi Swift3, więc dodam własne:
public static func daysBetween(start: Date, end: Date) -> Int {
Calendar.current.dateComponents([.day], from: start, to: end).day!
}
Nazewnictwo wydaje się bardziej szybkie, to jedna linia i przy użyciu najnowszej dateComponents()
metody.
Przetłumaczyłem moją odpowiedź Objective-C
let start = "2010-09-01"
let end = "2010-09-05"
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let startDate:NSDate = dateFormatter.dateFromString(start)
let endDate:NSDate = dateFormatter.dateFromString(end)
let cal = NSCalendar.currentCalendar()
let unit:NSCalendarUnit = .Day
let components = cal.components(unit, fromDate: startDate, toDate: endDate, options: nil)
println(components)
wynik
<NSDateComponents: 0x10280a8a0>
Day: 4
Najtrudniejsze było to, że autouzupełnianie nalega, aby fromDate i toDate były NSDate?
, ale w rzeczywistości muszą być takie, NSDate!
jak pokazano w pliku referencyjnym.
Nie widzę, jak wyglądałoby dobre rozwiązanie z operatorem, ponieważ w każdym przypadku chcesz inaczej określić jednostkę. Możesz zwrócić przedział czasowy, ale niewiele zyskasz.
.DayCalendarUnit
to, że jest przestarzały. Uważam, że teraz powinieneś użyć .CalendarUnitDay
zamiast tego.
let components = cal.components(.Day, fromDate: startDate, toDate: endDate, options: [])
.Day
teraz
Oto bardzo ładne Date
rozszerzenie, aby uzyskać różnicę między datami w latach, miesiącach, dniach, godzinach, minutach, sekundach
extension Date {
func years(sinceDate: Date) -> Int? {
return Calendar.current.dateComponents([.year], from: sinceDate, to: self).year
}
func months(sinceDate: Date) -> Int? {
return Calendar.current.dateComponents([.month], from: sinceDate, to: self).month
}
func days(sinceDate: Date) -> Int? {
return Calendar.current.dateComponents([.day], from: sinceDate, to: self).day
}
func hours(sinceDate: Date) -> Int? {
return Calendar.current.dateComponents([.hour], from: sinceDate, to: self).hour
}
func minutes(sinceDate: Date) -> Int? {
return Calendar.current.dateComponents([.minute], from: sinceDate, to: self).minute
}
func seconds(sinceDate: Date) -> Int? {
return Calendar.current.dateComponents([.second], from: sinceDate, to: self).second
}
}
date
powinny znajdować się sinceDate
w parametrach funkcji.
days
i działa dobrze.
func years(since date: Date) -> Int? { return Calendar.current.dateComponents[.year], from: date, to: self).years }
i możesz to nazwać jako let y = date1.years(since: date2)
. To może być bardziej spójne z nowoczesnymi konwencjami nazewnictwa.
Aktualizacja dla Swift 3 iOS 10 Beta 4
func daysBetweenDates(startDate: Date, endDate: Date) -> Int {
let calendar = Calendar.current
let components = calendar.dateComponents([Calendar.Component.day], from: startDate, to: endDate)
return components.day!
}
Oto odpowiedź na Swift 3 (testowany pod kątem IOS 10 Beta)
func daysBetweenDates(startDate: Date, endDate: Date) -> Int
{
let calendar = Calendar.current
let components = calendar.components([.day], from: startDate, to: endDate, options: [])
return components.day!
}
Wtedy możesz to tak nazwać
let pickedDate: Date = sender.date
let NumOfDays: Int = daysBetweenDates(startDate: pickedDate, endDate: Date())
print("Num of Days: \(NumOfDays)")
Swift 3. Podziękowania dla Emin Buğra Saral powyżej za startOfDay
sugestię.
extension Date {
func daysBetween(date: Date) -> Int {
return Date.daysBetween(start: self, end: date)
}
static func daysBetween(start: Date, end: Date) -> Int {
let calendar = Calendar.current
// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDay(for: start)
let date2 = calendar.startOfDay(for: end)
let a = calendar.dateComponents([.day], from: date1, to: date2)
return a.value(for: .day)!
}
}
Stosowanie:
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let start = dateFormatter.date(from: "2017-01-01")!
let end = dateFormatter.date(from: "2018-01-01")!
let diff = Date.daysBetween(start: start, end: end) // 365
Elementy wbudowane w szybkość są nadal bardzo podstawowe. Tak jak powinni być na tym wczesnym etapie. Ale możesz dodawać własne rzeczy z ryzykiem, które wiąże się z przeciążeniem operatorów i funkcji domeny globalnej. Będą jednak lokalne dla twojego modułu.
let now = NSDate()
let seventies = NSDate(timeIntervalSince1970: 0)
// Standard solution still works
let days = NSCalendar.currentCalendar().components(.CalendarUnitDay,
fromDate: seventies, toDate: now, options: nil).day
// Flashy swift... maybe...
func -(lhs:NSDate, rhs:NSDate) -> DateRange {
return DateRange(startDate: rhs, endDate: lhs)
}
class DateRange {
let startDate:NSDate
let endDate:NSDate
var calendar = NSCalendar.currentCalendar()
var days: Int {
return calendar.components(.CalendarUnitDay,
fromDate: startDate, toDate: endDate, options: nil).day
}
var months: Int {
return calendar.components(.CalendarUnitMonth,
fromDate: startDate, toDate: endDate, options: nil).month
}
init(startDate:NSDate, endDate:NSDate) {
self.startDate = startDate
self.endDate = endDate
}
}
// Now you can do this...
(now - seventies).months
(now - seventies).days
Oto moja odpowiedź na Swift 3:
func daysBetweenDates(startDate: NSDate, endDate: NSDate, inTimeZone timeZone: TimeZone? = nil) -> Int {
var calendar = Calendar.current
if let timeZone = timeZone {
calendar.timeZone = timeZone
}
let dateComponents = calendar.dateComponents([.day], from: startDate.startOfDay, to: endDate.startOfDay)
return dateComponents.day!
}
Nie ma jeszcze żadnej standardowej biblioteki specyficznej dla języka Swift; tylko podstawowe typy liczbowe, łańcuchowe i kolekcjonerskie.
Jest całkowicie możliwe zdefiniowanie takich skrótów za pomocą rozszerzeń, ale jeśli chodzi o rzeczywiste gotowe interfejsy API, nie ma „nowego” Cocoa; Swift po prostu mapuje bezpośrednio do tych samych starych, pełnych funkcji API Cocoa, które już istnieją.
Dodam swoją wersję, mimo że ten wątek ma już rok. Mój kod wygląda tak:
var name = txtName.stringValue // Get the users name
// Get the date components from the window controls
var dateComponents = NSDateComponents()
dateComponents.day = txtDOBDay.integerValue
dateComponents.month = txtDOBMonth.integerValue
dateComponents.year = txtDOBYear.integerValue
// Make a Gregorian calendar
let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)
// Get the two dates we need
var birthdate = calendar?.dateFromComponents(dateComponents)
let currentDate = NSDate()
var durationDateComponents = calendar?.components(NSCalendarUnit.CalendarUnitDay, fromDate: birthdate!, toDate: currentDate, options: nil)
let numberOfDaysAlive = durationDateComponents?.day
println("\(numberOfDaysAlive!)")
txtGreeting.stringValue = "Hello \(name), You have been alive for \(numberOfDaysAlive!) days."
Mam nadzieję, że to komuś pomoże.
Twoje zdrowie,
Metoda Erin została zaktualizowana do Swift 3, pokazuje dni od dzisiaj (bez względu na porę dnia)
func daysBetweenDates( endDate: Date) -> Int
let calendar: Calendar = Calendar.current
let date1 = calendar.startOfDay(for: Date())
let date2 = calendar.startOfDay(for: secondDate)
return calendar.dateComponents([.day], from: date1, to: date2).day!
}
Zwraca to bezwzględną różnicę w dniach między niektórymi Date
a dzisiejszymi:
extension Date {
func daysFromToday() -> Int {
return abs(Calendar.current.dateComponents([.day], from: self, to: Date()).day!)
}
}
a następnie użyj go:
if someDate.daysFromToday() >= 7 {
// at least a week from today
}
Możesz użyć następującego rozszerzenia:
public extension Date {
func daysTo(_ date: Date) -> Int? {
let calendar = Calendar.current
// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDay(for: self)
let date2 = calendar.startOfDay(for: date)
let components = calendar.dateComponents([.day], from: date1, to: date2)
return components.day // This will return the number of day(s) between dates
}
}
Następnie możesz to nazwać tak:
startDate.daysTo(endDate)
Swift 3.2
extension DateComponentsFormatter {
func difference(from fromDate: Date, to toDate: Date) -> String? {
self.allowedUnits = [.year,.month,.weekOfMonth,.day]
self.maximumUnitCount = 1
self.unitsStyle = .full
return self.string(from: fromDate, to: toDate)
}
}
Cała odpowiedź jest dobra. Ale w przypadku lokalizacji musimy obliczyć liczbę dni dziesiętnych między dwiema datami. dzięki czemu możemy zapewnić trwały format dziesiętny.
// This method returns the fractional number of days between to dates
func getFractionalDaysBetweenDates(date1: Date, date2: Date) -> Double {
let components = Calendar.current.dateComponents([.day, .hour], from: date1, to: date2)
var decimalDays = Double(components.day!)
decimalDays += Double(components.hour!) / 24.0
return decimalDays
}
extension Date {
func daysFromToday() -> Int {
return Calendar.current.dateComponents([.day], from: self, to: Date()).day!
}
}
Następnie użyj tego jak
func dayCount(dateString: String) -> String{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM dd,yyyy hh:mm a"
let fetchedDate = dateFormatter.date(from: dateString)
let day = fetchedDate?.daysFromToday()
if day! > -1{
return "\(day!) days passed."
}else{
return "\(day! * -1) days left."
}
}
To jest zaktualizowana wersja odpowiedzi Emin dla Swift 5, która zawiera sugestię, aby użyć południa zamiast północy jako ostatecznego czasu porównywania dni. Obsługuje również potencjalną awarię różnych funkcji daty, zwracając opcjonalny.
///
/// This is an approximation; it does not account for time differences. It will set the time to 1200 (noon) and provide the absolute number
/// of days between now and the given date. If the result is negative, it should be read as "days ago" instead of "days from today."
/// Returns nil if something goes wrong initializing or adjusting dates.
///
func daysFromToday() -> Int?
{
let calendar = NSCalendar.current
// Replace the hour (time) of both dates with noon. (Noon is less likely to be affected by DST changes, timezones, etc. than midnight.)
guard let date1 = calendar.date(bySettingHour: 12, minute: 00, second: 00, of: calendar.startOfDay(for: Date())),
let date2 = calendar.date(bySettingHour: 12, minute: 00, second: 00, of: calendar.startOfDay(for: self)) else
{
return nil
}
return calendar.dateComponents([.day], from: date1, to: date2).day
}
Swift 3 - dni od dziś do daty
func daysUntilDate(endDateComponents: DateComponents) -> Int
{
let cal = Calendar.current
var components = cal.dateComponents([.era, .year, .month, .day], from: NSDate() as Date)
let today = cal.date(from: components)
let otherDate = cal.date(from: endDateComponents)
components = cal.dateComponents([Calendar.Component.day], from: (today! as Date), to: otherDate!)
return components.day!
}
Wywołaj taką funkcję
// Days from today until date
var examnDate = DateComponents()
examnDate.year = 2016
examnDate.month = 12
examnDate.day = 15
let daysCount = daysUntilDate(endDateComponents: examnDate)
łatwiejszą opcją byłoby utworzenie rozszerzenia w dniu
public extension Date {
public var currentCalendar: Calendar {
return Calendar.autoupdatingCurrent
}
public func daysBetween(_ date: Date) -> Int {
let components = currentCalendar.dateComponents([.day], from: self, to: date)
return components.day!
}
}
func completeOffset(from date:Date) -> String? {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .brief
return formatter.string(from: Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second], from: date, to: self))
}
jeśli potrzebujesz rok, miesiąc, dni i godziny jako ciąg znaków, użyj tego
var tomorrow = Calendar.current.date (byAdding: .day, value: 1, to: Date ())!
let dc = tomorrow.completeOffset (from: Date ())
Szybki 4
func getDateHeader(indexPath: Int) -> String {
let formatter2 = DateFormatter()
formatter2.dateFormat = "MM-dd-yyyy"
var dateDeadline : Date?
dateDeadline = formatter2.date(from: arrCompletedDate[indexPath] as! String)
let currentTime = dateDeadline?.unixTimestamp
let calendar = NSCalendar.current
let date = NSDate(timeIntervalSince1970: Double(currentTime!))
if calendar.isDateInYesterday(date as Date) { return "Yesterday" }
else if calendar.isDateInToday(date as Date) { return "Today" }
else if calendar.isDateInTomorrow(date as Date) { return "Tomorrow" }
else {
let startOfNow = calendar.startOfDay(for: NSDate() as Date)
let startOfTimeStamp = calendar.startOfDay(for: date as Date)
let components = calendar.dateComponents([.day], from: startOfNow, to: startOfTimeStamp)
let day = components.day!
if day < 1 { return "\(abs(day)) days ago" }
else { return "In \(day) days" }
}
}
Rozwiązanie Swift 5.2.4:
import UIKit
let calendar = Calendar.current
let start = "2010-09-01"
let end = "2010-09-05"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let firstDate = dateFormatter.date(from: start)!
let secondDate = dateFormatter.date(from: end)!
// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDay(for: firstDate)
let date2 = calendar.startOfDay(for: secondDate)
let components = calendar.dateComponents([Calendar.Component.day], from: date1, to: date2)
components.day // This will return the number of day(s) between dates
func simpleIndex(ofDate: Date) -> Int {
// index here just means today 0, yesterday -1, tomorrow 1 etc.
let c = Calendar.current
let todayRightNow = Date()
let d = c.date(bySetting: .hour, value: 13, of: ofDate)
let t = c.date(bySetting: .hour, value: 13, of: todayRightNow)
if d == nil || today == nil {
print("weird problem simpleIndex#ofDate")
return 0
}
let r = c.dateComponents([.day], from: today!, to: d!)
// yesterday is negative one, tomorrow is one
if let o = r.value(for: .day) {
return o
}
else {
print("another weird problem simpleIndex#ofDate")
return 0
}
}
let calendar = NSCalendar.currentCalendar();
let component1 = calendar.component(.Day, fromDate: fromDate)
let component2 = calendar.component(.Day, fromDate: toDate)
let difference = component1 - component2