处理 NSDateFormatter 区域设置“功能”的最佳方法是什么?

发布于 2024-11-18 20:02:19 字数 5840 浏览 3 评论 0原文

似乎 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

显然苹果已经宣称这是“BAD”——破坏了设计,并且他们不会修复它。

规避显然是为特定区域(通常是美国)设置日期格式化程序的区域设置,但这有点混乱:

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

在 onesies-twosies 中还不错,但我正在处理大约十个不同的应用程序,第一个我看到有 43 个这种情况的实例。

那么,对于宏/重写的类/任何东西,有什么聪明的想法可以最大限度地减少更改所有内容的工作量,而不会使代码变得模糊吗? (我的第一直觉是用一个可以在 init 方法中设置区域设置的版本覆盖 NSDateFormatter。需要更改两行 - alloc/init 行和添加的导入。)

##Added

这是我想出的到目前为止——似乎适用于所有场景:

@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

##Update 关于 OMZ 的提案,这就是我发现的 --

这是类别版本 -- 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)

电话 [将其设为 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

如您所见,setLocale 根本没有打印。格式化程序的区域设置仍然是 en_GB。看起来类别中的 init 方法有些“奇怪”。

It seems that NSDateFormatter has a "feature" that bites you unexpectedly: If you do a simple "fixed" format operation such as:

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

Then it works fine in the US and most locales UNTIL ... someone with their phone set to a 24-hour region sets the 12/24 hour switch in settings to 12. Then the above starts tacking "AM" or "PM" onto the end of the resulting string.

(See, eg, NSDateFormatter, am I doing something wrong or is this a bug?)

(And see https://developer.apple.com/library/content/qa/qa1480/_index.html)

Apparently Apple has declared this to be "BAD" -- Broken As Designed, and they aren't going to fix it.

The circumvention is apparently to set the locale of the date formatter for a specific region, generally the US, but this is a bit messy:

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

Not too bad in onesies-twosies, but I'm dealing with about ten different apps, and the first one I look at has 43 instances of this scenario.

So any clever ideas for a macro/overridden class/whatever to minimize the effort to change everything, without making the code to obscure? (My first instinct is to override NSDateFormatter with a version that would set the locale in the init method. Requires changing two lines -- the alloc/init line and the added import.)

##Added

This is what I've come up with so far -- seems to work in all scenarios:

@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

##Update
Re OMZ's proposal, here is what I'm finding --

Here is the category version -- h file:

#import <Foundation/Foundation.h>


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

Category m file:

#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

The code:

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];

The result:

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)

The phone [make that an iPod Touch] is set to Great Britain, with the 12/24 switch set to 12. There's a clear difference in the two results, and I judge the category version to be wrong. Note that the log in the category version IS getting executed (and stops placed in the code are hit), so it's not simply a case of the code somehow not getting used.

##A curious observation

Modified the category implementation slightly:

#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

Basically just changed the name of the static locale variable (in case there was some conflict with the static declared in the subclass) and added the extra NSLog. But look what that NSLog prints:

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

As you can see, the setLocale simply didn't. The locale of the formatter is still en_GB. It appears that there is something "strange" about an init method in a category.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

苄①跕圉湢 2024-11-25 20:02:19

呃!!

有时你会“啊哈!!”有时候,这更像是“呃!!”这是后者。在 initWithSafeLocale 类别中,“super”init 被编码为 self = [super init];。这会初始化 NSDateFormatter 的 SUPERCLASS,但不会init NSDateFormatter 对象本身。

显然,当跳过此初始化时,setLocale“反弹”,可能是因为对象中缺少某些数据结构。将 init 更改为 self = [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

Duh!!

Sometimes you have an "Aha!!" moment, sometimes it's more of a "Duh!!" This is the latter. In the category for initWithSafeLocale the "super" init was coded as self = [super init];. This inits the SUPERCLASS of NSDateFormatter but does not init the NSDateFormatter object itself.

Apparently when this initialization is skipped, setLocale "bounces off", presumably because of some missing data structure in the object. Changing the init to self = [self init]; causes the NSDateFormatter initialization to occur, and setLocale is happy again.

Here is the "final" source for the category's .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
神妖 2024-11-25 20:02:19

您可以创建一个带有附加初始化程序的 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 决定在未来版本的操作系统中添加此类方法。

如果您始终使用相同的日期格式,您还可以添加返回具有某些配置的单例实例的类别方法(例如 +sharedRFC3339DateFormatter)。但请注意,NSDateFormatter 不是线程安全的,当您从多个线程使用同一实例时,您必须使用锁或@synchronized 块。

Instead of subclassing, you could create an NSDateFormatter category with an additional initializer that takes care of assigning the locale and possibly also a format string, so you'd have a ready-to-use formatter right after initializing it.

@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

Then you could use NSDateFormatter anywhere in your code with just:

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

You might want to prefix your category method somehow to avoid name conflicts, just in case Apple decides to add such a method in a future version of the OS.

In case you're always using the same date format(s), you could also add category methods that return singleton instances with certain configurations (something like +sharedRFC3339DateFormatter). Be aware however that NSDateFormatter is not thread-safe and you have to use locks or @synchronized blocks when you're using the same instance from multiple threads.

白芷 2024-11-25 20:02:19

我可以建议一些完全不同的东西吗,因为说实话,所有这些都有点像是掉进了兔子洞。

您应该使用一个设置了 dateFormatNSDateFormatter 并将 locale 强制设置为 en_US_POSIX 来接收日期(来自服务器/API) )。

然后,您应该为 UI 使用不同的 NSDateFormatter ,您将设置 timeStyle/dateStyle 属性 - 这样您就不会拥有您自己显式设置了 dateFormat,从而错误地假设将使用该格式。

这意味着 UI 是由用户偏好驱动的(上午/下午与 24 小时,以及根据用户选择正确格式化的日期字符串 - 来自 iOS 设置),而“进入”应用程序的日期始终会被正确“解析”为 < code>NSDate 供您使用。

May I suggest something totally different because to be honest all of this is somewhat running down a rabbit hole.

You should be using one NSDateFormatter with dateFormat set and locale forced to en_US_POSIX for receiving dates (from servers/APIs).

Then you should be using a different NSDateFormatter for the UI which you will set the timeStyle/dateStyle properties - this way you're not having an explicit dateFormat set by yourself, thus falsely assuming that format will be used.

This means UI is driven by user preferences (am/pm vs 24 hour, and date strings formatted correctly to user choice - from iOS settings), whereas dates that are "coming into" your app are always being "parsed" correctly to an NSDate for you to use.

衣神在巴黎 2024-11-25 20:02:19

这是 swift 版本中该问题的解决方案。在 swift 中,我们可以使用扩展而不是类别。
所以,在这里我创建了 DateFormatter 的扩展,并在 initWithSafeLocale 内部创建了扩展
返回具有相关区域设置的 DateFormatter,在我们的例子中是 en_US_POSIX,除此之外还提供了几种日期形成方法。

  • 斯威夫特4

    扩展 DateFormatter {
    
    私有静态 var dateFormatter = DateFormatter()
    
    class func initWithSafeLocale(withDateFormat dateFormat: String? = nil) ->;日期格式器 {
    
        日期格式器 = 日期格式器()
    
        var en_US_POSIX:区域设置? = 零;
    
        如果(en_US_POSIX == nil){
            en_US_POSIX = Locale.init(标识符:“en_US_POSIX”)
        }
        dateFormatter.locale = en_US_POSIX
    
        如果 dateFormat != nil, 让 format = dateFormat {
            dateFormatter.dateFormat = 格式
        }别的{
            dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        }
        返回日期格式化程序
    }
    
    // ------------------------------------------------ ------------------------------------------
    
    class func getDateFromString(string: String, fromFormat dateFormat: String? = nil) ->;日期? {
    
        如果 dateFormat != nil, 让 format = dateFormat {
            dateFormatter = DateFormatter.initWithSafeLocale(withDateFormat: 格式)
        }别的{
            dateFormatter = DateFormatter.initWithSafeLocale()
        }
        Guard let date = dateFormatter.date(from: string) else {
            返回零
        }
        返回日期
    }
    
    // ------------------------------------------------ ------------------------------------------
    
    class func getStringFromDate(date: Date, fromDateFormat dateFormat: String? = nil)->;细绳 {
    
        如果 dateFormat != nil, 让 format = dateFormat {
            dateFormatter = DateFormatter.initWithSafeLocale(withDateFormat: 格式)
        }别的{
            dateFormatter = DateFormatter.initWithSafeLocale()
        }
    
        让 string = dateFormatter.string(来自:日期)
    
        返回字符串
    } }
    
  • 使用说明:

    let date = DateFormatter.getDateFromString(string: "11-07-2001", fromFormat: "dd-MM-yyyy")
    print("自定义日期:\(日期)")
    让 dateFormatter = DateFormatter.initWithSafeLocale(withDateFormat: "yyyy-MM-dd HH:mm:ss")
    让 dt = DateFormatter.getDateFromString(字符串: "2001-05-05 12:34:56")
    print("基准日期 = \(dt)")
    dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    让 dateString = dateFormatter.string(来自: Date())
    print("日期字符串 = " + 日期字符串)
    让 date1 = dateFormatter.date(来自: "2001-05-05 12:34:56")
    print("日期1 = \(字符串(描述:日期1))")
    让 date2 = dateFormatter.date(来自: "2001-05-05 22:34:56")
    print("日期2 = \(字符串(描述:日期2))")
    让 date3 = dateFormatter.date(来自: "2001-05-05 12:34:56PM")
    print("date3 = \(String(描述:date3))")
    让 date4 = dateFormatter.date(来自: "2001-05-05 12:34:56 PM")
    print("date4 = \(String(描述:date4))")
    

Here is the solution for that problem in the swift version. In swift we can use extension instead of category.
So, Here I have created the extension for the DateFormatter and inside that initWithSafeLocale
returns the DateFormatter with the relevant Locale, Here in our case that is en_US_POSIX, Apart from that also provided couple of date formation methods.

  • Swift 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
    }   }
    
  • usage description:

    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))")
    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文