-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNSCalendarDate+ISO8601Unparsing.m
172 lines (144 loc) · 5.81 KB
/
NSCalendarDate+ISO8601Unparsing.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/*NSCalendarDate+ISO8601Unparsing.m
*
*Created by Peter Hosey on 2006-05-29.
*Copyright 2006 Peter Hosey. All rights reserved.
*/
#import <Foundation/Foundation.h>
#ifndef DEFAULT_TIME_SEPARATOR
# define DEFAULT_TIME_SEPARATOR ':'
#endif
unichar ISO8601UnparserDefaultTimeSeparatorCharacter = DEFAULT_TIME_SEPARATOR;
static BOOL is_leap_year(unsigned year) {
return \
((year % 4U) == 0U)
&& (((year % 100U) != 0U)
|| ((year % 400U) == 0U));
}
@interface NSString(ISO8601Unparsing)
//Replace all occurrences of ':' with timeSep.
- (NSString *)prepareDateFormatWithTimeSeparator:(unichar)timeSep;
@end
@implementation NSCalendarDate(ISO8601Unparsing)
#pragma mark Public methods
- (NSString *)ISO8601DateStringWithTime:(BOOL)includeTime timeSeparator:(unichar)timeSep {
NSString *dateFormat = [(includeTime ? @"%Y-%m-%dT%H:%M:%S" : @"%Y-%m-%d") prepareDateFormatWithTimeSeparator:timeSep];
NSDateFormatter *formatter = [[NSDateFormatter alloc] initWithDateFormat:dateFormat allowNaturalLanguage:NO];
NSString *str = [formatter stringForObjectValue:self];
[formatter release];
if(includeTime) {
int offset = [[self timeZone] secondsFromGMT];
offset /= 60; //bring down to minutes
if(offset == 0)
str = [str stringByAppendingString:@"Z"];
if(offset < 0)
str = [str stringByAppendingFormat:@"-%02d:%02d", -offset / 60, offset % 60];
else
str = [str stringByAppendingFormat:@"+%02d:%02d", offset / 60, offset % 60];
}
return str;
}
/*Adapted from:
* Algorithm for Converting Gregorian Dates to ISO 8601 Week Date
* Rick McCarty, 1999
* http://personal.ecu.edu/mccartyr/ISOwdALG.txt
*/
- (NSString *)ISO8601WeekDateStringWithTime:(BOOL)includeTime timeSeparator:(unichar)timeSep {
enum {
monday, tuesday, wednesday, thursday, friday, saturday, sunday
};
enum {
january = 1U, february, march,
april, may, june,
july, august, september,
october, november, december
};
unsigned year = [self yearOfCommonEra];
unsigned week = 0U;
unsigned dayOfWeek = ([self dayOfWeek] + 6U) % 7U;
unsigned dayOfYear = [self dayOfYear];
unsigned prevYear = year - 1U;
BOOL yearIsLeapYear = is_leap_year(year);
BOOL prevYearIsLeapYear = is_leap_year(prevYear);
unsigned YY = prevYear % 100U;
unsigned C = prevYear - YY;
unsigned G = YY + YY / 4U;
unsigned Jan1Weekday = (((((C / 100U) % 4U) * 5U) + G) % 7U);
unsigned weekday = ((dayOfYear + Jan1Weekday) - 1U) % 7U;
if((dayOfYear <= (7U - Jan1Weekday)) && (Jan1Weekday > thursday)) {
week = 52U + ((Jan1Weekday == friday) || ((Jan1Weekday == saturday) && prevYearIsLeapYear));
--year;
} else {
unsigned lengthOfYear = 365U + yearIsLeapYear;
if((lengthOfYear - dayOfYear) < (thursday - weekday)) {
++year;
week = 1U;
} else {
unsigned J = dayOfYear + (sunday - weekday) + Jan1Weekday;
week = J / 7U - (Jan1Weekday > thursday);
}
}
NSString *timeString;
if(includeTime) {
NSDateFormatter *formatter = [[NSDateFormatter alloc] initWithDateFormat:[@"T%H:%M:%S%z" prepareDateFormatWithTimeSeparator:timeSep] allowNaturalLanguage:NO];
timeString = [formatter stringForObjectValue:self];
[formatter release];
} else
timeString = @"";
return [NSString stringWithFormat:@"%u-W%02u-%02u%@", year, week, dayOfWeek + 1U, timeString];
}
- (NSString *)ISO8601OrdinalDateStringWithTime:(BOOL)includeTime timeSeparator:(unichar)timeSep {
NSString *timeString;
if(includeTime) {
NSDateFormatter *formatter = [[NSDateFormatter alloc] initWithDateFormat:[@"T%H:%M:%S%z" prepareDateFormatWithTimeSeparator:timeSep] allowNaturalLanguage:NO];
timeString = [formatter stringForObjectValue:self];
[formatter release];
} else
timeString = @"";
return [NSString stringWithFormat:@"%u-%03u%@", [self yearOfCommonEra], [self dayOfYear], timeString];
}
#pragma mark -
- (NSString *)ISO8601DateStringWithTime:(BOOL)includeTime {
return [self ISO8601DateStringWithTime:includeTime timeSeparator:ISO8601UnparserDefaultTimeSeparatorCharacter];
}
- (NSString *)ISO8601WeekDateStringWithTime:(BOOL)includeTime {
return [self ISO8601WeekDateStringWithTime:includeTime timeSeparator:ISO8601UnparserDefaultTimeSeparatorCharacter];
}
- (NSString *)ISO8601OrdinalDateStringWithTime:(BOOL)includeTime {
return [self ISO8601OrdinalDateStringWithTime:includeTime timeSeparator:ISO8601UnparserDefaultTimeSeparatorCharacter];
}
#pragma mark -
- (NSString *)ISO8601DateStringWithTimeSeparator:(unichar)timeSep {
return [self ISO8601DateStringWithTime:YES timeSeparator:timeSep];
}
- (NSString *)ISO8601WeekDateStringWithTimeSeparator:(unichar)timeSep {
return [self ISO8601WeekDateStringWithTime:YES timeSeparator:timeSep];
}
- (NSString *)ISO8601OrdinalDateStringWithTimeSeparator:(unichar)timeSep {
return [self ISO8601OrdinalDateStringWithTime:YES timeSeparator:timeSep];
}
#pragma mark -
- (NSString *)ISO8601DateString {
return [self ISO8601DateStringWithTime:YES timeSeparator:ISO8601UnparserDefaultTimeSeparatorCharacter];
}
- (NSString *)ISO8601WeekDateString {
return [self ISO8601WeekDateStringWithTime:YES timeSeparator:ISO8601UnparserDefaultTimeSeparatorCharacter];
}
- (NSString *)ISO8601OrdinalDateString {
return [self ISO8601OrdinalDateStringWithTime:YES timeSeparator:ISO8601UnparserDefaultTimeSeparatorCharacter];
}
@end
@implementation NSString(ISO8601Unparsing)
//Replace all occurrences of ':' with timeSep.
- (NSString *)prepareDateFormatWithTimeSeparator:(unichar)timeSep {
NSString *dateFormat = self;
if(timeSep != ':') {
NSMutableString *dateFormatMutable = [[dateFormat mutableCopy] autorelease];
[dateFormatMutable replaceOccurrencesOfString:@":"
withString:[NSString stringWithCharacters:&timeSep length:1U]
options:NSBackwardsSearch | NSLiteralSearch
range:(NSRange){ 0U, [dateFormat length] }];
dateFormat = dateFormatMutable;
}
return dateFormat;
}
@end