Comment puis-je obtenir une date ISO 8601 sur iOS?

il est assez facile d'obtenir la chaîne de date ISO 8601 (par exemple, 2004-02-12T15:19:21+00:00 ) en PHP via date('c') , mais comment l'obtenir en Objectif-C (iPhone)? Est-il de même de courte façon de le faire?

voici le long comment j'ai trouvé pour le faire:

NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";

NSDate *now = [NSDate date];
NSString *formattedDateString = [dateFormatter stringFromDate:now];
NSLog(@"ISO-8601 date: %@", formattedDateString);

// Output: ISO-8601 date: 2013-04-27T13:27:50-0700

il semble beaucoup de rigmarole pour quelque chose d'aussi central.

98
demandé sur JohnK 2013-04-27 20:45:39

10 réponses

utiliser NSDateFormatter :

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];   
NSLocale *enUSPOSIXLocale = [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"];
[dateFormatter setLocale:enUSPOSIXLocale];
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"];

NSDate *now = [NSDate date];
NSString *iso8601String = [dateFormatter stringFromDate:now];

et dans Swift:

let dateFormatter = DateFormatter()
let enUSPosixLocale = Locale(identifier: "en_US_POSIX")
dateFormatter.locale = enUSPosixLocale
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"

let iso8601String = dateFormatter.string(from: Date())
195
répondu rmaddy 2017-11-01 21:00:35

iOS 10 introduit une nouvelle classe NSISO8601DateFormatter pour gérer exactement cela. Si vous utilisez Swift 3, votre code serait quelque chose comme ceci:

let formatter = ISO8601DateFormatter()
let date = formatter.date(from: "2016-08-26T12:39:00Z")
let string = formatter.string(from: Date())
38
répondu TwoStraws 2017-04-07 11:31:47

en complément de la réponse de maddy, le format du fuseau horaire devrait être" ZZZZZ "(5 fois Z) pour ISO 8601 au lieu d'un simple" Z " (qui est pour le format RFC 822). Au moins sur iOS 6.

(voir ) http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns )

27
répondu Etienne 2013-09-04 08:06:58

utilisez donc la catégorie de Sam Soffee sur NSDate found ici . Avec ce code ajouté à votre projet, vous pouvez désormais utiliser une seule méthode sur NSDate:

- (NSString *)sam_ISO8601String

non seulement il est une ligne, son beaucoup plus rapide que L'approche NSDateFormatter, depuis son écrit en C pur.

8
répondu David H 2014-04-07 15:20:13

de IS8601 , les problèmes sont la représentation et le fuseau horaire

  • ISO 8601 = year-month-day time timezone
  • Pour la date et l'heure, il y a de base (AAAAMMJJ, hhmmss, ...) et le format étendu (AAAA-MM-JJ, hh: mm: ss,...)
  • fuseau horaire peut être Zoulou, offset ou GMT
  • séparateur pour la date et l'heure peut être l'espace, ou T
  • il y a format de la semaine pour la date, mais il est rarement utilisé
  • Timezone peut être beaucoup d'espaces après
  • Second est facultatif

Voici quelques chaînes valides

2016-04-08T10:25:30Z
2016-04-08 11:25:30+0100
2016-04-08 202530GMT+1000
20160408 08:25:30-02:00
2016-04-08 11:25:30     +0100

Solutions

NSDateFormatter

voici donc le format que j'utilise dans onmyway133 ISO8601

let formatter = NSDateFormatter()
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
formatter.dateFormat = "yyyyMMdd HHmmssZ"

à propos du Z identificateur Date zone Table symbole

Z: The ISO8601 basic format with hours, minutes and optional seconds fields. The format is equivalent to RFC 822 zone format (when optional seconds field is absent)

à propos de locale formatage des données en utilisant les paramètres locaux

Locales représentent les choix de formatage pour un utilisateur particulier, pas la langue préférée de l'utilisateur. Ce sont souvent les mêmes mais peuvent être différents. Par exemple, un locuteur natif de l'anglais qui vit en Allemagne pourrait choisir l'anglais comme langue et L'Allemagne comme région

à propos de en_US_POSIX Q&A technique QA1480 NSDateFormatter and Internet Dates

d'un autre côté, si vous travaillez avec des dates à format fixe, vous devez d'abord définir la locale du formatteur de date à quelque chose d'approprié pour votre format fixe. Dans la plupart des cas, la meilleure locale à choisir est "en_US_POSIX", une locale qui est spécifiquement conçu pour nous donner des résultats en anglais indépendamment des préférences de l'utilisateur et du système. "en_US_POSIX" est également invariant dans le temps (si les États-Unis, à un moment donné dans le futur, modifie la façon dont ils formatent les dates, "en_US" changera pour refléter nouveau comportement, mais "en_US_POSIX"ne le fera pas), et entre les machines ("en_US_POSIX" fonctionne de la même manière sur iOS que sur OS X, et comme il le fait sur d'autres plateformes).

Intéressantes liées quetions

5
répondu onmyway133 2017-05-23 12:26:08

un problème souvent négligé est que les chaînes au format ISO 8601 peuvent avoir des millisecondes et peuvent ne pas l'avoir.

en d'autres termes, les deux" 2016-12-31T23:59:59.9999999 "et" 2016-12-01T00:00:00 " sont légitimes, mais si vous utilisez un formatage de date static-typed, l'un d'eux ne sera pas analysé.

à partir de iOS 10 vous devez utiliser ISO8601DateFormatter qui gère toutes les variations des chaînes de date ISO 8601. Voir l'exemple ci-dessous:

let date = Date()
var string: String

let formatter = ISO8601DateFormatter()
string = formatter.string(from: date)

let GMT = TimeZone(abbreviation: "GMT")
let options: ISO8601DateFormatOptions = [.withInternetDateTime, .withDashSeparatorInDate, .withColonSeparatorInTime, .withTimeZone]
string = ISO8601DateFormatter.string(from: date, timeZone: GMT, formatOptions: options)

Pour iOS 9 et ci-dessous utiliser l'approche suivante de données multiples formateurs.

Je n'ai pas trouvé de réponse qui couvre à la fois les cas et résume cette différence subtile. Voici la solution qui l'aborde:

extension DateFormatter {

    static let iso8601DateFormatter: DateFormatter = {
        let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX")
        let iso8601DateFormatter = DateFormatter()
        iso8601DateFormatter.locale = enUSPOSIXLocale
        iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
        iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
        return iso8601DateFormatter
    }()

    static let iso8601WithoutMillisecondsDateFormatter: DateFormatter = {
        let enUSPOSIXLocale = Locale(identifier: "en_US_POSIX")
        let iso8601DateFormatter = DateFormatter()
        iso8601DateFormatter.locale = enUSPOSIXLocale
        iso8601DateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'"
        iso8601DateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
        return iso8601DateFormatter
    }()

    static func date(fromISO8601String string: String) -> Date? {
        if let dateWithMilliseconds = iso8601DateFormatter.date(from: string) {
            return dateWithMilliseconds
        }

        if let dateWithoutMilliseconds = iso8601WithoutMillisecondsDateFormatter.date(from: string) {
            return dateWithoutMilliseconds
        }

        return nil
    }
}

Utilisation:

let dateToString = "2016-12-31T23:59:59.9999999"
let dateTo = DateFormatter.date(fromISO8601String: dateToString)
// dateTo: 2016-12-31 23:59:59 +0000

let dateFromString = "2016-12-01T00:00:00"
let dateFrom = DateFormatter.date(fromISO8601String: dateFromString)
// dateFrom: 2016-12-01 00:00:00 +0000

je recommande aussi de vérifier article de pomme à propos de la date formateuses.

5
répondu Vadim Bulavin 2018-05-08 10:02:22

basé sur cette gist: https://github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift , la méthode suivante peut être utilisée pour convertir NSDate en chaîne de date ISO 8601 dans le format AAAA-MM-jj'T'HH:mm:SS.Sssz

-(NSString *)getISO8601String
    {
        static NSDateFormatter *formatter = nil;
        if (!formatter)
        {
            formatter = [[NSDateFormatter alloc] init];
            [formatter setLocale: [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]];
            formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation: @"UTC"];
            [formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS"];

        }
        NSString *iso8601String = [formatter stringFromDate: self];
        return [iso8601String stringByAppendingString: @"Z"];
    }
3
répondu Zack Zhu 2016-05-03 00:46:03

il suffit d'utiliser NSISO8601DateFormatter de la Fondation de cadre.

let isoDateFormatter = ISO8601DateFormatter()
print("ISO8601 string: \(isoDateFormatter.string(from: Date()))")
// ISO8601 string: 2018-03-21T19:11:46Z

https://developer.apple.com/documentation/foundation/nsiso8601dateformatter?language=objc

3
répondu LLIAJLbHOu 2018-03-21 19:12:37

C'est un peu plus simple et met la date dans UTC.

extension NSDate
{
    func iso8601() -> String
    {
        let dateFormatter = NSDateFormatter()
        dateFormatter.timeZone = NSTimeZone(name: "UTC")
        let iso8601String = dateFormatter.stringFromDate(NSDate())
        return iso8601String
    }
}

let date = NSDate().iso8601()
0
répondu iphaaw 2016-08-20 07:53:04

utilisant Swift 3.0 et iOS 9.0

extension Date {
    private static let jsonDateFormatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(identifier: "UTC")!
        return formatter
    }()

    var IOS8601String: String {
        get {
            return Date.jsonDateFormatter.string(from: self)
        }
    }

    init?(fromIOS8601 dateString: String) {
        if let d = Date.jsonDateFormatter.date(from: dateString) {
            self.init(timeInterval: 0, since:d)
        } else {
            return nil
        }
    }
}
-1
répondu Denis Krivitski 2017-04-02 14:25:54