2017-08-23 5 views
1

Benutzer können Artikel verkaufen und ein Ablaufdatum hinzufügen, das von 1-3 Wochen ab dem aktuellen Datum abweicht.Countdown vom aktuellen Datum bis zum bestimmten Datum Swift

So speichern Sie das Ablaufdatum als Double. Muss ich explizit über andere Datumskomponenten wie Jahr, Monat usw. sprechen? Diese

enum Weeks: Int { 
    case one 
    case two 
    case three 
} 

extension Weeks { 
    var timeInterval: Double? { 
     let currentDate = Date() 
     let calendar = Calendar.current 
     let calendarComponents: Set<Calendar.Component> = Set(arrayLiteral: Calendar.Component.year, Calendar.Component.month, Calendar.Component.day, Calendar.Component.hour, Calendar.Component.minute, Calendar.Component.second) 

     var components = calendar.dateComponents(calendarComponents, from: currentDate) 

     switch self { 
     case .one: components.weekOfMonth = 1 
     case .two: components.weekOfMonth = 2 
     case .three: components.weekOfMonth = 3 
     } 

     if let expirationDate = calendar.date(from: components) { 
      return expirationDate.timeIntervalSince1970 as Double 
     } else { 
      return nil 
     } 
    } 
} 

ist, wie ich den Countdown in Date Erweiterung berechnen:

func countdown(to date: Date) -> CountdownResponse { 
    let difference = Calendar.current.dateComponents([.day, .hour, .minute, .second], from: self, to: date) 

    guard let day = difference.day, let hour = difference.hour, let minute = difference.minute, let second = difference.second else { 
     return .error(message: "One or more date components are nil.") 
    } 

    if day <= 0 && hour <= 0 && minute <= 0 && second <= 0 { 
     return .isFinished 
    } 

    let days = displayableText(from: difference.day) 
    let hours = displayableText(from: difference.hour) 
    let minutes = displayableText(from: difference.minute) 
    let seconds = displayableText(from: difference.second) 

    let timeRemaining = "\(days) : \(hours) : \(minutes) : \(seconds)" 

    return .result(time: timeRemaining) 
} 

Dies ist, wie ich möchte den Countdown bekommen, und dann überprüfe ich die Antwort Enum für Fehler oder Ergebnis. Aber das gibt mir falsche Zeit.

Wenn ich Datum manuell erstelle und wie folgt teste, funktioniert es wie erwartet.

var comp = calendar.dateComponents(calendarComponents, from: Date()) 

comp.year = 2017 
comp.month = 8 
comp.day = 24 
comp.minute = 50 
comp.second = 30 

Was mache ich falsch? Behalte ich das Datum als falsches Zeitintervall oder das Datum falsch von timeInterval?

Als ich über den Code schaue, merke ich, dass ich die Woche falsch berechnen kann. Wenn es die zweite Woche des Monats ist und ein Nutzer wählt, dass der Artikel in 3 Wochen abläuft, sollte die Woche des Monats nicht 3 sein, sondern 3 Wochen ab der aktuellen Woche des Monats. Jede Anleitung zur Behebung dieser Logik wird begrüßt.

+1

Auf einen flüchtigen Blick muss ich fragen ... warum machen Sie die Berechnungen so kompliziert? Siehe https://stackoverflow.com/questions/29465205/how-to-add-minutes-to-current-time-in-swift und https://developer.apple.com/documentation/foundation/calendar. Für mich sieht es so aus, als wäre alles, was Sie brauchen, eingebaut. – solenoid

Antwort

0

Warum haben Sie Ihren Code so kompliziert gemacht? Das Foundation-Framework bietet alles, was Sie benötigen, von der kalendarischen Berechnung (Datum hinzufügen und subtrahieren) bis zur Ausgabeformatierung (x Tage, y Stunden, z Minuten usw.).

Hier ist ein Beispiel dafür, wie man es verkürzen:

enum Week: Int { 
    case one = 7, two = 14, three = 21 
} 

enum CountdownResponse { 
    case isFinished 
    case result(time: String) 
} 

struct ProductListing { 
    // Customize this if you want to change timeRemaining's format 
    // It automatically take care of singular vs. plural, i.e. 1 hr and 2 hrs 
    private static let dateComponentFormatter: DateComponentsFormatter = { 
     var formatter = DateComponentsFormatter() 
     formatter.allowedUnits = [.day, .hour, .minute, .second] 
     formatter.unitsStyle = .short 
     return formatter 
    }() 

    var listingDate: Date 
    var duration: Week 
    var expirationDate: Date { 
     return Calendar.current.date(byAdding: .day, value: duration.rawValue, to: listingDate)! 
    } 

    var timeRemaining: CountdownResponse { 
     let now = Date() 

     if expirationDate <= now { 
      return .isFinished 
     } else { 
      let timeRemaining = ProductListing.dateComponentFormatter.string(from: now, to: expirationDate)! 
      return .result(time: timeRemaining) 
     } 
    } 
} 

// Usage 
let august01 = DateComponents(calendar: .current, year: 2017, month: 8, day: 1).date! 
let august19 = DateComponents(calendar: .current, year: 2017, month: 8, day: 19).date! 

let listing1 = ProductListing(listingDate: august01, duration: .three) 
let listing2 = ProductListing(listingDate: august19, duration: .one) 

print(listing1.timeRemaining) // .isFinished 
print(listing2.timeRemaining) // .result("2 days, 4 hrs, 9 min, 23 secs") 

Hinweis obwohl die Berechnung in Echt haarig wird, wenn es die Zeitumstellung Tage kreuzt als die Zeit hin und her verschiebt. Ich habe diese Randfälle nicht mit dem obigen Code getestet.

Verwandte Themen