web-dev-qa-db-ja.com

iOSでISO 8601の日付を取得するにはどうすればよいですか?

date('c')を介してPHPでISO 8601日付文字列(たとえば、2004-02-12T15:19:21+00:00)を取得するのは簡単ですが、Objective-C(iPhone)ではどのように取得しますか?同様の短い方法がありますか?

これがlongの方法です。

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

とても中心的な何かのためのひどい多くのリグマロールのようです。

106
JohnK

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"];
[dateFormatter setCalendar:[NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian]];

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

そして、Swiftでは:

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

let iso8601String = dateFormatter.string(from: Date())
207
rmaddy

iOS 10では、これを処理するための新しい NSISO8601DateFormatter クラスが導入されています。 Swift 3を使用している場合、コードは次のようになります。

let formatter = ISO8601DateFormatter()
let date = formatter.date(from: "2016-08-26T12:39:00Z")
let string = formatter.string(from: Date())
48
TwoStraws

Maddyの答えを補完するものとして、タイムゾーン形式は、単一の「Z」(RFC 822形式)ではなく、ISO 8601の「ZZZZZ」(Zの5倍)でなければなりません。少なくともiOS 6。

http://www.unicode.org/reports/tr35/tr35-25.html#Date_Format_Patterns を参照)

27
Etienne

よく見落とされがちな問題は、ISO 8601形式の文字列にはミリ秒がある場合とない場合があることです。

つまり、「2016-12-31T23:59:59.9999999」と「2016-12-01T00:00:00」はどちらも合法ですが、静的型の日付フォーマッターを使用している場合は、どちらかが解析されません。

iOS 10から開始して、ISO 8601日付文字列のすべてのバリエーションを処理するISO8601DateFormatterを使用する必要があります。以下の例を参照してください。

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)

iOS 9以下では、複数のデータフォーマッタで次のアプローチを使用します。

この微妙な違いを取り除いて、ケースとアブストラクトの両方をカバーする答えは見つかりませんでした。これに対処するソリューションは次のとおりです。

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

使用法:

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

また、日付フォーマッタについて Appleの記事 を確認することもお勧めします。

14
Vadim Bulavin

NSDateのSam Soffeeのカテゴリを使用してください here 。そのコードをプロジェクトに追加すると、それ以降はNSDateで単一のメソッドを使用できます。

- (NSString *)sam_ISO8601String

純粋なCで記述されているため、NSDateFormatterアプローチよりもはるかに高速な1行だけではありません。

8
David H

IS8601 から、問題は表現とタイムゾーンです

  • ISO 8601 = year-month-day time timezone
  • 日付と時刻には、基本形式(YYYYMMDD、hhmmss、...)と拡張形式(YYYY-MM-DD、hh:mm:ss、...)があります
  • タイムゾーンは、ズールー語、オフセット、またはGMTです。
  • 日付と時刻の区切りには、スペースまたはTを使用できます
  • 日付には週形式がありますが、めったに使用されません
  • タイムゾーンは後にスペースが多くなることがあります
  • 2番目はオプションです

有効な文字列は次のとおりです

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

ソリューション

NSDateFormatter

だからここで私が使用している形式は onmyway133 ISO8601

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

Z識別子について 日付フィールドシンボルテーブル

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)

localeについて ロケール設定を使用したデータのフォーマット

ロケールは、ユーザーの優先言語ではなく、特定のユーザーの書式設定の選択肢を表します。これらはしばしば同じですが、異なる場合があります。たとえば、ドイツに住んでいるネイティブスピーカーは、言語として英語を選択し、地域としてドイツを選択します。

en_US_POSIXについて 技術的なQ&A QA1480 NSDateFormatterとインターネット日付

一方、固定形式の日付を使用している場合は、まず日付フォーマッターのロケールを固定形式に適したものに設定する必要があります。ほとんどの場合、選択する最適なロケールは「en_US_POSIX」です。これは、ユーザー設定とシステム設定の両方に関係なく、米国英語の結果が得られるように特別に設計されたロケールです。 「en_US_POSIX」も時間的に不変です(米国が将来のある時点で日付のフォーマット方法を変更した場合、「en_US」は新しい動作を反映するように変更されますが、「en_US_POSIX」は変更されません)、およびマシン間( 「en_US_POSIX」は、iOS上でもOS X上でも、他のプラットフォーム上でも同じように機能します)。

興味深い関連質問

6
onmyway133

FoundationフレームワークのNSISO8601DateFormatterを使用するだけです。

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

4
LLIAJLbHOu

この要点に基づいて: https://github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.Swift 、次の方法を使用してNSDateをISO 8601日付文字列に変換できますyyyy-MM-dd'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
Zack Zhu

これは少し簡単で、日付を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
iphaaw