API  0.9.7
 All Classes Files Functions Variables Macros Groups Pages
CPDate.j
Go to the documentation of this file.
1 /*
2  * CPDate.j
3  * Foundation
4  *
5  * Created by Thomas Robinson.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 var CPDateReferenceDate = new Date(Date.UTC(2001, 0, 1, 0, 0, 0, 0));
25 
31 @implementation CPDate : CPObject
32 {
33  id __doxygen__;
34 }
35 
36 + (id)alloc
37 {
38  var result = new Date;
39  result.isa = [self class];
40  return result;
41 }
42 
43 + (id)date
44 {
45  return [[self alloc] init];
46 }
47 
48 + (id)dateWithTimeIntervalSinceNow:(CPTimeInterval)seconds
49 {
50  return [[CPDate alloc] initWithTimeIntervalSinceNow:seconds];
51 }
52 
53 + (id)dateWithTimeIntervalSince1970:(CPTimeInterval)seconds
54 {
55  return [[CPDate alloc] initWithTimeIntervalSince1970:seconds];
56 }
57 
58 + (id)dateWithTimeIntervalSinceReferenceDate:(CPTimeInterval)seconds
59 {
61 }
62 
63 + (id)distantPast
64 {
65  return [CPDate dateWithTimeIntervalSinceReferenceDate:-63113817600.0];
66 }
67 
68 + (id)distantFuture
69 {
70  return [CPDate dateWithTimeIntervalSinceReferenceDate:63113990400.0];
71 }
72 
73 - (id)initWithTimeIntervalSinceNow:(CPTimeInterval)seconds
74 {
75  self = new Date((new Date()).getTime() + seconds * 1000);
76  return self;
77 }
78 
79 - (id)initWithTimeIntervalSince1970:(CPTimeInterval)seconds
80 {
81  self = new Date(seconds * 1000);
82  return self;
83 }
84 
85 - (id)initWithTimeIntervalSinceReferenceDate:(CPTimeInterval)seconds
86 {
87  self = [self initWithTimeInterval:seconds sinceDate:CPDateReferenceDate];
88  return self;
89 }
90 
91 - (id)initWithTimeInterval:(CPTimeInterval)seconds sinceDate:(CPDate)refDate
92 {
93  self = new Date(refDate.getTime() + seconds * 1000);
94  return self;
95 }
96 
102 - (id)initWithString:(CPString)description
103 {
104  var format = /(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}) ([-+])(\d{2})(\d{2})/,
105  d = description.match(new RegExp(format));
106 
107  if (!d || d.length != 10)
108  [CPException raise:CPInvalidArgumentException
109  reason:"initWithString: the string must be in YYYY-MM-DD HH:MM:SS ±HHMM format"];
110 
111  var date = new Date(d[1], d[2] - 1, d[3]),
112  timeZoneOffset = (Number(d[8]) * 60 + Number(d[9])) * (d[7] === '-' ? 1 : -1);
113 
114  date.setHours(d[4]);
115  date.setMinutes(d[5]);
116  date.setSeconds(d[6]);
117 
118  self = new Date(date.getTime() + (timeZoneOffset - date.getTimezoneOffset()) * 60 * 1000);
119  return self;
120 }
121 
122 - (CPTimeInterval)timeIntervalSinceDate:(CPDate)anotherDate
123 {
124  return (self.getTime() - anotherDate.getTime()) / 1000.0;
125 }
126 
127 - (CPTimeInterval)timeIntervalSinceNow
128 {
129  return [self timeIntervalSinceDate:[CPDate date]];
130 }
131 
132 - (CPTimeInterval)timeIntervalSince1970
133 {
134  return self.getTime() / 1000.0;
135 }
136 
137 - (CPTimeInterval)timeIntervalSinceReferenceDate
138 {
139  return (self.getTime() - CPDateReferenceDate.getTime()) / 1000.0;
140 }
141 
142 + (CPTimeInterval)timeIntervalSinceReferenceDate
143 {
145 }
146 
147 - (BOOL)isEqual:(CPDate)aDate
148 {
149  if (self === aDate)
150  return YES;
151 
152  if (!aDate || ![aDate isKindOfClass:[CPDate class]])
153  return NO;
154 
155  return [self isEqualToDate:aDate];
156 }
157 
158 - (BOOL)isEqualToDate:(CPDate)aDate
159 {
160  if (!aDate)
161  return NO;
162 
163  return !(self < aDate || self > aDate);
164 }
165 
166 - (CPComparisonResult)compare:(CPDate)anotherDate
167 {
168  return (self > anotherDate) ? CPOrderedDescending : ((self < anotherDate) ? CPOrderedAscending : CPOrderedSame);
169 }
170 
171 - (CPDate)earlierDate:(CPDate)anotherDate
172 {
173  return (self < anotherDate) ? self : anotherDate;
174 }
175 
176 - (CPDate)laterDate:(CPDate)anotherDate
177 {
178  return (self > anotherDate) ? self : anotherDate;
179 }
180 
184 + (CPString)timezoneOffsetString:(int)timezoneOffset
185 {
186  var offset = -timezoneOffset,
187  positive = offset >= 0,
188  hours = positive ? FLOOR(offset / 60) : CEIL(offset / 60),
189  minutes = offset - hours * 60;
190  return [CPString stringWithFormat:@"%s%02d%02d", positive ? "+" : "-", ABS(hours), ABS(minutes)];
191 }
192 
197 - (CPString)description
198 {
199  return [CPString stringWithFormat:@"%04d-%02d-%02d %02d:%02d:%02d %s", self.getFullYear(), self.getMonth() + 1, self.getDate(), self.getHours(), self.getMinutes(), self.getSeconds(), [CPDate timezoneOffsetString:self.getTimezoneOffset()]];
200 }
201 
202 - (id)copy
203 {
204  return new Date(self.getTime());
205 }
206 
207 @end
208 
209 var CPDateTimeKey = @"CPDateTimeKey";
210 
211 @implementation CPDate (CPCoding)
212 
213 - (id)initWithCoder:(CPCoder)aCoder
214 {
215  if (self)
216  {
217  self.setTime([aCoder decodeIntForKey:CPDateTimeKey]);
218  }
219 
220  return self;
221 }
222 
223 - (void)encodeWithCoder:(CPCoder)aCoder
224 {
225  [aCoder encodeInt:self.getTime() forKey:CPDateTimeKey];
226 }
227 
228 @end
229 
230 // Based on 'Universal JavaScript Date.parse for ISO 8601' available at https://github.com/csnover/js-iso8601.
231 var numericKeys = [1, 4, 5, 6, 7, 10, 11];
232 
233 Date.parseISO8601 = function (date)
234 {
235  var timestamp,
236  struct,
237  minutesOffset = 0;
238 
239  // First, check for native parsing.
240  timestamp = Date.parse(date);
241 
242  if (isNaN(timestamp) && (struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date)))
243  {
244  // avoid NaN timestamps caused by "undefined" values being passed to Date.UTC
245  for (var i = 0, k; (k = numericKeys[i]); ++i)
246  struct[k] = +struct[k] || 0;
247 
248  // allow undefined days and months
249  struct[2] = (+struct[2] || 1) - 1;
250  struct[3] = +struct[3] || 1;
251 
252  if (struct[8] !== 'Z' && struct[9] !== undefined)
253  {
254  minutesOffset = struct[10] * 60 + struct[11];
255 
256  if (struct[9] === '+')
257  minutesOffset = 0 - minutesOffset;
258  }
259 
260  return Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]);
261  }
262 
263  return timestamp;
264 };
265 
266 Date.prototype.isa = CPDate;