Data Formatting Guide

本文深入探讨了使用Objective-C中的NSDateFormatter类进行日期和时间的格式化与解析过程,包括基本方法、自定义格式、格式化风格以及本地化设置等关键概念。详细介绍了如何通过设置日期和时间样式、格式字符串以及本地化属性来呈现用户偏好化的日期显示,并提供了实例代码以展示实际应用。同时,还讨论了固定格式日期的解析方法及如何利用标准C库函数在特定格式下处理日期与时间。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Date Formatters

There are two basic methods you use to create a string representation of a date and to parse a string to get a date object using a date formatter—dateFromString: and stringFromDate:respectively. You can also use getObjectValue:forString:range:error: if you need more control over the range of a string you want to parse.

There are many attributes you can get and set on a date formatter. When you present information to the user, you should typically simply use the NSDateFormatter style constants to specify pre-defined sets of attributes that determine how a formatted date is displayed. If you need to generate a representation of a date in a precise format, however, you should use a format string.

If you need to parse a date string, the approach you take again depends on what you want to accomplish. If you want to parse input from the user, you should typically use the style constants so as to match their expectations. If you want to parse dates you get from a database or a web service, for example, you should use a format string.

In all cases, you should consider that formatters default to using the user’s locale (currentLocale) superimposed with the user’s preference settings. If you want to use the user’s locale but without their individual settings, you can get the locale id from the current user locale (localeIdentifier) and make a new "standard” locale with that, then set the standard locale as the formatter’s locale.

Use Formatter Styles to Present Dates and Times With the User’s Preferences

NSDateFormatter makes it easy for you to format a date using the settings a user configured in the International preferences panel in System Preferences. The NSDateFormatter style constants—NSDateFormatterNoStyleNSDateFormatterShortStyleNSDateFormatterMediumStyleNSDateFormatterLongStyle, and NSDateFormatterFullStyle—specify sets of attributes that determine how a date is displayed according to the user’s preferences.

You specify the style of the date and time components of a date formatter independently using setDateStyle: and setTimeStyle: respectively. Listing 1 illustrates how you can format a date using formatter styles. Notice the use of NSDateFormatterNoStyle to suppress the time component and yield a string containing just the date.

Listing 1  Formatting a date using formatter styles

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterNoStyle];
 
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:162000];
 
NSString *formattedDateString = [dateFormatter stringFromDate:date];
NSLog(@"formattedDateString: %@", formattedDateString);
// Output for locale en_US: "formattedDateString: Jan 2, 2001".

Use Format Strings to Specify Custom Formats

There are broadly speaking two situations in which you need to use custom formats:

  1. For fixed format strings, like Internet dates.

  2. For user-visible elements that don’t match any of the existing styles

Fixed Formats

To specify a custom fixed format for a date formatter, you use setDateFormat:. The format string uses the format patterns from the Unicode Technical Standard #35. The version of the standard varies with release of the operating system:

Although in principle a format string specifies a fixed format, by default NSDateFormater still takes the user’s preferences (including the locale setting) into account. You must consider the following points when using format strings:

  • NSDateFormatter treats the numbers in a string you parse as if they were in the user’s chosen calendar. For example, if the user selects the Buddhist calendar, parsing the year 2010yields an NSDate object in 1467 in the Gregorian calendar. (For more about different calendrical systems and how to use them, see Date and Time Programming Guide.)

  • In iOS, the user can override the default AM/PM versus 24-hour time setting. This may cause NSDateFormatter to rewrite the format string you set.

Note with the Unicode format string format, you should enclose literal text in the format string between apostrophes ('').

The following example illustrates using a format string to generate a string:

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd 'at' HH:mm"];
 
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:162000];
 
NSString *formattedDateString = [dateFormatter stringFromDate:date];
NSLog(@"formattedDateString: %@", formattedDateString);
// For US English, the output may be:
// formattedDateString: 2001-01-02 at 13:00

There are two things to note about this example:

  1. It uses yyyy to specify the year component. A common mistake is to use YYYYyyyy specifies the calendar year whereas YYYY specifies the year (of “Week of Year”), used in the ISO year-week calendar. In most cases, yyyy and YYYY yield the same number, however they may be different. Typically you should use the calendar year.

  2. The representation of the time may be 13:00. In iOS, however, if the user has switched 24-Hour Time to Off, the time may be 1:00 pm.

Custom Formats for User-Visible Dates

To display a date that contains a specific set of elements, you use dateFormatFromTemplate:options:locale:]. The method generates a format string with the date components you want to use, but with the correct punctuation and order appropriate for the user (that is, customized for the user’s locale and preferences). You then use the format string to create a formatter.

For example, to create a formatter to display today’s day name, day, and month using the current locale, you would write:

NSString *formatString = [NSDateFormatter dateFormatFromTemplate:@"EdMMM" options:0
                                          locale:[NSLocale currentLocale]];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:formatString];
 
NSString *todayString = [dateFormatter stringFromDate:[NSDate date]];
NSLog(@"todayString: %@", todayString);

To understand the need for this, consider a situation where you want to display the day name, day, and month. You cannot create this representation of a date using formatter styles (there is no style that omits the year). Neither, though, can you easily and consistently create the representation correctly using format strings. Although at first glance it may seem straightforward, there’s a complication: a user from the United States would typically expect dates in the form, “Mon, Jan 3”, whereas a user from Great Britain would typically expect dates in the form “Mon 31 Jan”.

The following example illustrates the point:

NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
NSString *usFormatString = [NSDateFormatter dateFormatFromTemplate:@"EdMMM" options:0 locale:usLocale];
NSLog(@"usFormatterString: %@", usFormatString);
// Output: usFormatterString: EEE, MMM d.
 
NSLocale *gbLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_GB"];
NSString *gbFormatString = [NSDateFormatter dateFormatFromTemplate:@"EdMMM" options:0 locale:gbLocale];
NSLog(@"gbFormatterString: %@", gbFormatString);
// Output: gbFormatterString: EEE d MMM.

Parsing Date Strings

In addition to the methods inherited from NSFormatter (such as getObjectValue:forString:errorDescription:), NSDateFormatter adds dateFromString: andgetObjectValue:forString:range:error:. These methods make it easier for you to use an NSDateFormatter object directly in code, and make it easier to format dates into strings more complex and more convenient ways than NSString formatting allows.

The getObjectValue:forString:range:error: method allows you to specify a subrange of the string to be parsed, and it returns the range of the string that was actually parsed (in the case of failure, it indicates where the failure occurred). It also returns an NSError object that can contain richer information than the failure string returned by thegetObjectValue:forString:errorDescription: method inherited from NSFormatter.

If you're working with fixed-format dates, you should first set the locale of the date formatter to something appropriate for your fixed format. In most cases the best locale to choose isen_US_POSIX, a locale that's specifically designed to yield US English results regardless of both user and system preferences. en_US_POSIX is also invariant in time (if the US, at some point in the future, changes the way it formats dates, en_US will change to reflect the new behavior, but en_US_POSIX will not), and between platforms (en_US_POSIX works the same on iPhone OS as it does on OS X, and as it does on other platforms).

Once you’ve set en_US_POSIX as the locale of the date formatter, you can then set the date format string and the date formatter will behave consistently for all users.

Listing 2 shows how to use NSDateFormatter for both of the roles described above. First it creates a en_US_POSIX date formatter to parse the incoming RFC 3339 date string, using a fixed date format string and UTC as the time zone. Next, it creates a standard date formatter to render the date as a string to display to the user.

Listing 2  Parsing an RFC 3339 date-time

- (NSString *)userVisibleDateTimeStringForRFC3339DateTimeString:(NSString *)rfc3339DateTimeString {
    /*
      Returns a user-visible date time string that corresponds to the specified
      RFC 3339 date time string. Note that this does not handle all possible
      RFC 3339 date time strings, just one of the most common styles.
     */
 
    NSDateFormatter *rfc3339DateFormatter = [[NSDateFormatter alloc] init];
    NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
 
    [rfc3339DateFormatter setLocale:enUSPOSIXLocale];
    [rfc3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
    [rfc3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
 
    // Convert the RFC 3339 date time string to an NSDate.
    NSDate *date = [rfc3339DateFormatter dateFromString:rfc3339DateTimeString];
 
    NSString *userVisibleDateTimeString;
    if (date != nil) {
        // Convert the date object to a user-visible date string.
        NSDateFormatter *userVisibleDateFormatter = [[NSDateFormatter alloc] init];
        assert(userVisibleDateFormatter != nil);
 
        [userVisibleDateFormatter setDateStyle:NSDateFormatterShortStyle];
        [userVisibleDateFormatter setTimeStyle:NSDateFormatterShortStyle];
 
        userVisibleDateTimeString = [userVisibleDateFormatter stringFromDate:date];
    }
    return userVisibleDateTimeString;
}

Cache Formatters for Efficiency

Creating a date formatter is not a cheap operation. If you are likely to use a formatter frequently, it is typically more efficient to cache a single instance than to create and dispose of multiple instances. One approach is to use a static variable.

Listing 3 re-implements the method shown in Listing 2 to hold on to the date formatters for subsequent reuse.

Listing 3  Parsing an RFC 3339 date-time using a cached formatter

static NSDateFormatter *sUserVisibleDateFormatter = nil;
 
- (NSString *)userVisibleDateTimeStringForRFC3339DateTimeString:(NSString *)rfc3339DateTimeString {
    /*
      Returns a user-visible date time string that corresponds to the specified
      RFC 3339 date time string. Note that this does not handle all possible
      RFC 3339 date time strings, just one of the most common styles.
     */
 
    // If the date formatters aren't already set up, create them and cache them for reuse.
    static NSDateFormatter *sRFC3339DateFormatter = nil;
    if (sRFC3339DateFormatter == nil) {
        sRFC3339DateFormatter = [[NSDateFormatter alloc] init];
        NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
 
        [sRFC3339DateFormatter setLocale:enUSPOSIXLocale];
        [sRFC3339DateFormatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"];
        [sRFC3339DateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
    }
 
    // Convert the RFC 3339 date time string to an NSDate.
    NSDate *date = [rfc3339DateFormatter dateFromString:rfc3339DateTimeString];
 
    NSString *userVisibleDateTimeString;
    if (date != nil) {
        if (sUserVisibleDateFormatter == nil) {
            sUserVisibleDateFormatter = [[NSDateFormatter alloc] init];
            [sUserVisibleDateFormatter setDateStyle:NSDateFormatterShortStyle];
            [sUserVisibleDateFormatter setTimeStyle:NSDateFormatterShortStyle];
        }
        // Convert the date object to a user-visible date string.
        userVisibleDateTimeString = [sUserVisibleDateFormatter stringFromDate:date];
    }
    return userVisibleDateTimeString;
}

If you cache date formatters (or any other objects that depend on the user’s current locale), you should subscribe to the NSCurrentLocaleDidChangeNotification notification and update your cached objects when the current locale changes. The code in Listing 3 defines sUserVisibleDateFormatter outside of the method so that other code, not shown, can update it as necessary. In contrast, sRFC3339DateFormatter is defined inside the method because, by design, it is not dependent on the user’s locale settings.

Note: In theory you could use an auto-updating locale (autoupdatingCurrentLocale) to create a locale that automatically accounts for changes in the user’s locale settings. In practice this currently does not work with date formatters.

Consider Unix Functions for Fixed-Format, Unlocalized Dates

For date and times in a fixed, unlocalized format, that are always guaranteed to use the same calendar, it may sometimes be easier and more efficient to use the standard C library functionsstrptime_l and strftime_l.

Be aware that the C library also has the idea of a current locale. To guarantee a fixed date format, you should pass NULL as the loc parameter of these routines. This causes them to use the POSIX locale (also known as the C locale), which is equivalent to Cocoa's en_US_POSIX locale, as illustrated in this example.

struct tm  sometime;
const char *formatString = "%Y-%m-%d %H:%M:%S %z";
(void) strptime_l("2005-07-01 12:00:00 -0700", formatString, &sometime, NULL);
NSLog(@"NSDate is %@", [NSDate dateWithTimeIntervalSince1970: mktime(&sometime)]);
// Output: NSDate is 2005-07-01 12:00:00 -0700
<think>我们正在处理用户关于Ultralytics YOLO训练时出现的警告:“No labels found in C:\yyhxw\image\val.cache”。这个警告通常表明在验证集(val)的标签文件缺失或未被正确识别。需要指导用户正确格式化YOLO数据集。 关键点: 1. YOLO格式要求每个图像对应一个同名的.txt标签文件,内容为:`class_id center_x center_y width height`(归一化坐标)。 2. 数据集目录结构应合理,通常包含images(存放图像)和labels(存放标签)两个子目录,且训练集和验证集分别放在各自的子目录下。 3. 确保数据集路径正确,并且在训练时通过.yaml配置文件指定。 步骤: 1. 检查标签文件是否存在:确认在验证集图像的相同位置(或对应的labels目录下)有同名的.txt标签文件。 2. 检查标签文件内容:确保标签文件格式正确,没有错误的数据(如超出[0,1]的坐标)。 3. 检查数据集配置文件(.yaml):确保配置文件中验证集的路径和标签路径正确。 此外,警告中提到了.cache文件,这是YOLO在训练前生成的数据缓存,如果标签缺失,则缓存文件会指出问题。 具体解决方案: - 重新检查数据集结构,确保符合YOLO格式。 - 运行一个简单的脚本来验证标签文件的存在和格式。 下面我们将详细说明如何正确格式化数据集,并提供一个示例的目录结构和数据集配置文件。 同时,生成相关问题以帮助用户深入理解。</think>### Ultralytics YOLO 标签缺失警告解决方案 当出现 `WARNING No labels found in C:\yyhxw\image\val.cache` 时,表明 YOLO 在验证集路径中未检测到有效的标签文件。以下是系统化的解决步骤: #### 1. **检查数据集结构** YOLO 格式要求数据集目录必须满足以下结构: ``` 数据集根目录/ ├── images/ │ ├── train/ # 训练集图像 │ └── val/ # 验证集图像 └── labels/ ├── train/ # 训练集标签(与图像同名) └── val/ # 验证集标签(与图像同名) ``` - 验证 `C:\yyhxw\image\` 是否包含 `images/val/` 和 `labels/val/` 子目录 - 确认标签文件与图像文件 **同名**(如 `image001.jpg` 对应 `image001.txt`) #### 2. **验证标签文件格式** 每个 `.txt` 标签文件必须是 YOLO 格式: ```plaintext <class_id> <center_x> <center_y> <width> <height> ``` - **坐标要求**:所有值必须是归一化的浮点数(范围 $[0,1]$) - **示例**:`0 0.45 0.67 0.32 0.19` 表示: - 类别 0 的物体 - 中心点 $(x,y)$ 在 $(0.45 \times \text{img\_width}, 0.67 \times \text{img\_height})$ - 宽高分别为原图的 $0.32$ 和 $0.19$ 倍 #### 3. **修正数据集配置文件** 在数据集 YAML 文件(如 `data.yaml`)中确保路径正确: ```yaml train: C:/yyhxw/image/images/train # 正斜杠避免转义 val: C:/yyhxw/image/images/val nc: 80 # 类别数 names: ["person", "car", ...] # 类别名称 ``` #### 4. **重建缓存文件** 删除现有缓存文件后重新训练: ```bash rm C:\yyhxw\image\val.cache # 删除旧缓存 python train.py --data data.yaml --cache disk # 重新生成 ``` #### 5. **验证工具** 使用 Ultralytics 的自动验证功能: ```python from ultralytics import YOLO model = YOLO('yolov8n.yaml') model.val(data='data.yaml') # 主动触发验证流程 ``` 系统将输出缺失文件的具体路径[^1]。 > **关键检查点**:若图像无对应物体,仍需创建**空标签文件**(0 字节的 `.txt` 文件),否则会被视为缺失[^2]。 ### 相关问题 1. 如何将 COCO 格式数据集转换为 YOLO 格式? 2. 训练中出现 `Labels class imbalance` 警告该如何处理? 3. YOLOv8 支持哪些数据增强方法?如何配置? 4. 如何解释 YOLO 标签文件中的归一化坐标计算原理? [^1]: Ultralytics YOLOv8 Documentation, Dataset Management [^2]: YOLOv5 Dataset Guide, Empty Label Handling
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值