iOS에서 ISO 8601 날짜를 얻으려면 어떻게해야합니까?


115

ISO 8601 날짜 문자열 (예 : 2004-02-12T15:19:21+00:00PHP에서date('c') Objective-C (iPhone)에서는 어떻게 얻습니까? 그것을 수행하는 비슷한 짧은 방법이 있습니까?

여기에 내가 찾은 방법이 있습니다.

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

너무 중심적인 것에 대해 엄청나게 많은 리마 롤처럼 보입니다.


1
나는 짧은 것이 보는 사람의 눈에 있다고 생각합니다. 세 줄의 코드는 매우 짧습니다. 추가 할 수있는 C NSDate 하위 클래스가 있으며 한 줄로 수행 할 수 있습니다. github.com/soffes/SAMCategories/tree/master/SAMCategories/… . 즉, 정말 좋은 답변 (IMHO)을 받았으며 Etienne 또는 rmaddy에게 답변을 제공해야합니다. 그저 좋은 습관과 실제 유용한 정보를 제공하는 사람들에게 보상을줍니다 (이 정보가 오늘 필요했습니다). Etienne은 rmaddy보다 포인트를 더 많이 사용할 수 있습니다. 좋은 측정의 표시로 나는 당신의 질문에 찬성 투표 할 것입니다!
David H

답변:


212

사용 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())

1
고마워, 매디. 내 코드를 게시 한 후 방금 귀하의 답변을 보았습니다. 인가 setLocale중요?
JohnK

2
@rmaddy ZZZZZ를 사용하도록 예제를 편집하여 사람들이 복사-붙여 넣기에 화상을 입지 않도록 할 수 있습니다.
Jesse Rusak 2014 년

4
@jlmendezbonini 아니요. YYYY를 원하는 것은 매우 드뭅니다. 일반적으로 yyyy를 원합니다.
rmaddy

7
로케일을 en_US_POSIX로 설정해야하는 이유에 대한 소스 : developer.apple.com/library/mac/qa/qa1480/_index.html
yood

11
@maddy-Google을 통해 다른 사람들이이를 쉽게 발견 할 수 있도록하고 싶었고 올바른 형식, 로케일 등을 실제로 찾아낸 것에 대한 크레딧을 제공하고 싶었습니다.하지만 원하는 경우 별도의 답변으로 게시하게되어 기쁩니다
Robin

60

iOS 10에는 NSISO8601DateFormatter이를 처리 하는 새로운 클래스가 도입되었습니다 . Swift 3를 사용하는 경우 코드는 다음과 같습니다.

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

그리고 어떤 형식을 제공합니까? 또한 2016-08-26T12 : 39 : 00-0000 및 2016-08-26T12 : 39 : 00-00 : 00 및 2016-08-26T12 : 39 : 00.374-0000에서 처리 할 수 ​​있는지 아는 것이 좋습니다.
malhal

1
내 대답의 세 줄이 실행되면 string"2016-09-03T21 : 47 : 27Z"가 포함됩니다.
TwoStraws

3
이 형식으로 는 밀리 초 를 처리 할 수 없습니다 .
Enrique

3
@Enrique : NSISO8601DateFormatWithFractionalSeconds를 포맷터 옵션에 추가해야 밀리 초로 작업 할 수 있습니다. 문서를 확인하세요.
PakitoV

1
NSISO8601DateFormatWithFractionalSeconds는 11.2 이상에서만 작동합니다. 그렇지 않으면 충돌이 발생했습니다!
hash3r

27

maddy의 답변을 보완하기 위해 표준 시간대 형식은 단일 "Z"(RFC 822 형식) 대신 ISO 8601의 경우 "ZZZZZ"(Z의 5 배) 여야합니다. 적어도 iOS 6에서는.

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


그레이트 캐치! 이에 관심이있는 다른 사람은 링크로 이동하여 8601을 검색하면 볼 수 있습니다.
David H

날짜의 시간대가 UTC 인 경우 Z (동등한) 대신 00:00을 표시 할 수있는 방법이 있습니까?
shim

고마워요;) dateformatter가 날짜를 반환하지 않고 벽에 머리를 두드리는 중이었습니다 !!! :)
polo987

19

자주 간과되는 문제는 ISO 8601 형식의 문자열이 밀리 초를 가질 수도 있고 그렇지 않을 수도 있다는 것입니다.

즉, "2016-12-31T23 : 59 : 59.9999999"와 "2016-12-01T00 : 00 : 00"은 모두 합법적이지만 정적 형식의 날짜 포맷터를 사용하는 경우 둘 중 하나가 파싱되지 않습니다. .

iOS 10 부터 ISO8601DateFormatterISO 8601 날짜 문자열의 모든 변형을 처리 하는 것을 사용해야 합니다. 아래 예를 참조하십시오.

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)

들어 아이폰 OS 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 기사 를 확인하는 것이 좋습니다 .


Obj-C에서 NSISO8601DateFormtter를 확보하는 방법도 말씀해 주시겠습니까? (물론 위의 아이폰 OS 10에)
은 Motti Shneor

8

따라서 여기 에있는 NSDate에서 Sam Soffee의 카테고리를 사용 하십시오 . 해당 코드를 프로젝트에 추가하면 NSDate에서 단일 메서드를 사용할 수 있습니다.

- (NSString *)sam_ISO8601String

순수한 C로 작성 되었기 때문에 NSDateFormatter 접근 방식보다 훨씬 빠른 한 줄일뿐만 아니라


1
카테고리의 현재 위치는 여기에 있습니다
Perry

1
나는 그것에 대해 조언하고
싶습니다

1
@M_Waly 그에게 이것을보고 했습니까? 경고없이 그의 코드를 만들었고 분석 검사를 통과했습니다.
David H

6

에서 IS8601 , 문제는 표현 및 시간대입니다

  • ISO 8601 = year-month-day time timezone
  • 날짜 및 시간에는 기본 (YYYYMMDD, hhmmss, ...) 및 확장 형식 (YYYY-MM-DD, hh : mm : ss, ...)이 있습니다.
  • 시간대는 Zulu, 오프셋 또는 GMT 일 수 있습니다.
  • 날짜 및 시간 구분 기호는 공백이거나 T
  • 날짜에 대한 주 형식이 있지만 거의 사용되지 않습니다.
  • 시간대는 이후에 많은 공간이 될 수 있습니다.
  • 두 번째는 선택 사항입니다.

다음은 유효한 문자열입니다.

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와 ​​다른 플랫폼에서와 동일하게 작동합니다.

흥미로운 관련 질문


24 : 난 그냥 2016-07-23T07과 노력 23Z, 그것은 작동하지 않습니다
가면 Dobrev을

@KamenDobrev "작동하지 않음"이란 무엇을 의미합니까? 나는 단지 당신의 예제를 테스트 github.com/onmyway133/ISO8601/blob/master/ISO8601Tests/…에 추가 하고 작동합니다
onmyway133


3

이 요점을 기반으로 : https://github.com/justinmakaila/NSDate-ISO-8601/blob/master/NSDateISO8601.swift , 다음 방법을 사용하여 NSDate를 yyyy-MM 형식의 ISO 8601 날짜 문자열로 변환 할 수 있습니다. -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"];
    }

S하위 초 동안 여기에 핵심이었다
마크 마이어

3 개 이상의 S가 필요한 경우 날짜 포맷터를 사용하여 수동으로 구문 분석 할 수 없습니다.
malhal

-1

이것은 조금 더 간단하며 날짜를 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()

-1

Swift 3.0 및 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
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.