#include "LCDateTools.h" #include "GNUstep.h" /** * Provides support for converting dates to strings and vice-versa. * The strings are structured so that lexicographic sorting orders * them by date, which makes them suitable for use as field values * and search terms. * *

This class also helps you to limit the resolution of your dates. Do not * save dates with a finer resolution than you really need, as then * RangeQuery and PrefixQuery will require more memory and become slower. * *

Compared to {@link DateField} the strings generated by the methods * in this class take slightly more space, unless your selected resolution * is set to Resolution.DAY or lower. */ @implementation NSString (LuceneKit_Document_Date) /** convert a date to string in this format depending on resolution: * "%Y%m%d%H%M%S%F" (yyyyMMddHHmmssSSS) in GMT. */ + (id) stringWithCalendarDate: (NSCalendarDate *) date resolution: (LCResolution) res; { return [NSString stringWithTimeIntervalSince1970: [date timeIntervalSince1970] resolution: res]; } /** convert a millisecond to string in this format depending on resolution: * "%Y%m%d%H%M%S%F" (yyyyMMddHHmmssSSS) in GMT. */ + (id) stringWithTimeIntervalSince1970: (NSTimeInterval) time resolution: (LCResolution) resolution; { NSTimeInterval interval; NSCalendarDate *date; NSString *pattern; date = [NSCalendarDate dateWithTimeIntervalSince1970: time]; interval = [date timeIntervalSince1970WithResolution: resolution]; date = [NSCalendarDate dateWithTimeIntervalSince1970: interval]; /* Make sure date is in GMT format */ [date setTimeZone: [NSTimeZone timeZoneWithAbbreviation: @"GMT"]]; if (resolution == LCResolution_YEAR) { pattern = @"%Y"; } else if (resolution == LCResolution_MONTH) { pattern = @"%Y%m"; } else if (resolution == LCResolution_DAY) { pattern = @"%Y%m%d"; } else if (resolution == LCResolution_HOUR) { pattern = @"%Y%m%d%H"; } else if (resolution == LCResolution_MINUTE) { pattern = @"%Y%m%d%H%M"; } else if (resolution == LCResolution_SECOND) { pattern = @"%Y%m%d%H%M%S"; } else if (resolution == LCResolution_MILLISECOND) { pattern = @"%Y%m%d%H%M%S%F"; } else { return nil; // Unknown Resolution } return [date descriptionWithCalendarFormat: pattern]; } /** * Converts a string produced by timeToString or * dateToString back to a time, represented as the * number of milliseconds since January 1, 1970, 00:00:00 GMT. * * @param dateString the date string to be converted * @return the number of milliseconds since January 1, 1970, 00:00:00 GMT * @throws ParseException if dateString is not in the * expected format */ - (NSTimeInterval) timeIntervalSince1970 { return [[self calendarDate] timeIntervalSince1970]; } /* Convert a string in this format to date: * "%Y%m%d%H%M%S%F" (yyyyMMddHHmmssSSS) in GMT. */ - (NSCalendarDate *) calendarDate; { NSString *pattern = nil; int len = [self length]; switch(len) { case 4: pattern = @"%Y%Z"; break; case 6: pattern = @"%Y%m%Z"; break; case 8: pattern = @"%Y%m%d%Z"; break; case 10: pattern = @"%Y%m%d%H%Z"; break; case 12: pattern = @"%Y%m%d%H%M%Z"; break; case 14: pattern = @"%Y%m%d%H%M%S%Z"; break; case 17: pattern = @"%Y%m%d%H%M%S%F%Z"; break; default: return nil; // Not Valid Date String } /* make sure the string is in GMT format */ return [NSCalendarDate dateWithString: [self stringByAppendingString:@"GMT"] calendarFormat: pattern]; } @end @implementation NSCalendarDate (LuceneKit_Document_Date) /** * Limit a date's resolution. For example, the date 1095767411000 * (which represents 2004-09-21 13:50:11) will be changed to * 1093989600000 (2004-09-01 00:00:00) when using * Resolution.MONTH. * * @param resolution The desired resolution of the date to be returned * @return the date with all values more precise than resolution * set to 0 or 1, expressed as milliseconds since January 1, 1970, 00:00:00 GMT */ - (NSTimeInterval) timeIntervalSince1970WithResolution: (LCResolution) res { return [[self dateWithResolution: res] timeIntervalSince1970]; } /** * Limit a date's resolution. For example, the date 2004-09-21 13:50:11 * will be changed to 2004-09-01 00:00:00 when using * Resolution.MONTH. * * @param resolution The desired resolution of the date to be returned * @return the date with all values more precise than resolution * set to 0 or 1 */ - (NSCalendarDate *) dateWithResolution: (LCResolution) res { switch(res) { case LCResolution_YEAR: return [NSCalendarDate dateWithYear: [self yearOfCommonEra] month: 1 day: 1 hour: 0 minute: 0 second: 0 timeZone: [self timeZone]]; case LCResolution_MONTH: return [NSCalendarDate dateWithYear: [self yearOfCommonEra] month: [self monthOfYear] day: 1 hour: 0 minute: 0 second: 0 timeZone: [self timeZone]]; case LCResolution_DAY: return [NSCalendarDate dateWithYear: [self yearOfCommonEra] month: [self monthOfYear] day: [self dayOfMonth] hour: 0 minute: 0 second: 0 timeZone: [self timeZone]]; case LCResolution_HOUR: return [NSCalendarDate dateWithYear: [self yearOfCommonEra] month: [self monthOfYear] day: [self dayOfMonth] hour: [self hourOfDay] minute: 0 second: 0 timeZone: [self timeZone]]; case LCResolution_MINUTE: return [NSCalendarDate dateWithYear: [self yearOfCommonEra] month: [self monthOfYear] day: [self dayOfMonth] hour: [self hourOfDay] minute: [self minuteOfHour] second: 0 timeZone: [self timeZone]]; case LCResolution_SECOND: return [NSCalendarDate dateWithYear: [self yearOfCommonEra] month: [self monthOfYear] day: [self dayOfMonth] hour: [self hourOfDay] minute: [self minuteOfHour] second: [self secondOfMinute] timeZone: [self timeZone]]; case LCResolution_MILLISECOND: return AUTORELEASE([self copy]); // don't cut off anything default: return nil; // Error; } } @end