web-dev-qa-db-fra.com

iOS Swift - Obtenir l'heure locale et l'heure actuelle

J'essaie de créer une application d'assistance et je suis vraiment perplexe à propos de la date et de l'heure dans iOS et Firebase.

J'utilise date comme clé, c'est la structure de ma base de données Firebase.

--Employees
  --Unique_ID
     --Details
          Name: John
     --Attendance
          --dateToday
              Timein: 8:00 AM
              Timeout: 5:00 PM
              BreakStart: 12:00 PM
              BreakFinish: 1:00 PM

Ceci est mon code pour obtenir l'horodatage de la date que j'ai utilisé comme clé

 override func viewDidLoad() {
     super.viewDidLoad()

     let now = NSDate()
     let nowTimeStamp = self.getCurrentTimeStampWOMiliseconds(dateToConvert: now)

     // I save this dateToday as Key in Firebase
     dateToday = nowTimeStamp
}


func getCurrentTimeStampWOMiliseconds(dateToConvert: NSDate) -> String {
    let objDateformat: DateFormatter = DateFormatter()
    objDateformat.dateFormat = "yyyy-MM-dd"
    let strTime: String = objDateformat.string(from: dateToConvert as Date)
    let objUTCDate: NSDate = objDateformat.date(from: strTime)! as NSDate
    let milliseconds: Int64 = Int64(objUTCDate.timeIntervalSince1970)
    let strTimeStamp: String = "\(milliseconds)"
    return strTimeStamp
}

Mais lorsque je le reconvertis, je reçois le 2017-09-22 16:00:00 +0000, ce qui est faux car le 23 septembre est à mon emplacement.

Quel est le bon code à utiliser pour obtenir l'horodatage de la date et de l'horodatage corrects? 

17
TSM

Pour enregistrer l'heure actuelle dans la base de données firebase, j'utilise la conversation Unic Epoch

let timestamp = NSDate().timeIntervalSince1970

et pour le décodage de l’époque Unix jusqu’à la date ().

let myTimeInterval = TimeInterval(timestamp)
let time = NSDate(timeIntervalSince1970: TimeInterval(myTimeInterval))
38
Satish Babariya

Premièrement, je vous recommanderais de stocker votre horodatage en tant que NSNumber dans votre base de données Firebase, au lieu de le stocker en tant que String.

Une autre chose à noter ici est que si vous voulez manipuler des dates avec Swift, vous devriez utiliser Date au lieu de NSDate, sauf si vous interagissez avec du code Obj-C dans votre application. .

Vous pouvez bien sûr utiliser les deux, mais la documentation indique:

Les ponts de date vers la classe NSDate. Vous pouvez les utiliser indifféremment dans code qui interagit avec les API Objective-C.

Maintenant, pour répondre à votre question, je pense que le problème ici est dû au fuseau horaire. 

Par exemple, si vous print(Date()), comme pour le moment, vous obtiendriez:

2017-09-23 06:59:34 +0000

C'est l'heure de Greenwich (GMT).

Donc, selon votre lieu de résidence (ou celui de vos utilisateurs), vous devez ajuster le fuseau horaire avant (ou après, lorsque vous essayez d'accéder aux données, par exemple), en stockant votre Date:

    let now = Date()

    let formatter = DateFormatter()

    formatter.timeZone = TimeZone.current

    formatter.dateFormat = "yyyy-MM-dd HH:mm"

    let dateString = formatter.string(from: now)

Ensuite, vous avez correctement formaté String, en indiquant l’heure actuelle à votre position, et vous êtes libre d’en faire ce que vous voulez :) (convertissez-le en un fichier Date/NSNumber , ou stockez-le directement en tant que String dans la base de données ..)

8
Alex

Si vous voulez juste le timestamp unix, créez une extension:

extension Date {
    func currentTimeMillis() -> Int64! {
        return Int64(self.timeIntervalSince1970 * 1000)
    }
}

Ensuite, vous pouvez l'utiliser comme dans d'autres langages de programmation:

let timestamp = Date().currentTimeMillis()
3
lenooh

Le moyen simple de créer Current TimeStamp. comme ci-dessous,

func generateCurrentTimeStamp () -> String {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy_MM_dd_hh_mm_ss"
    return (formatter.string(from: Date()) as NSString) as String
}
2
User558

Lorsque vous convertissez un horodatage UTC (par exemple, le 2017-11-06 20:15:33 - 08:00) en un objet Date() dans Swift, Swift met à zéro le fuseau horaire vers GMT (qui est plus ou moins 0). Pour calculer un intervalle de temps, cela ne pose pas de problème car peu importe le nombre d'heures (et de minutes, car plusieurs fuseaux horaires ne sont pas divisés sur l'heure, mais à: 45 ou: 30) sont ajoutés ou soustraits de la remise à zéro. hors le fuseau horaire sont ajoutés ou soustraits à la valeur de l'heure (et parfois de la minute) de la date, de sorte que le moment absolu ne change jamais. Toutefois, lors de la conversion de cet objet de date en chaîne, à l'aide de DateFormatter() ou ISO8601DateFormatter(), cela pose un problème, car le fuseau horaire d'origine a été mis à zéro.

Maintenant, je suis favorable à l’utilisation de RFC3339 (le 2017-11-06T20: 15: 33-08: 00), le format convivial pour Internet du format de temps normalisé ISO8601. Il y a de fortes chances que l'API tierce que vous allez un jour utiliser va l'utiliser. Je pense que nous devrions tous l'utiliser maintenant. Le format dans Swift est yyyy-MM-dd'T'HH:mm:ssXXXXX. Swift possède également une ISO8601DateFormatter() qui permet de convertir très simplement les littéraux de chaîne en objets de date:

func getDateFromUTC(RFC3339: String) -> Date? {
    let formatter = ISO8601DateFormatter()
    return formatter.date(from: RFC3339)
}

Et en utilisant le format RFC3339, l'extraction du fuseau horaire est également très simple:

func getTimeZoneFromUTC(RFC3339: String) -> TimeZone? {
    switch RFC3339.suffix(6) {
    case "+05:45":
        return TimeZone(identifier: "Asia/Kathmandu")
    default:
        return nil
    }
}

Bien sûr, vous devrez indiquer les 37 autres fuseaux horaires en utilisant les méthodes qui vous conviennent le mieux. Et maintenant, si vous voulez formater ce littéral de chaîne en quelque chose de plus convivial, vous pouvez combiner les deux méthodes ci-dessus en quelque chose comme ceci:

func getFormattedDateFromUTC(RFC3339: String) -> String? {
    guard let date = getDateFromUTC(RFC3339: RFC3339),
        let timeZone = getTimeZoneFromUTC(RFC3339: RFC3339) else {
            return nil
    }
    let formatter = DateFormatter()
    formatter.dateFormat = "h:mma EEE, MMM d yyyy"
    formatter.amSymbol = "AM"
    formatter.pmSymbol = "PM"
    formatter.timeZone = timeZone // preserve local time zone
    return formatter.string(from: date)
}

Et ainsi cette chaîne "2018-11-06T17:00:00+05:45", qui exprime 17h00 quelque part dans Kathmandu, imprimera 5:00PM Tue, Nov 6 2018, affichant l’heure locale, quel que soit l’emplacement de la machine. Et, bien sûr, si vous ne souhaitez pas le formater en utilisant son heure locale contextuelle, ne définissez tout simplement pas la propriété timeZone.

En guise de remarque en réponse à certaines des suggestions de ce fil de discussion, je vous recommande de stocker les dates sous forme de chaînes dans Firebase. Le stockage de dates sous forme de chaînes, en utilisant notamment un format tel que RFC3339, rend cette plate-forme de données agnostique. Vous pouvez basculer vers n'importe quelle base de données sur n'importe quelle plate-forme, dans n'importe quel framework et vous n'avez pas besoin de changer de logique, car les chaînes ne sont toujours que des chaînes. Et le RFC3339 est le profil que tout framework digne de ce nom reconnaît.

0
bsod