IT

NSDateFormatter 로케일 "기능"을 처리하는 가장 좋은 방법은 무엇입니까?

itgroup 2023. 6. 12. 21:18
반응형

NSDateFormatter 로케일 "기능"을 처리하는 가장 좋은 방법은 무엇입니까?

는 것 같습니다.NSDateFormatter에는 예기치 않게 다음과 같은 "기능"이 기능은 다음과 같습니다.다음과 같은 간단한 "고정" 형식 작업을 수행하는 경우:

NSDateFormatter* fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyyMMddHHmmss"];
NSString* dateStr = [fmt stringFromDate:someDate];
[fmt release];

그러면 미국과 대부분의 지역에서 24시간 지역으로 전화를 설정한 사람이 12/24시간 스위치를 12로 설정할 때까지 작동합니다.그런 다음 위에서 "AM" 또는 "PM"을 결과 문자열 끝에 고정하기 시작합니다.

(예: NSDateFormatter를 참조하십시오. 내가 잘못하고 있는 것입니까 아니면 버그입니까?)

(또한 https://developer.apple.com/library/content/qa/qa1480/_index.html) 를 참조하십시오.

분명히 애플은 이것을 "나쁜" 것으로 선언했습니다. "설계된 대로 고장났습니다." 그리고 그들은 그것을 고치지 않을 것입니다.

이 회피책은 일반적으로 미국과 같은 특정 지역에 대한 날짜 형식의 로케일을 설정하기 위한 것으로 보이지만, 이는 약간 지저분합니다.

NSLocale *loc = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[df setLocale: loc];
[loc release];

1-2-2개의 경우에는 그리 나쁘지 않지만, 저는 약 10개의 다른 앱들을 다루고 있습니다. 제가 처음으로 본 것은 43개의 시나리오를 가지고 있습니다.

매크로/오버라이드 클래스에 대한 현명한 아이디어/코드를 모호하게 만들지 않고 모든 것을 변경하려는 노력을 최소화할 수 있는 방법은 무엇입니까?(첫 번째 본능은 init 메서드에서 로케일을 설정하는 버전으로 NSDateFormatter를 재정의하는 것입니다.alloc/init 라인과 추가된 가져오기의 두 줄을 변경해야 합니다.)

##추가됨

이것이 제가 지금까지 생각해낸 것입니다. 모든 시나리오에서 작동하는 것 같습니다.

@implementation BNSDateFormatter

-(id)init {
static NSLocale* en_US_POSIX = nil;
NSDateFormatter* me = [super init];
if (en_US_POSIX == nil) {
    en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
[me setLocale:en_US_POSIX];
return me;
}

@end

##ReOMZ의 제안 업데이트, 여기 제가 발견한 것이 있습니다.

다음은 범주 버전 --h 파일입니다.

#import <Foundation/Foundation.h>


@interface NSDateFormatter (Locale)
- (id)initWithSafeLocale;
@end

범주 m 파일:

#import "NSDateFormatter+Locale.h"


@implementation NSDateFormatter (Locale)

- (id)initWithSafeLocale {
static NSLocale* en_US_POSIX = nil;
self = [super init];
if (en_US_POSIX == nil) {
    en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
NSLog(@"Category's locale: %@ %@", en_US_POSIX.description, [en_US_POSIX localeIdentifier]);
[self setLocale:en_US_POSIX];
return self;    
}

@end

코드:

NSDateFormatter* fmt;
NSString* dateString;
NSDate* date1;
NSDate* date2;
NSDate* date3;
NSDate* date4;

fmt = [[NSDateFormatter alloc] initWithSafeLocale];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
dateString = [fmt stringFromDate:[NSDate date]];
NSLog(@"dateString = %@", dateString);
date1 = [fmt dateFromString:@"2001-05-05 12:34:56"];
NSLog(@"date1 = %@", date1.description);
date2 = [fmt dateFromString:@"2001-05-05 22:34:56"];
NSLog(@"date2 = %@", date2.description);
date3 = [fmt dateFromString:@"2001-05-05 12:34:56PM"];  
NSLog(@"date3 = %@", date3.description);
date4 = [fmt dateFromString:@"2001-05-05 12:34:56 PM"]; 
NSLog(@"date4 = %@", date4.description);
[fmt release];

fmt = [[BNSDateFormatter alloc] init];
[fmt setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
dateString = [fmt stringFromDate:[NSDate date]];
NSLog(@"dateString = %@", dateString);
date1 = [fmt dateFromString:@"2001-05-05 12:34:56"];
NSLog(@"date1 = %@", date1.description);
date2 = [fmt dateFromString:@"2001-05-05 22:34:56"];
NSLog(@"date2 = %@", date2.description);
date3 = [fmt dateFromString:@"2001-05-05 12:34:56PM"];  
NSLog(@"date3 = %@", date3.description);
date4 = [fmt dateFromString:@"2001-05-05 12:34:56 PM"]; 
NSLog(@"date4 = %@", date4.description);
[fmt release];

결과:

2011-07-11 17:44:43.243 DemoApp[160:307] Category's locale: <__NSCFLocale: 0x11a820> en_US_POSIX
2011-07-11 17:44:43.257 DemoApp[160:307] dateString = 2011-07-11 05:44:43 PM
2011-07-11 17:44:43.264 DemoApp[160:307] date1 = (null)
2011-07-11 17:44:43.272 DemoApp[160:307] date2 = (null)
2011-07-11 17:44:43.280 DemoApp[160:307] date3 = (null)
2011-07-11 17:44:43.298 DemoApp[160:307] date4 = 2001-05-05 05:34:56 PM +0000
2011-07-11 17:44:43.311 DemoApp[160:307] Extended class's locale: <__NSCFLocale: 0x11a820> en_US_POSIX
2011-07-11 17:44:43.336 DemoApp[160:307] dateString = 2011-07-11 17:44:43
2011-07-11 17:44:43.352 DemoApp[160:307] date1 = 2001-05-05 05:34:56 PM +0000
2011-07-11 17:44:43.369 DemoApp[160:307] date2 = 2001-05-06 03:34:56 AM +0000
2011-07-11 17:44:43.380 DemoApp[160:307] date3 = (null)
2011-07-11 17:44:43.392 DemoApp[160:307] date4 = (null)

[make that a iPod Touch] 전화기는 12/24 스위치가 12로 설정된 영국으로 설정되어 있습니다.두 가지 결과에는 분명한 차이가 있고, 저는 카테고리 버전이 틀렸다고 판단합니다.카테고리 버전의 로그가 실행 중이므로(코드에 배치된 중지가 히트됨) 단순히 코드가 사용되지 않는 경우가 아닙니다.

##궁금한 관찰

범주 구현을 약간 수정했습니다.

#import "NSDateFormatter+Locale.h"

@implementation NSDateFormatter (Locale)

- (id)initWithSafeLocale {
static NSLocale* en_US_POSIX2 = nil;
self = [super init];
if (en_US_POSIX2 == nil) {
    en_US_POSIX2 = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
}
NSLog(@"Category's locale: %@ %@", en_US_POSIX2.description, [en_US_POSIX2 localeIdentifier]);
[self setLocale:en_US_POSIX2];
NSLog(@"Category's object: %@ and object's locale: %@ %@", self.description, self.locale.description, [self.locale localeIdentifier]);
return self;    
}

@end

기본적으로 정적 로케일 변수의 이름을 변경하고(서브 클래스에서 선언된 정적과 충돌하는 경우) NSLog를 추가했습니다.NSLog에서 출력하는 내용을 확인하십시오.

2011-07-15 16:35:24.322 DemoApp[214:307] Category's locale: <__NSCFLocale: 0x160550> en_US_POSIX
2011-07-15 16:35:24.338 DemoApp[214:307] Category's object: <NSDateFormatter: 0x160d90> and object's locale: <__NSCFLocale: 0x12be70> en_GB
2011-07-15 16:35:24.345 DemoApp[214:307] dateString = 2011-07-15 04:35:24 PM
2011-07-15 16:35:24.370 DemoApp[214:307] date1 = (null)
2011-07-15 16:35:24.378 DemoApp[214:307] date2 = (null)
2011-07-15 16:35:24.390 DemoApp[214:307] date3 = (null)
2011-07-15 16:35:24.404 DemoApp[214:307] date4 = 2001-05-05 05:34:56 PM +0000

보시다시피 세트 로케일은 그렇지 않았습니다.포맷터의 로케일은 여전히 en_GB입니다.범주의 init 메서드에 대해 "이상한" 부분이 있는 것 같습니다.

앗!!

때로는 "아하!" 순간이 있고, 때로는 "우!"에 더 가깝습니다.이것은 후자입니다. 에서.initWithSafeLocale" .init가 됨화드로 되었습니다.self = [super init];은 이은그슈클있습다니에스래퍼의 에 있습니다.NSDateFormatter하지만 그렇지 않습니다.init그자리의 NSDateFormatter이의 제기 자체.

이 때, 이초화건면뛰너를기,,setLocale개체의 일부 누락된 데이터 구조 때문인 것으로 추정됩니다.initself = [self init];은 인은입니다.NSDateFormatter하며, "는 " "라는 이름으로 표시합니다.setLocale다시 행복합니다.

카테고리의 .m에 대한 "최종" 소스는 다음과 같습니다.

#import "NSDateFormatter+Locale.h"

@implementation NSDateFormatter (Locale)

- (id)initWithSafeLocale {
    static NSLocale* en_US_POSIX = nil;
    self = [self init];
    if (en_US_POSIX == nil) {
        en_US_POSIX = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
    }
    [self setLocale:en_US_POSIX];
    return self;    
}

@end

하위 분류 대신 다음을 생성할 수 있습니다.NSDateFormatter로케일 할당을 처리하는 추가 이니셜라이저가 있는 범주 및 형식 문자열이 있으므로 초기화한 후 바로 사용할 수 있는 포맷터가 제공됩니다.

@interface NSDateFormatter (LocaleAdditions)

- (id)initWithPOSIXLocaleAndFormat:(NSString *)formatString;

@end

@implementation NSDateFormatter (LocaleAdditions)

- (id)initWithPOSIXLocaleAndFormat:(NSString *)formatString {
    self = [super init];
    if (self) {
        NSLocale *locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
        [self setLocale:locale];
        [locale release];
        [self setFormat:formatString];
    }
    return self;
}

@end

그러면 당신은 사용할 수 있습니다.NSDateFormatter코드의 모든 위치에서 다음을 수행할 수 있습니다.

NSDateFormatter* fmt = [[NSDateFormatter alloc] initWithPOSIXLocaleAndFormat:@"yyyyMMddHHmmss"];

Apple이 향후 OS 버전에서 이름 충돌을 방지하기 위해 범주 메서드를 접두사로 추가할 수도 있습니다.

날짜 : 일 한날형사는경사싱예인특우스를반스턴정환글있범추수하메습다니도할가를드주서는상성구용톤을하용여짜식하을예▁in▁with▁methods▁that▁liketon(있something▁format▁you▁single▁instances수(다니습▁category:)을 사용하는 경우 싱글톤 인스턴스를 방법을 추가할 수 .+sharedRFC3339DateFormatter). 단, 다음 사항을 유의하시기 바랍니다.NSDateFormatter가 아니며 스드세가아잠금장사치합용니다야해를니이며프레▁locks▁을 사용해야 합니다.@synchronized여러 스레드에서 동일한 인스턴스를 사용하는 경우 차단합니다.

제가 완전히 다른 것을 제안해도 될까요? 솔직히 말해서, 이 모든 것은 토끼굴로 흘러가고 있기 때문입니다.

당신은 하나를 사용해야 합니다.NSDateFormatter와 함께dateFormat 및 세트앤locale할 수밖에 없는.en_US_POSIX(서버/API에서) 날짜를 수신합니다.

그렇다면 당신은 다른 것을 사용해야 합니다.NSDateFormatter UI 우경을 timeStyle/dateStyle속성 - 이렇게 하면 명시적이지 않습니다.dateFormat사용자가 직접 설정하므로 형식이 사용될 것이라고 잘못 가정합니다.

, 는 사용자 설정선택에 에 의해 , " "NSDate사용할 수 있습니다.

여기 빠른 버전의 그 문제에 대한 해결책이 있습니다.신속하게 범주 대신 확장을 사용할 수 있습니다.그래서 여기서 나는 DateFormatter의 확장자를 만들었고 initWithSafeLocale은 관련 로케일과 함께 DateFormatter를 반환합니다. 여기서 우리의 경우 en_US_POSIX는 그것 외에도 몇 가지 날짜 형성 방법을 제공했습니다.

  • 스위프트 4

    extension DateFormatter {
    
    private static var dateFormatter = DateFormatter()
    
    class func initWithSafeLocale(withDateFormat dateFormat: String? = nil) -> DateFormatter {
    
        dateFormatter = DateFormatter()
    
        var en_US_POSIX: Locale? = nil;
    
        if (en_US_POSIX == nil) {
            en_US_POSIX = Locale.init(identifier: "en_US_POSIX")
        }
        dateFormatter.locale = en_US_POSIX
    
        if dateFormat != nil, let format = dateFormat {
            dateFormatter.dateFormat = format
        }else{
            dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        }
        return dateFormatter
    }
    
    // ------------------------------------------------------------------------------------------
    
    class func getDateFromString(string: String, fromFormat dateFormat: String? = nil) -> Date? {
    
        if dateFormat != nil, let format = dateFormat {
            dateFormatter = DateFormatter.initWithSafeLocale(withDateFormat: format)
        }else{
            dateFormatter = DateFormatter.initWithSafeLocale()
        }
        guard let date = dateFormatter.date(from: string) else {
            return nil
        }
        return date
    }
    
    // ------------------------------------------------------------------------------------------
    
    class func getStringFromDate(date: Date, fromDateFormat dateFormat: String? = nil)-> String {
    
        if dateFormat != nil, let format = dateFormat {
            dateFormatter = DateFormatter.initWithSafeLocale(withDateFormat: format)
        }else{
            dateFormatter = DateFormatter.initWithSafeLocale()
        }
    
        let string = dateFormatter.string(from: date)
    
        return string
    }   }
    
  • 사용법 설명:

    let date = DateFormatter.getDateFromString(string: "11-07-2001”, fromFormat: "dd-MM-yyyy")
    print("custom date : \(date)")
    let dateFormatter = DateFormatter.initWithSafeLocale(withDateFormat: "yyyy-MM-dd HH:mm:ss")
    let dt = DateFormatter.getDateFromString(string: "2001-05-05 12:34:56")
    print("base date = \(dt)")
    dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    let dateString = dateFormatter.string(from: Date())
    print("dateString = " + dateString)
    let date1 = dateFormatter.date(from: "2001-05-05 12:34:56")
    print("date1 = \(String(describing: date1))")
    let date2 = dateFormatter.date(from: "2001-05-05 22:34:56")
    print("date2 = \(String(describing: date2))")
    let date3 = dateFormatter.date(from: "2001-05-05 12:34:56PM")
    print("date3 = \(String(describing: date3))")
    let date4 = dateFormatter.date(from: "2001-05-05 12:34:56 PM")
    print("date4 = \(String(describing: date4))")
    

언급URL : https://stackoverflow.com/questions/6613110/what-is-the-best-way-to-deal-with-the-nsdateformatter-locale-feature

반응형