2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
22 #include "NSCalendarDate+misc.h"
25 #define NUMBER_OF_SECONDS_IN_DAY (24 * 60 * 60)
27 @implementation NSCalendarDate(misc)
29 + (NSCalendarDate *)mondayOfWeek:(int)_weekNumber inYear:(int)_year
30 timeZone:(NSTimeZone *)_tz
32 NSCalendarDate *janFirst;
34 janFirst = [NSCalendarDate dateWithYear:_year month:1 day:1
35 hour:0 minute:0 second:0
37 return [janFirst mondayOfWeek:_weekNumber];
40 - (NSCalendarDate *)mondayOfWeek:(int)_weekNumber {
41 NSCalendarDate *mondayOfWeek;
44 mondayOfWeek = [self firstMondayAndLastWeekInYear:&lastWeek];
49 return [mondayOfWeek dateByAddingYears:0
51 days:(7 * (_weekNumber - 1))];
54 + (NSArray *)mondaysOfYear:(int)_year timeZone:(NSTimeZone *)_tz {
55 NSCalendarDate *janFirst;
57 janFirst = [NSCalendarDate dateWithYear:_year month:1 day:1
58 hour:0 minute:0 second:0
60 return [janFirst mondaysOfYear];
63 - (NSArray *)mondaysOfYear {
65 NSMutableArray *mondays;
66 NSCalendarDate *mondayOfWeek;
70 mondayOfWeek = [self firstMondayAndLastWeekInYear:&lastWeek];
71 mondays = [[NSMutableArray alloc] initWithCapacity:55];
73 for (i = 0; i < lastWeek; i++) {
74 #if 0 // hh: can someone explain this ?!
77 [mondayOfWeek addYear:0 month:0 day:7 hour:0 minute:0 second:0];
79 mondayOfWeek = [[mondayOfWeek copy] autorelease];
80 [mondays addObject:mondayOfWeek];
83 tmp = [mondayOfWeek dateByAddingYears:0 months:0 days:(i * 7)];
84 [mondays addObject:tmp];
88 array = [mondays copy];
90 return [array autorelease];
93 - (NSCalendarDate *)firstMondayAndLastWeekInYear:(short *)_lastWeek {
97 NSCalendarDate *janFirst;
98 NSCalendarDate *silvester;
99 NSCalendarDate *mondayOfWeek;
101 tz = [self timeZone];
102 currentYear = [self yearOfCommonEra];
104 if ([self weekOfYear] == 53) {
105 NSCalendarDate *nextJanFirst = nil;
107 nextJanFirst = [NSCalendarDate dateWithYear:(currentYear + 1)
109 hour:0 minute:0 second:0
112 if ([nextJanFirst weekOfYear] == 1)
116 janFirst = [NSCalendarDate dateWithYear:currentYear
118 hour:0 minute:0 second:0
120 silvester = [NSCalendarDate dateWithYear:currentYear
122 hour:23 minute:59 second:59
125 lastWeek = [silvester weekOfYear];
127 if (lastWeek == 53) {
128 NSCalendarDate *nextJanFirst = nil;
130 nextJanFirst = [NSCalendarDate dateWithYear:currentYear+1
132 hour:0 minute:0 second:0
135 if ([nextJanFirst weekOfYear] == 1)
139 if ([janFirst weekOfYear] != 1) {
140 mondayOfWeek = [janFirst mondayOfWeek];
141 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
143 [mondayOfWeek dateByAddingYears:0 months:0 days:7
144 hours:0 minutes:0 seconds:0];
147 [mondayOfWeek addYear:0 month:0 day:7 hour:0 minute:0 second:0];
151 mondayOfWeek = [janFirst mondayOfWeek];
154 if (_lastWeek) *_lastWeek = lastWeek;
158 - (NSCalendarDate *)firstDayOfMonth {
160 NSCalendarDate *first;
164 dayOfMonth = [self dayOfMonth];
165 tz = [self timeZone];
167 tv = (1 - dayOfMonth) * NUMBER_OF_SECONDS_IN_DAY;
168 tv = [self timeIntervalSince1970] + tv;
169 first = [NSCalendarDate dateWithTimeIntervalSince1970:tv];
170 [first setTimeZone:tz];
174 - (NSCalendarDate *)lastDayOfMonth {
175 int offset = [self numberOfDaysInMonth] - [self dayOfMonth];
176 return [self dateByAddingYears:0 months:0 days:offset];
179 - (int)numberOfDaysInMonth {
180 static int leapYearMonths[12] = {31,29,31,30,31,30,31,31,30,31,30,31};
181 static int nonLeapYearMonths[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
182 int *numberOfDaysInMonth = [self isInLeapYear] ? leapYearMonths :
184 return numberOfDaysInMonth[[self monthOfYear] - 1];
189 unsigned year = [self yearOfCommonEra];
190 return (((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0);
199 dayOfMonth = [self dayOfMonth]; /* 1-31 */
203 /* could be done smarter (by calculating on dayOfWeek) */
204 weekOfYear = [self weekOfYear];
205 firstWeekOfYear = [[self firstDayOfMonth] weekOfYear];
207 return (weekOfYear - firstWeekOfYear + 1);
211 static int whereToStart[] = { 6, 7, 8, 9, 10, 4, 5 };
212 NSCalendarDate *janFirst;
213 int year, day, weekOfYear;
216 year = [self yearOfCommonEra];
217 day = [self dayOfYear] - 1;
219 tz = [self timeZone];
221 janFirst = [NSCalendarDate dateWithYear:year month:1 day:1
222 hour:0 minute:0 second:0
225 weekOfYear = (day + whereToStart[[janFirst dayOfWeek]]) / 7;
227 if (weekOfYear == 0) {
228 NSCalendarDate *silvesterLastYear;
230 silvesterLastYear = [NSCalendarDate dateWithYear:(year - 1)
232 hour:0 minute:0 second:0
234 return [silvesterLastYear weekOfYear];
238 if (weekOfYear == 53) {
239 NSCalendarDate *nextJanFirst = nil;
240 int janYear = year + 1;
244 nextJanFirst = [NSCalendarDate dateWithYear:janYear
246 hour:0 minute:0 second:0
247 timeZone:[self timeZone]];
249 janDay = [nextJanFirst dayOfYear];
250 week = (janDay + whereToStart[[nextJanFirst dayOfWeek]]) / 7;
259 - (short)numberOfWeeksInYear {
260 NSCalendarDate *silvester;
261 NSCalendarDate *dayOfLastWeek;
265 currentYear = [self yearOfCommonEra];
266 tz = [self timeZone];
268 silvester = [NSCalendarDate dateWithYear:currentYear
270 hour:23 minute:59 second:59
272 dayOfLastWeek = [silvester dateByAddingYears:0 months:0 days:-3 hours:0
273 minutes:0 seconds:0];
275 return [dayOfLastWeek weekOfYear];
278 - (NSCalendarDate *)mondayOfWeek {
280 NSCalendarDate *monday;
284 dayOfWeek = [self dayOfWeek];
285 tz = [self timeZone];
287 if (dayOfWeek == 0) dayOfWeek = 7; // readjust Sunday
289 tv = (1 - dayOfWeek) * NUMBER_OF_SECONDS_IN_DAY;
290 tv = [self timeIntervalSince1970] + tv;
291 monday = [NSCalendarDate dateWithTimeIntervalSince1970:tv];
292 [monday setTimeZone:tz];
296 - (NSCalendarDate *)beginOfDay {
299 tz = [self timeZone];
301 return [NSCalendarDate dateWithYear:[self yearOfCommonEra]
302 month: [self monthOfYear]
303 day: [self dayOfMonth]
304 hour:0 minute:0 second:0
308 - (NSCalendarDate *)endOfDay {
311 tz = [self timeZone];
313 return [NSCalendarDate dateWithYear:[self yearOfCommonEra]
314 month: [self monthOfYear]
315 day: [self dayOfMonth]
316 hour:23 minute:59 second:59
320 - (BOOL)isDateOnSameDay:(NSCalendarDate *)_date {
321 if ([self dayOfYear] != [_date dayOfYear]) return NO;
322 if ([self yearOfCommonEra] != [_date yearOfCommonEra]) return NO;
325 - (BOOL)isDateInSameWeek:(NSCalendarDate *)_date {
326 if ([self weekOfYear] != [_date weekOfYear]) return NO;
327 if ([self yearOfCommonEra] != [_date yearOfCommonEra]) return NO;
335 d = [[NSCalendarDate alloc] init];
336 [d setTimeZone:[self timeZone]];
337 result = [self isDateOnSameDay:d];
343 return [self hourOfDay] >= 12 ? NO : YES;
345 - (BOOL)isAfternoon {
346 return [self hourOfDay] >= 12 ? YES : NO;
349 - (NSCalendarDate *)yesterday {
350 return [self dateByAddingYears:0 months:0 days:-1
351 hours:0 minutes:0 seconds:0];
353 - (NSCalendarDate *)tomorrow {
354 return [self dateByAddingYears:0 months:0 days:1
355 hours:0 minutes:0 seconds:0];
358 - (NSCalendarDate *)lastYear {
359 return [self dateByAddingYears:-1 months:0 days:0
360 hours:0 minutes:0 seconds:0];
362 - (NSCalendarDate *)nextYear {
363 return [self dateByAddingYears:1 months:0 days:0
364 hours:0 minutes:0 seconds:0];
367 - (NSCalendarDate *)hour:(int)_hour minute:(int)_minute second:(int)_second {
370 tz = [self timeZone];
372 return [NSCalendarDate dateWithYear:[self yearOfCommonEra]
373 month: [self monthOfYear]
374 day: [self dayOfMonth]
375 hour:_hour minute:_minute second:_second
378 - (NSCalendarDate *)hour:(int)_hour minute:(int)_minute {
379 return [self hour:_hour minute:_minute second:0];
384 - (NSCalendarDate *)y2kDate {
385 NSCalendarDate *newDate;
388 year = [self yearOfCommonEra];
389 if (year >= 70 && year < 135) {
390 newDate = [[NSCalendarDate
392 initWithYear:(year + 1900)
393 month:[self monthOfYear]
394 day:[self dayOfMonth]
395 hour:[self hourOfDay]
396 minute:[self minuteOfHour]
397 second:[self secondOfMinute]
398 timeZone:[self timeZone]];
400 else if (year >= 0 && year < 70) {
401 newDate = [[NSCalendarDate
403 initWithYear:(year + 2000)
404 month:[self monthOfYear]
405 day:[self dayOfMonth]
406 hour:[self hourOfDay]
407 minute:[self minuteOfHour]
408 second:[self secondOfMinute]
409 timeZone:[self timeZone]];
412 newDate = [self retain];
414 return [newDate autorelease];
417 - (NSCalendarDate *)dateByAddingYears:(int)_years
422 /* this expects that NSCalendarDate accepts invalid days, like
424 int newYear, newMonth, newDay;
426 newYear = [self yearOfCommonEra] + _years;
427 newMonth = [self monthOfYear] + _months;
428 newDay = [self dayOfMonth] + _days;
430 // this doesn't check month overflow !!
431 return [NSCalendarDate dateWithYear:newYear month:newMonth day:newDay
432 hour:[self hourOfDay]
433 minute:[self minuteOfHour]
434 second:[self secondOfMinute]
435 timeZone:[self timeZone]];
438 return [self dateByAddingYears:_years months:_months days:_days
439 hours:0 minutes:0 seconds:0];
443 /* calculate easter ... */
445 - (NSCalendarDate *)easterOfYear {
447 algorithm taken from:
448 http://www.uni-bamberg.de/~ba1lw1/fkal.html#Algorithmus
453 unsigned easterMonth, easterDay;
455 y = [self yearOfCommonEra];
457 if ((y > 1699) && (y < 1800)) {
461 else if ((y > 1799) && (y < 1900)) {
465 else if ((y > 1899) && (y < 2100)) {
469 else if ((y > 2099) && (y < 2200)) {
479 d = (19 * a + m) % 30;
480 e = (2 * b + 4 * c + 6 * d + n) % 7;
483 easterDay = 22 + d + e;
484 if (easterDay > 31) {
489 if ((easterDay == 25) && (d == 28) && (a > 10))
493 return [NSCalendarDate dateWithYear:y
496 hour:0 minute:0 second:0
497 timeZone:[self timeZone]];
500 #if !LIB_FOUNDATION_LIBRARY
501 - (id)valueForUndefinedKey:(NSString *)_key {
502 NSLog(@"WARNING: tried to access undefined KVC key '%@' on date object: %@",
508 @end /* NSCalendarDate(misc) */
512 void __link_NSCalendarDate_misc(void) {
513 __link_NSCalendarDate_misc();