~ubuntu-branches/ubuntu/trusty/gnustep-base/trusty

« back to all changes in this revision

Viewing changes to Source/NSCalendarDate.m

Tags: upstream-1.20.0
ImportĀ upstreamĀ versionĀ 1.20.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
   Boston, MA 02111 USA.
26
26
 
27
27
   <title>NSCalendarDate class reference</title>
28
 
   $Date: 2008-10-16 05:36:42 +0100 (Thu, 16 Oct 2008) $ $Revision: 26919 $
 
28
   $Date: 2010-03-19 06:10:11 -0600 (Fri, 19 Mar 2010) $ $Revision: 30001 $
29
29
   */
30
30
 
31
 
#include "config.h"
 
31
#import "common.h"
 
32
#define EXPOSE_NSCalendarDate_IVARS     1
32
33
#include <math.h>
33
 
#include "Foundation/NSArray.h"
34
 
#include "Foundation/NSAutoreleasePool.h"
35
 
#include "Foundation/NSCalendarDate.h"
36
 
#include "Foundation/NSCoder.h"
37
 
#include "Foundation/NSData.h"
38
 
#include "Foundation/NSDate.h"
39
 
#include "Foundation/NSDictionary.h"
40
 
#include "Foundation/NSDebug.h"
41
 
#include "Foundation/NSException.h"
42
 
#include "Foundation/NSObjCRuntime.h"
43
 
#include "Foundation/NSString.h"
44
 
#include "Foundation/NSTimeZone.h"
45
 
#include "Foundation/NSUserDefaults.h"
46
 
#include "GNUstepBase/GSObjCRuntime.h"
 
34
#import "Foundation/NSArray.h"
 
35
#import "Foundation/NSAutoreleasePool.h"
 
36
#import "Foundation/NSCalendarDate.h"
 
37
#import "Foundation/NSCoder.h"
 
38
#import "Foundation/NSData.h"
 
39
#import "Foundation/NSDate.h"
 
40
#import "Foundation/NSDictionary.h"
 
41
#import "Foundation/NSException.h"
 
42
#import "Foundation/NSTimeZone.h"
 
43
#import "Foundation/NSUserDefaults.h"
 
44
#import "GNUstepBase/GSObjCRuntime.h"
47
45
 
48
 
#include "GSPrivate.h"
 
46
#import "GSPrivate.h"
49
47
 
50
48
#ifdef HAVE_SYS_TIME_H
51
49
#include <sys/time.h>
52
50
#endif
53
51
#include <time.h>
54
52
#include <stdio.h>
55
 
#include <stdlib.h>
56
53
#include <ctype.h>
57
54
 
58
55
@class  GSTimeZone;
70
67
 
71
68
static NSTimeZone       *localTZ = nil;
72
69
 
 
70
static Class    NSCalendarDateClass;
73
71
static Class    absClass;
74
72
static Class    dstClass;
75
73
 
102
100
    }
103
101
  else
104
102
    {
105
 
      Class     c = GSObjCClass(tz);
 
103
      Class     c = object_getClass(tz);
106
104
 
107
105
      if (c == dstClass && dstOffIMP != 0)
108
106
        {
134
132
    }
135
133
  else
136
134
    {
137
 
      Class     c = GSObjCClass(tz);
 
135
      Class     c = object_getClass(tz);
138
136
 
139
137
      if (c == dstClass && dstAbrIMP != 0)
140
138
        {
148
146
    }
149
147
}
150
148
 
151
 
static inline unsigned int
152
 
lastDayOfGregorianMonth(unsigned month, unsigned year)
 
149
static inline NSUInteger
 
150
lastDayOfGregorianMonth(NSUInteger month, NSUInteger year)
153
151
{
154
152
  switch (month)
155
153
    {
167
165
    }
168
166
}
169
167
 
170
 
static inline unsigned
171
 
absoluteGregorianDay(unsigned day, unsigned month, unsigned year)
 
168
static inline NSUInteger
 
169
absoluteGregorianDay(NSUInteger day, NSUInteger month, NSUInteger year)
172
170
{
173
171
  if (month > 1)
174
172
    {
198
196
  when /= 86400.0;
199
197
  // Offset by Gregorian reference
200
198
  when += GREGORIAN_REFERENCE;
201
 
  r = (int)when;
 
199
  r = (NSInteger)when;
202
200
  return r;
203
201
}
204
202
 
205
203
static void
206
 
gregorianDateFromAbsolute(int abs, int *day, int *month, int *year)
 
204
gregorianDateFromAbsolute(NSInteger abs, int *day, int *month, int *year)
207
205
{
208
206
  // Search forward year by year from approximate year
209
207
  *year = abs/366;
259
257
  // Offset by Gregorian reference
260
258
  a += GREGORIAN_REFERENCE;
261
259
  // result is the day of common era.
262
 
  dayOfEra = (int)a;
 
260
  dayOfEra = (NSInteger)a;
263
261
 
264
262
  // Calculate year, month, and day
265
263
  gregorianDateFromAbsolute(dayOfEra, day, month, year);
269
267
  d *= 86400;
270
268
  a = abs(d - when);
271
269
  b = a / 3600;
272
 
  *hour = (int)b;
 
270
  *hour = (NSInteger)b;
273
271
  h = *hour;
274
272
  h = h * 3600;
275
273
  b = a - h;
276
274
  b = b / 60;
277
 
  *minute = (int)b;
 
275
  *minute = (NSInteger)b;
278
276
  m = *minute;
279
277
  m = m * 60;
280
278
  c = a - h - m;
281
 
  *second = (int)c;
282
 
  *mil = (int)((a - h - m - c) * 1000.0 + 0.5);
 
279
  *second = (NSInteger)c;
 
280
  *mil = (NSInteger)((a - h - m - c) * 1000.0 + 0.5);
283
281
}
284
282
 
285
283
/**
288
286
NSTimeInterval
289
287
GSTimeNow(void)
290
288
{
291
 
#if !defined(__MINGW32__)
292
 
  NSTimeInterval interval;
 
289
  NSTimeInterval t;
 
290
#if !defined(__MINGW__)
293
291
  struct timeval tp;
294
292
 
295
293
  gettimeofday (&tp, NULL);
296
 
  interval = -NSTimeIntervalSince1970;
297
 
  interval += tp.tv_sec;
298
 
  interval += (double)tp.tv_usec / 1000000.0;
299
 
  return interval;
 
294
  t = (NSTimeInterval)tp.tv_sec - NSTimeIntervalSince1970;
 
295
  t += (NSTimeInterval)tp.tv_usec / (NSTimeInterval)1000000.0;
 
296
#if     1
 
297
/* This is a workaround for a bug on some SMP intel systems where the TSC
 
298
 * clock information from the processors gets out of sync and causes a
 
299
 * leap of 4398 seconds into the future for an instant, and then back.
 
300
 * If we detect a time jump back by more than the sort of small interval
 
301
 * that ntpd might do (or forwards by a very large amount) we refetch the
 
302
 * system time to make sure we don't have a temporary glitch.
 
303
 */
 
304
{
 
305
  static int    old = 0;
 
306
 
 
307
  if (old == 0)
 
308
    {
 
309
      old = tp.tv_sec;
 
310
    }
 
311
  else
 
312
    {
 
313
      int       diff = tp.tv_sec - old;
 
314
 
 
315
      old = tp.tv_sec;
 
316
      if (diff < -1 || diff > 3000)
 
317
        {
 
318
          time_t        now = (time_t)tp.tv_sec;
 
319
 
 
320
          fprintf(stderr, "WARNING: system time changed by %d seconds: %s\n",
 
321
            diff, ctime(&now));
 
322
          /* Get time again ... should be OK now.
 
323
           */
 
324
          t = GSTimeNow();
 
325
        }
 
326
    }
 
327
}
 
328
#endif
 
329
 
300
330
#else
301
331
  SYSTEMTIME sys_time;
302
 
  NSTimeInterval t;
303
332
  /*
304
333
   * Get current GMT time, convert to NSTimeInterval since reference date,
305
334
   */
306
335
  GetSystemTime(&sys_time);
307
336
  t = GSTime(sys_time.wDay, sys_time.wMonth, sys_time.wYear, sys_time.wHour,
308
337
    sys_time.wMinute, sys_time.wSecond, sys_time.wMilliseconds);
 
338
#endif /* __MINGW__ */
 
339
 
309
340
  return t;
310
 
#endif /* __MINGW32__ */
311
341
}
312
342
 
313
343
/**
321
351
{
322
352
  if (self == [NSCalendarDate class])
323
353
    {
 
354
      NSCalendarDateClass = self;
324
355
      [self setVersion: 1];
325
356
      localTZ = RETAIN([NSTimeZone localTimeZone]);
326
357
 
391
422
 * Creates and returns an NSCalendarDate from the specified values
392
423
 * by calling -initWithYear:month:day:hour:minute:second:timeZone:
393
424
 */
394
 
+ (id) dateWithYear: (int)year
395
 
              month: (unsigned int)month
396
 
                day: (unsigned int)day
397
 
               hour: (unsigned int)hour
398
 
             minute: (unsigned int)minute
399
 
             second: (unsigned int)second
 
425
+ (id) dateWithYear: (NSInteger)year
 
426
              month: (NSUInteger)month
 
427
                day: (NSUInteger)day
 
428
               hour: (NSUInteger)hour
 
429
             minute: (NSUInteger)minute
 
430
             second: (NSUInteger)second
400
431
           timeZone: (NSTimeZone *)aTimeZone
401
432
{
402
433
  NSCalendarDate *d = [[self alloc] initWithYear: year
558
589
 *     %c   same as '%X %x'
559
590
 *   </item>
560
591
 *   <item>
561
 
 *     %d   day of month as decimal number
 
592
 *     %d   day of month as a two digit decimal number
562
593
 *   </item>
563
594
 *   <item>
564
 
 *     %e   same as %d without leading zero (you get a leading space instead)
 
595
 *     %e   same as %d without leading zero
565
596
 *   </item>
566
597
 *   <item>
567
598
 *     %F   milliseconds as a decimal number
576
607
 *     %j   day of year as a decimal number
577
608
 *   </item>
578
609
 *   <item>
 
610
 *     %k   same as %H without leading zero (leading space is used instead)
 
611
 *   </item>
 
612
 *   <item>
579
613
 *     %m   month as decimal number
580
614
 *   </item>
581
615
 *   <item>
623
657
 * If no second is specified in the format, 0 is assumed.<br />
624
658
 * If no millisecond is specified in the format, 0 is assumed.<br />
625
659
 * If no timezone is specified in the format, the local timezone is assumed.
 
660
 * <p>If GSMacOSXCompatible is YES, the %k specifier is not recognized.</p>
626
661
 * <p>NB. Where the format calls for a numeric value and the string contains
627
662
 * fewer digits than expected, the value will be accepted and left padded
628
663
 * with zeros to the expected size.<br />
769
804
                      [fd setLength:
770
805
                        (formatLen + sLen - 2) * sizeof(unichar)];
771
806
                      format = (unichar*)[fd mutableBytes];
772
 
                      for (i = formatLen-1; i > (int)pos; i--)
 
807
                      for (i = formatLen-1; i > (NSInteger)pos; i--)
773
808
                        {
774
809
                          format[i+sLen-2] = format[i];
775
810
                        }
776
811
                    }
777
812
                  else
778
813
                    {
779
 
                      for (i = pos+1; i < (int)formatLen; i++)
 
814
                      for (i = pos+1; i < (NSInteger)formatLen; i++)
780
815
                        {
781
816
                          format[i+sLen-2] = format[i];
782
817
                        }
843
878
        {
844
879
          // Skip '%'
845
880
          formatIdx++;
846
 
 
847
 
          switch (format[formatIdx])
848
 
            {
849
 
              case '%':
850
 
                // skip literal %
851
 
                if (sourceIdx < sourceLen)
852
 
                  {
853
 
                    if (source[sourceIdx] != '%')
 
881
          while (formatIdx < formatLen && isdigit(format[formatIdx]))
 
882
            {
 
883
              formatIdx++; // skip field width
 
884
            }
 
885
          if (formatIdx < formatLen)
 
886
            {
 
887
              switch (format[formatIdx])
 
888
                {
 
889
                  case '%':
 
890
                    // skip literal %
 
891
                    if (sourceIdx < sourceLen)
 
892
                      {
 
893
                        if (source[sourceIdx] != '%')
 
894
                          {
 
895
                            error = YES;
 
896
                            NSDebugMLog(
 
897
                              @"Expected literal '%%' but got '%c' parsing"
 
898
                              @"'%@' using '%@'", source[sourceIdx],
 
899
                              description, fmt);
 
900
                          }
 
901
                        sourceIdx++;
 
902
                      }
 
903
                    else
854
904
                      {
855
905
                        error = YES;
856
906
                        NSDebugMLog(
857
 
                          @"Expected literal '%%' but got '%c' parsing"
 
907
                          @"Expected literal '%%' but got end of string parsing"
858
908
                          @"'%@' using '%@'", source[sourceIdx],
859
909
                          description, fmt);
860
910
                      }
861
 
                    sourceIdx++;
862
 
                  }
863
 
                else
864
 
                  {
865
 
                    error = YES;
866
 
                    NSDebugMLog(
867
 
                      @"Expected literal '%%' but got end of string parsing"
868
 
                      @"'%@' using '%@'", source[sourceIdx],
869
 
                      description, fmt);
870
 
                  }
871
 
                break;
872
 
 
873
 
              case 'a':
874
 
                /* FIXME ... Should look for all values from the locale,
875
 
                 * matching for longest values first, rather than (wrongly)
876
 
                 * assuming a fixed length of three characters.
877
 
                 */
878
 
                tmpStr[0] = toupper(source[sourceIdx]);
879
 
                if (sourceIdx < sourceLen)
880
 
                  sourceIdx++;
881
 
                tmpStr[1] = tolower(source[sourceIdx]);
882
 
                if (sourceIdx < sourceLen)
883
 
                  sourceIdx++;
884
 
                tmpStr[2] = tolower(source[sourceIdx]);
885
 
                if (sourceIdx < sourceLen)
886
 
                  sourceIdx++;
887
 
                tmpStr[3] = '\0';
888
 
                {
889
 
                  NSString      *currDay;
890
 
                  NSArray       *dayNames;
891
 
 
892
 
                  currDay = [[NSString alloc] initWithCString: tmpStr];
893
 
                  dayNames = [locale objectForKey: NSShortWeekDayNameArray];
894
 
                  for (tmpIdx = 0; tmpIdx < 7; tmpIdx++)
895
 
                    {
896
 
                      if ([[dayNames objectAtIndex: tmpIdx] isEqual:
897
 
                        currDay] == YES)
898
 
                        {
899
 
                          break;
900
 
                        }
901
 
                    }
902
 
                  if (tmpIdx == 7)
903
 
                    {
904
 
                      error = YES;
905
 
                      NSDebugMLog(@"Day of week '%@' not found in locale",
906
 
                        currDay);
907
 
                    }
908
 
                  else
909
 
                    {
910
 
                      dayOfWeek = tmpIdx;
911
 
                      had |= hadw;
912
 
                    }
913
 
                  RELEASE(currDay);
914
 
                }
915
 
                break;
916
 
 
917
 
              case 'A':
918
 
                /* FIXME ... Should look for all values from the locale,
919
 
                 * matching for longest values first, rather than (wrongly)
920
 
                 * assuming the name contains only western letters.
921
 
                 */
922
 
                tmpEnd = sizeof(tmpStr) - 1;
923
 
                if (sourceLen - sourceIdx < tmpEnd)
924
 
                  {
925
 
                    tmpEnd = sourceLen - sourceIdx;
926
 
                  }
927
 
                for (tmpIdx = 0; tmpIdx < tmpEnd; tmpIdx++)
928
 
                  {
929
 
                    if (isalpha(source[sourceIdx + tmpIdx]))
930
 
                      {
931
 
                        tmpStr[tmpIdx] = source[sourceIdx + tmpIdx];
932
 
                      }
933
 
                    else
934
 
                      {
935
 
                        break;
936
 
                      }
937
 
                  }
938
 
                tmpStr[tmpIdx] = '\0';
939
 
                sourceIdx += tmpIdx;
940
 
                {
941
 
                  NSString      *currDay;
942
 
                  NSArray       *dayNames;
943
 
 
944
 
                  currDay = [[NSString alloc] initWithCString: tmpStr];
945
 
                  dayNames = [locale objectForKey: NSWeekDayNameArray];
946
 
                  for (tmpIdx = 0; tmpIdx < 7; tmpIdx++)
947
 
                    {
948
 
                      if ([[dayNames objectAtIndex: tmpIdx] isEqual:
949
 
                        currDay] == YES)
950
 
                        {
951
 
                          break;
952
 
                        }
953
 
                    }
954
 
                  if (tmpIdx == 7)
955
 
                    {
956
 
                      error = YES;
957
 
                      NSDebugMLog(@"Day of week '%@' not found in locale",
958
 
                        currDay);
959
 
                    }
960
 
                  else
961
 
                    {
962
 
                      dayOfWeek = tmpIdx;
963
 
                      had |= hadw;
964
 
                    }
965
 
                  RELEASE(currDay);
966
 
                }
967
 
                break;
968
 
 
969
 
              case 'b':
970
 
                /* FIXME ... Should look for all values from the locale,
971
 
                 * matching for longest values first, rather than (wrongly)
972
 
                 * assuming a fixed length of three characters.
973
 
                 */
974
 
                tmpStr[0] = toupper(source[sourceIdx]);
975
 
                if (sourceIdx < sourceLen)
976
 
                  sourceIdx++;
977
 
                tmpStr[1] = tolower(source[sourceIdx]);
978
 
                if (sourceIdx < sourceLen)
979
 
                  sourceIdx++;
980
 
                tmpStr[2] = tolower(source[sourceIdx]);
981
 
                if (sourceIdx < sourceLen)
982
 
                  sourceIdx++;
983
 
                tmpStr[3] = '\0';
984
 
                {
985
 
                  NSString      *currMonth;
986
 
                  NSArray       *monthNames;
987
 
 
988
 
                  currMonth = [[NSString alloc] initWithCString: tmpStr];
989
 
                  monthNames = [locale objectForKey: NSShortMonthNameArray];
990
 
 
991
 
                  for (tmpIdx = 0; tmpIdx < 12; tmpIdx++)
992
 
                    {
993
 
                      if ([[monthNames objectAtIndex: tmpIdx]
994
 
                                isEqual: currMonth] == YES)
995
 
                        {
996
 
                          break;
997
 
                        }
998
 
                    }
999
 
                  if (tmpIdx == 12)
1000
 
                    {
1001
 
                      error = YES;
1002
 
                      NSDebugMLog(@"Month of year '%@' not found in locale",
1003
 
                        currMonth);
1004
 
                    }
1005
 
                  else
1006
 
                    {
1007
 
                      month = tmpIdx+1;
1008
 
                      had |= hadM;
1009
 
                    }
1010
 
                  RELEASE(currMonth);
1011
 
                }
1012
 
                break;
1013
 
 
1014
 
              case 'B':
1015
 
                /* FIXME ... Should look for all values from the locale,
1016
 
                 * matching for longest values first, rather than (wrongly)
1017
 
                 * assuming the name contains only western letters.
1018
 
                 */
1019
 
                tmpEnd = sizeof(tmpStr) - 1;
1020
 
                if (sourceLen - sourceIdx < tmpEnd)
1021
 
                  {
1022
 
                    tmpEnd = sourceLen - sourceIdx;
1023
 
                  }
1024
 
                for (tmpIdx = 0; tmpIdx < tmpEnd; tmpIdx++)
1025
 
                  {
1026
 
                    if (isalpha(source[sourceIdx + tmpIdx]))
1027
 
                      {
1028
 
                        tmpStr[tmpIdx] = source[sourceIdx + tmpIdx];
1029
 
                      }
1030
 
                    else
1031
 
                      {
1032
 
                        break;
1033
 
                      }
1034
 
                  }
1035
 
                tmpStr[tmpIdx] = '\0';
1036
 
                sourceIdx += tmpIdx;
1037
 
                {
1038
 
                  NSString      *currMonth;
1039
 
                  NSArray       *monthNames;
1040
 
 
1041
 
                  currMonth = [[NSString alloc] initWithCString: tmpStr];
1042
 
                  monthNames = [locale objectForKey: NSMonthNameArray];
1043
 
 
1044
 
                  for (tmpIdx = 0; tmpIdx < 12; tmpIdx++)
1045
 
                    {
1046
 
                      if ([[monthNames objectAtIndex: tmpIdx]
1047
 
                                isEqual: currMonth] == YES)
1048
 
                        {
1049
 
                          break;
1050
 
                        }
1051
 
                    }
1052
 
                  if (tmpIdx == 12)
1053
 
                    {
1054
 
                      error = YES;
1055
 
                      NSDebugMLog(@"Month of year '%@' not found in locale",
1056
 
                        currMonth);
1057
 
                    }
1058
 
                  else
1059
 
                    {
1060
 
                      month = tmpIdx+1;
1061
 
                      had |= hadM;
1062
 
                    }
1063
 
                  RELEASE(currMonth);
1064
 
                }
1065
 
                break;
1066
 
 
1067
 
              case 'd': // fall through
1068
 
              case 'e':
1069
 
                sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
1070
 
                day = atoi(tmpStr);
1071
 
                had |= hadD;
1072
 
                if (error == NO && day < 1)
1073
 
                  {
1074
 
                    error = YES;
1075
 
                    NSDebugMLog(@"Day of month is zero");
1076
 
                  }
1077
 
                break;
1078
 
 
1079
 
              case 'F':
1080
 
                sourceIdx += getDigits(&source[sourceIdx], tmpStr, 3, &error);
1081
 
                milliseconds = atoi(tmpStr);
1082
 
                break;
1083
 
 
1084
 
              case 'I': // fall through
1085
 
                twelveHrClock = YES;
1086
 
              case 'H':
1087
 
                sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
1088
 
                hour = atoi(tmpStr);
1089
 
                had |= hadh;
1090
 
                break;
1091
 
 
1092
 
              case 'j':
1093
 
                sourceIdx += getDigits(&source[sourceIdx], tmpStr, 3, &error);
1094
 
                day = atoi(tmpStr);
1095
 
                had |= hadD;
1096
 
                break;
1097
 
 
1098
 
              case 'm':
1099
 
                sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
1100
 
                month = atoi(tmpStr);
1101
 
                had |= hadM;
1102
 
                if (error == NO && month < 1)
1103
 
                  {
1104
 
                    error = YES;
1105
 
                    NSDebugMLog(@"Month of year is zero");
1106
 
                  }
1107
 
                break;
1108
 
 
1109
 
              case 'M':
1110
 
                sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
1111
 
                min = atoi(tmpStr);
1112
 
                had |= hadm;
1113
 
                break;
1114
 
 
1115
 
              case 'p':
1116
 
                /* FIXME ... Should look for all values from the locale,
1117
 
                 * matching for longest values first, rather than (wrongly)
1118
 
                 * assuming the name is always two uppercase letters.
1119
 
                 */
1120
 
                tmpStr[0] = toupper(source[sourceIdx]);
1121
 
                if (sourceIdx < sourceLen)
1122
 
                  sourceIdx++;
1123
 
                tmpStr[1] = toupper(source[sourceIdx]);
1124
 
                if (sourceIdx < sourceLen)
1125
 
                  sourceIdx++;
1126
 
                tmpStr[2] = '\0';
1127
 
                {
1128
 
                  NSString      *currAMPM;
1129
 
                  NSArray       *amPMNames;
1130
 
 
1131
 
                  currAMPM = [NSString stringWithUTF8String: tmpStr];
1132
 
                  amPMNames = [locale objectForKey: NSAMPMDesignation];
1133
 
 
1134
 
                  /*
1135
 
                   * The time addition is handled below because this
1136
 
                   * indicator only modifies the time on a 12hour clock.
1137
 
                   */
1138
 
                  if ([[amPMNames objectAtIndex: 1] isEqual:
1139
 
                    currAMPM] == YES)
1140
 
                    {
1141
 
                      ampm = YES;
1142
 
                    }
1143
 
                }
1144
 
                break;
1145
 
 
1146
 
              case 'S':
1147
 
                sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
1148
 
                sec = atoi(tmpStr);
1149
 
                had |= hads;
1150
 
                break;
1151
 
 
1152
 
              case 'w':
1153
 
                sourceIdx += getDigits(&source[sourceIdx], tmpStr, 1, &error);
1154
 
                dayOfWeek = atoi(tmpStr);
1155
 
                had |= hadw;
1156
 
                break;
1157
 
 
1158
 
              case 'W': // Fall through
1159
 
                weekStartsMonday = 1;
1160
 
              case 'U':
1161
 
                sourceIdx += getDigits(&source[sourceIdx], tmpStr, 1, &error);
1162
 
                julianWeeks = atoi(tmpStr);
1163
 
                break;
1164
 
 
1165
 
                //      case 'x':
1166
 
                //      break;
1167
 
 
1168
 
                //      case 'X':
1169
 
                //      break;
1170
 
 
1171
 
              case 'y':
1172
 
                sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
1173
 
                year = atoi(tmpStr);
1174
 
                if (year >= 70)
1175
 
                  {
1176
 
                    year += 1900;
1177
 
                  }
1178
 
                else
1179
 
                  {
1180
 
                    year += 2000;
1181
 
                  }
1182
 
                had |= hadY;
1183
 
                break;
1184
 
 
1185
 
              case 'Y':
1186
 
                sourceIdx += getDigits(&source[sourceIdx], tmpStr, 4, &error);
1187
 
                year = atoi(tmpStr);
1188
 
                had |= hadY;
1189
 
                break;
1190
 
 
1191
 
              case 'z':
1192
 
                {
1193
 
                  int   sign = 1;
1194
 
                  int   zone;
1195
 
                  int   found;
1196
 
 
1197
 
                  if (source[sourceIdx] == '+')
1198
 
                    {
1199
 
                      sourceIdx++;
1200
 
                    }
1201
 
                  else if (source[sourceIdx] == '-')
1202
 
                    {
1203
 
                      sign = -1;
1204
 
                      sourceIdx++;
1205
 
                    }
1206
 
                  found = getDigits(&source[sourceIdx], tmpStr, 4, &error);
1207
 
                  if (found > 0)
1208
 
                    {
1209
 
                      sourceIdx += found;
1210
 
                      zone = atoi(tmpStr);
1211
 
                      if (found == 2)
1212
 
                        {
1213
 
                          zone *= 100;  // Convert 2 digits to 4
1214
 
                        }
1215
 
                      tz = [NSTimeZone timeZoneForSecondsFromGMT:
1216
 
                        sign * ((zone / 100) * 60 + (zone % 100)) * 60];
1217
 
                    }
1218
 
                }
1219
 
                break;
1220
 
 
1221
 
              case 'Z':
1222
 
                /* Can we assume a timezone name is always space terminated?
1223
 
                 */
1224
 
                tmpEnd = sizeof(tmpStr) - 1;
1225
 
                if (sourceLen - sourceIdx < tmpEnd)
1226
 
                  {
1227
 
                    tmpEnd = sourceLen - sourceIdx;
1228
 
                  }
1229
 
                for (tmpIdx = 0; tmpIdx < tmpEnd; tmpIdx++)
1230
 
                  {
1231
 
                    if (!isspace(source[sourceIdx + tmpIdx]))
1232
 
                      {
1233
 
                        tmpStr[tmpIdx] = source[sourceIdx + tmpIdx];
1234
 
                      }
1235
 
                    else
1236
 
                      {
1237
 
                        break;
1238
 
                      }
1239
 
                  }
1240
 
                tmpStr[tmpIdx] = '\0';
1241
 
                sourceIdx += tmpIdx;
1242
 
                {
1243
 
                  NSString      *z = [NSString stringWithUTF8String: tmpStr];
1244
 
 
1245
 
                  /* Abbreviations aren't one-to-one with time zone names
1246
 
                     so just look for the zone named after the abbreviation,
1247
 
                     then look up the abbreviation as a last resort */
1248
 
                  tz = [NSTimeZone timeZoneWithName: z];
1249
 
                  if (tz == nil)
1250
 
                    {
1251
 
                      tz = [NSTimeZone timeZoneWithAbbreviation: z];
 
911
                    break;
 
912
 
 
913
                  case 'a':
 
914
                    /* FIXME ... Should look for all values from the locale,
 
915
                     * matching for longest values first, rather than (wrongly)
 
916
                     * assuming a fixed length of three characters.
 
917
                     */
 
918
                    tmpStr[0] = toupper(source[sourceIdx]);
 
919
                    if (sourceIdx < sourceLen)
 
920
                      sourceIdx++;
 
921
                    tmpStr[1] = tolower(source[sourceIdx]);
 
922
                    if (sourceIdx < sourceLen)
 
923
                      sourceIdx++;
 
924
                    tmpStr[2] = tolower(source[sourceIdx]);
 
925
                    if (sourceIdx < sourceLen)
 
926
                      sourceIdx++;
 
927
                    tmpStr[3] = '\0';
 
928
                    {
 
929
                      NSString  *currDay;
 
930
                      NSArray   *dayNames;
 
931
 
 
932
                      currDay = [[NSString alloc] initWithCString: tmpStr];
 
933
                      dayNames = [locale objectForKey: NSShortWeekDayNameArray];
 
934
                      for (tmpIdx = 0; tmpIdx < 7; tmpIdx++)
 
935
                        {
 
936
                          if ([[dayNames objectAtIndex: tmpIdx] isEqual:
 
937
                            currDay] == YES)
 
938
                            {
 
939
                              break;
 
940
                            }
 
941
                        }
 
942
                      if (tmpIdx == 7)
 
943
                        {
 
944
                          error = YES;
 
945
                          NSDebugMLog(@"Day of week '%@' not found in locale",
 
946
                            currDay);
 
947
                        }
 
948
                      else
 
949
                        {
 
950
                          dayOfWeek = tmpIdx;
 
951
                          had |= hadw;
 
952
                        }
 
953
                      RELEASE(currDay);
 
954
                    }
 
955
                    break;
 
956
 
 
957
                  case 'A':
 
958
                    /* FIXME ... Should look for all values from the locale,
 
959
                     * matching for longest values first, rather than (wrongly)
 
960
                     * assuming the name contains only western letters.
 
961
                     */
 
962
                    tmpEnd = sizeof(tmpStr) - 1;
 
963
                    if (sourceLen - sourceIdx < tmpEnd)
 
964
                      {
 
965
                        tmpEnd = sourceLen - sourceIdx;
 
966
                      }
 
967
                    for (tmpIdx = 0; tmpIdx < tmpEnd; tmpIdx++)
 
968
                      {
 
969
                        if (isalpha(source[sourceIdx + tmpIdx]))
 
970
                          {
 
971
                            tmpStr[tmpIdx] = source[sourceIdx + tmpIdx];
 
972
                          }
 
973
                        else
 
974
                          {
 
975
                            break;
 
976
                          }
 
977
                      }
 
978
                    tmpStr[tmpIdx] = '\0';
 
979
                    sourceIdx += tmpIdx;
 
980
                    {
 
981
                      NSString  *currDay;
 
982
                      NSArray   *dayNames;
 
983
 
 
984
                      currDay = [[NSString alloc] initWithCString: tmpStr];
 
985
                      dayNames = [locale objectForKey: NSWeekDayNameArray];
 
986
                      for (tmpIdx = 0; tmpIdx < 7; tmpIdx++)
 
987
                        {
 
988
                          if ([[dayNames objectAtIndex: tmpIdx] isEqual:
 
989
                            currDay] == YES)
 
990
                            {
 
991
                              break;
 
992
                            }
 
993
                        }
 
994
                      if (tmpIdx == 7)
 
995
                        {
 
996
                          error = YES;
 
997
                          NSDebugMLog(@"Day of week '%@' not found in locale",
 
998
                            currDay);
 
999
                        }
 
1000
                      else
 
1001
                        {
 
1002
                          dayOfWeek = tmpIdx;
 
1003
                          had |= hadw;
 
1004
                        }
 
1005
                      RELEASE(currDay);
 
1006
                    }
 
1007
                    break;
 
1008
 
 
1009
                  case 'b':
 
1010
                    /* FIXME ... Should look for all values from the locale,
 
1011
                     * matching for longest values first, rather than (wrongly)
 
1012
                     * assuming a fixed length of three characters.
 
1013
                     */
 
1014
                    tmpStr[0] = toupper(source[sourceIdx]);
 
1015
                    if (sourceIdx < sourceLen)
 
1016
                      sourceIdx++;
 
1017
                    tmpStr[1] = tolower(source[sourceIdx]);
 
1018
                    if (sourceIdx < sourceLen)
 
1019
                      sourceIdx++;
 
1020
                    tmpStr[2] = tolower(source[sourceIdx]);
 
1021
                    if (sourceIdx < sourceLen)
 
1022
                      sourceIdx++;
 
1023
                    tmpStr[3] = '\0';
 
1024
                    {
 
1025
                      NSString  *currMonth;
 
1026
                      NSArray   *monthNames;
 
1027
 
 
1028
                      currMonth = [[NSString alloc] initWithCString: tmpStr];
 
1029
                      monthNames = [locale objectForKey: NSShortMonthNameArray];
 
1030
 
 
1031
                      for (tmpIdx = 0; tmpIdx < 12; tmpIdx++)
 
1032
                        {
 
1033
                          if ([[monthNames objectAtIndex: tmpIdx]
 
1034
                                    isEqual: currMonth] == YES)
 
1035
                            {
 
1036
                              break;
 
1037
                            }
 
1038
                        }
 
1039
                      if (tmpIdx == 12)
 
1040
                        {
 
1041
                          error = YES;
 
1042
                          NSDebugMLog(@"Month of year '%@' not found in locale",
 
1043
                            currMonth);
 
1044
                        }
 
1045
                      else
 
1046
                        {
 
1047
                          month = tmpIdx+1;
 
1048
                          had |= hadM;
 
1049
                        }
 
1050
                      RELEASE(currMonth);
 
1051
                    }
 
1052
                    break;
 
1053
 
 
1054
                  case 'B':
 
1055
                    /* FIXME ... Should look for all values from the locale,
 
1056
                     * matching for longest values first, rather than (wrongly)
 
1057
                     * assuming the name contains only western letters.
 
1058
                     */
 
1059
                    tmpEnd = sizeof(tmpStr) - 1;
 
1060
                    if (sourceLen - sourceIdx < tmpEnd)
 
1061
                      {
 
1062
                        tmpEnd = sourceLen - sourceIdx;
 
1063
                      }
 
1064
                    for (tmpIdx = 0; tmpIdx < tmpEnd; tmpIdx++)
 
1065
                      {
 
1066
                        if (isalpha(source[sourceIdx + tmpIdx]))
 
1067
                          {
 
1068
                            tmpStr[tmpIdx] = source[sourceIdx + tmpIdx];
 
1069
                          }
 
1070
                        else
 
1071
                          {
 
1072
                            break;
 
1073
                          }
 
1074
                      }
 
1075
                    tmpStr[tmpIdx] = '\0';
 
1076
                    sourceIdx += tmpIdx;
 
1077
                    {
 
1078
                      NSString  *currMonth;
 
1079
                      NSArray   *monthNames;
 
1080
 
 
1081
                      currMonth = [[NSString alloc] initWithCString: tmpStr];
 
1082
                      monthNames = [locale objectForKey: NSMonthNameArray];
 
1083
 
 
1084
                      for (tmpIdx = 0; tmpIdx < 12; tmpIdx++)
 
1085
                        {
 
1086
                          if ([[monthNames objectAtIndex: tmpIdx]
 
1087
                                    isEqual: currMonth] == YES)
 
1088
                            {
 
1089
                              break;
 
1090
                            }
 
1091
                        }
 
1092
                      if (tmpIdx == 12)
 
1093
                        {
 
1094
                          error = YES;
 
1095
                          NSDebugMLog(@"Month of year '%@' not found in locale",
 
1096
                            currMonth);
 
1097
                        }
 
1098
                      else
 
1099
                        {
 
1100
                          month = tmpIdx+1;
 
1101
                          had |= hadM;
 
1102
                        }
 
1103
                      RELEASE(currMonth);
 
1104
                    }
 
1105
                    break;
 
1106
 
 
1107
                  case 'd': // fall through
 
1108
                  case 'e':
 
1109
                    sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
 
1110
                    day = atoi(tmpStr);
 
1111
                    had |= hadD;
 
1112
                    if (error == NO && day < 1)
 
1113
                      {
 
1114
                        error = YES;
 
1115
                        NSDebugMLog(@"Day of month is zero");
 
1116
                      }
 
1117
                    break;
 
1118
 
 
1119
                  case 'F':
 
1120
                    sourceIdx += getDigits(&source[sourceIdx], tmpStr, 3, &error);
 
1121
                    milliseconds = atoi(tmpStr);
 
1122
                    break;
 
1123
 
 
1124
                  case 'k':
 
1125
                    // GNUstep extension, not available in Cocoa
 
1126
                    if (GSPrivateDefaultsFlag(GSMacOSXCompatible))
 
1127
                      {
 
1128
                        error = YES;
 
1129
                        NSLog(@"Invalid NSCalendar date, "
 
1130
                              @"specifier %c not recognized in format %@",
 
1131
                              format[formatIdx], fmt);
 
1132
                      }
 
1133
                  case 'I': // fall through
 
1134
                    twelveHrClock = YES;
 
1135
                  case 'H':
 
1136
                    sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
 
1137
                    hour = atoi(tmpStr);
 
1138
                    had |= hadh;
 
1139
                    break;
 
1140
 
 
1141
                  case 'j':
 
1142
                    sourceIdx += getDigits(&source[sourceIdx], tmpStr, 3, &error);
 
1143
                    day = atoi(tmpStr);
 
1144
                    had |= hadD;
 
1145
                    break;
 
1146
 
 
1147
                  case 'm':
 
1148
                    sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
 
1149
                    month = atoi(tmpStr);
 
1150
                    had |= hadM;
 
1151
                    if (error == NO && month < 1)
 
1152
                      {
 
1153
                        error = YES;
 
1154
                        NSDebugMLog(@"Month of year is zero");
 
1155
                      }
 
1156
                    break;
 
1157
 
 
1158
                  case 'M':
 
1159
                    sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
 
1160
                    min = atoi(tmpStr);
 
1161
                    had |= hadm;
 
1162
                    break;
 
1163
 
 
1164
                  case 'p':
 
1165
                    /* FIXME ... Should look for all values from the locale,
 
1166
                     * matching for longest values first, rather than (wrongly)
 
1167
                     * assuming the name is always two uppercase letters.
 
1168
                     */
 
1169
                    tmpStr[0] = toupper(source[sourceIdx]);
 
1170
                    if (sourceIdx < sourceLen)
 
1171
                      sourceIdx++;
 
1172
                    tmpStr[1] = toupper(source[sourceIdx]);
 
1173
                    if (sourceIdx < sourceLen)
 
1174
                      sourceIdx++;
 
1175
                    tmpStr[2] = '\0';
 
1176
                    {
 
1177
                      NSString  *currAMPM;
 
1178
                      NSArray   *amPMNames;
 
1179
 
 
1180
                      currAMPM = [NSString stringWithUTF8String: tmpStr];
 
1181
                      amPMNames = [locale objectForKey: NSAMPMDesignation];
 
1182
 
 
1183
                      /*
 
1184
                       * The time addition is handled below because this
 
1185
                       * indicator only modifies the time on a 12hour clock.
 
1186
                       */
 
1187
                      if ([[amPMNames objectAtIndex: 1] isEqual:
 
1188
                        currAMPM] == YES)
 
1189
                        {
 
1190
                          ampm = YES;
 
1191
                        }
 
1192
                    }
 
1193
                    break;
 
1194
 
 
1195
                  case 'S':
 
1196
                    sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
 
1197
                    sec = atoi(tmpStr);
 
1198
                    had |= hads;
 
1199
                    break;
 
1200
 
 
1201
                  case 'w':
 
1202
                    sourceIdx += getDigits(&source[sourceIdx], tmpStr, 1, &error);
 
1203
                    dayOfWeek = atoi(tmpStr);
 
1204
                    had |= hadw;
 
1205
                    break;
 
1206
 
 
1207
                  case 'W': // Fall through
 
1208
                    weekStartsMonday = 1;
 
1209
                  case 'U':
 
1210
                    sourceIdx += getDigits(&source[sourceIdx], tmpStr, 1, &error);
 
1211
                    julianWeeks = atoi(tmpStr);
 
1212
                    break;
 
1213
 
 
1214
                    //  case 'x':
 
1215
                    //  break;
 
1216
 
 
1217
                    //  case 'X':
 
1218
                    //  break;
 
1219
 
 
1220
                  case 'y':
 
1221
                    sourceIdx += getDigits(&source[sourceIdx], tmpStr, 2, &error);
 
1222
                    year = atoi(tmpStr);
 
1223
                    if (year >= 70)
 
1224
                      {
 
1225
                        year += 1900;
 
1226
                      }
 
1227
                    else
 
1228
                      {
 
1229
                        year += 2000;
 
1230
                      }
 
1231
                    had |= hadY;
 
1232
                    break;
 
1233
 
 
1234
                  case 'Y':
 
1235
                    sourceIdx += getDigits(&source[sourceIdx], tmpStr, 4, &error);
 
1236
                    year = atoi(tmpStr);
 
1237
                    had |= hadY;
 
1238
                    break;
 
1239
 
 
1240
                  case 'z':
 
1241
                    {
 
1242
                      int       sign = 1;
 
1243
                      int       zone;
 
1244
                      int       found;
 
1245
 
 
1246
                      if (source[sourceIdx] == '+')
 
1247
                        {
 
1248
                          sourceIdx++;
 
1249
                        }
 
1250
                      else if (source[sourceIdx] == '-')
 
1251
                        {
 
1252
                          sign = -1;
 
1253
                          sourceIdx++;
 
1254
                        }
 
1255
                      found = getDigits(&source[sourceIdx], tmpStr, 4, &error);
 
1256
                      if (found > 0)
 
1257
                        {
 
1258
                          sourceIdx += found;
 
1259
                          zone = atoi(tmpStr);
 
1260
                          if (found == 2)
 
1261
                            {
 
1262
                              zone *= 100;      // Convert 2 digits to 4
 
1263
                            }
 
1264
                          tz = [NSTimeZone timeZoneForSecondsFromGMT:
 
1265
                            sign * ((zone / 100) * 60 + (zone % 100)) * 60];
 
1266
                        }
 
1267
                    }
 
1268
                    break;
 
1269
 
 
1270
                  case 'Z':
 
1271
                    /* Can we assume a timezone name is always space terminated?
 
1272
                     */
 
1273
                    tmpEnd = sizeof(tmpStr) - 1;
 
1274
                    if (sourceLen - sourceIdx < tmpEnd)
 
1275
                      {
 
1276
                        tmpEnd = sourceLen - sourceIdx;
 
1277
                      }
 
1278
                    for (tmpIdx = 0; tmpIdx < tmpEnd; tmpIdx++)
 
1279
                      {
 
1280
                        if (!isspace(source[sourceIdx + tmpIdx]))
 
1281
                          {
 
1282
                            tmpStr[tmpIdx] = source[sourceIdx + tmpIdx];
 
1283
                          }
 
1284
                        else
 
1285
                          {
 
1286
                            break;
 
1287
                          }
 
1288
                      }
 
1289
                    tmpStr[tmpIdx] = '\0';
 
1290
                    sourceIdx += tmpIdx;
 
1291
                    {
 
1292
                      NSString  *z = [NSString stringWithUTF8String: tmpStr];
 
1293
 
 
1294
                      /* Abbreviations aren't one-to-one with time zone names
 
1295
                         so just look for the zone named after the abbreviation,
 
1296
                         then look up the abbreviation as a last resort */
 
1297
                      tz = [NSTimeZone timeZoneWithName: z];
1252
1298
                      if (tz == nil)
1253
1299
                        {
1254
 
                          error = YES;
1255
 
                          NSDebugMLog(@"Time zone '%@' not found", z);
 
1300
                          tz = [NSTimeZone timeZoneWithAbbreviation: z];
 
1301
                          if (tz == nil)
 
1302
                            {
 
1303
                              error = YES;
 
1304
                              NSDebugMLog(@"Time zone '%@' not found", z);
 
1305
                            }
1256
1306
                        }
1257
1307
                    }
 
1308
                    break;
 
1309
 
 
1310
                  default:
 
1311
                    error = YES;
 
1312
                    NSLog(@"Invalid NSCalendar date, "
 
1313
                      @"specifier %c not recognized in format %@",
 
1314
                      format[formatIdx], fmt);
 
1315
                    break;
1258
1316
                }
1259
 
                break;
1260
 
 
1261
 
              default:
1262
 
                error = YES;
1263
 
                NSLog(@"Invalid NSCalendar date, "
1264
 
                  @"specifier %c not recognized in format %@",
1265
 
                  format[formatIdx], fmt);
1266
 
                break;
1267
1317
            }
1268
1318
        }
1269
1319
      formatIdx++;
1295
1345
 
1296
1346
          if ((had & (hadY|hadw)) != (hadY|hadw))
1297
1347
            {
1298
 
              NSCalendarDate    *now = [[NSCalendarDate alloc] init];
 
1348
              NSCalendarDate    *now = [[NSCalendarDateClass alloc] init];
1299
1349
 
1300
1350
              [now setTimeZone: gmtZone];
1301
1351
              if ((had & hadY) == 0)
1311
1361
              RELEASE(now);
1312
1362
            }
1313
1363
 
1314
 
          d = [[NSCalendarDate alloc] initWithYear: year
1315
 
                                             month: 1
1316
 
                                               day: 1
1317
 
                                              hour: 0
1318
 
                                            minute: 0
1319
 
                                            second: 0
1320
 
                                          timeZone: gmtZone];
 
1364
          d = [[NSCalendarDateClass alloc] initWithYear: year
 
1365
                                                  month: 1
 
1366
                                                    day: 1
 
1367
                                                   hour: 0
 
1368
                                                 minute: 0
 
1369
                                                 second: 0
 
1370
                                               timeZone: gmtZone];
1321
1371
          currDay = [d dayOfWeek];
1322
1372
          RELEASE(d);
1323
1373
 
1347
1397
       */
1348
1398
      if ((had & hadY) == 0)
1349
1399
        {
1350
 
          NSCalendarDate        *now = [[NSCalendarDate alloc] init];
 
1400
          NSCalendarDate        *now = [[NSCalendarDateClass alloc] init];
1351
1401
 
1352
1402
          year = [now yearOfCommonEra];
1353
1403
          RELEASE(now);
1422
1472
 *   </item>
1423
1473
 * </list>
1424
1474
 */
1425
 
- (id) initWithYear: (int)year
1426
 
              month: (unsigned int)month
1427
 
                day: (unsigned int)day
1428
 
               hour: (unsigned int)hour
1429
 
             minute: (unsigned int)minute
1430
 
             second: (unsigned int)second
 
1475
- (id) initWithYear: (NSInteger)year
 
1476
              month: (NSUInteger)month
 
1477
                day: (NSUInteger)day
 
1478
               hour: (NSUInteger)hour
 
1479
             minute: (NSUInteger)minute
 
1480
             second: (NSUInteger)second
1431
1481
           timeZone: (NSTimeZone *)aTimeZone
1432
1482
{
1433
1483
  unsigned int          c;
1533
1583
 * Return the day number (ie number of days since the start of) in the
1534
1584
 * 'common' era of the receiving date.  The era starts at 1 A.D.
1535
1585
 */
1536
 
- (int) dayOfCommonEra
 
1586
- (NSInteger) dayOfCommonEra
1537
1587
{
1538
1588
  NSTimeInterval        when;
1539
1589
 
1544
1594
/**
1545
1595
 * Return the month (1 to 31) of the receiving date.
1546
1596
 */
1547
 
- (int) dayOfMonth
 
1597
- (NSInteger) dayOfMonth
1548
1598
{
1549
1599
  int m, d, y;
1550
1600
  NSTimeInterval        when;
1567
1617
 *   <item>6 is saturday</item>
1568
1618
 * </list>
1569
1619
 */
1570
 
- (int) dayOfWeek
 
1620
- (NSInteger) dayOfWeek
1571
1621
{
1572
1622
  int   d;
1573
1623
  NSTimeInterval        when;
1588
1638
/**
1589
1639
 * Return the day of the year (1 to 366) of the receiving date.
1590
1640
 */
1591
 
- (int) dayOfYear
 
1641
- (NSInteger) dayOfYear
1592
1642
{
1593
1643
  int m, d, y, days, i;
1594
1644
  NSTimeInterval        when;
1605
1655
/**
1606
1656
 * Return the hour of the day (0 to 23) of the receiving date.
1607
1657
 */
1608
 
- (int) hourOfDay
 
1658
- (NSInteger) hourOfDay
1609
1659
{
1610
1660
  int h;
1611
1661
  double a, d;
1617
1667
  d *= 86400;
1618
1668
  a = abs(d - (_seconds_since_ref + offset(_time_zone, self)));
1619
1669
  a = a / 3600;
1620
 
  h = (int)a;
 
1670
  h = (NSInteger)a;
1621
1671
 
1622
1672
  // There is a small chance of getting
1623
1673
  // it right at the stroke of midnight
1630
1680
/**
1631
1681
 * Return the minute of the hour (0 to 59) of the receiving date.
1632
1682
 */
1633
 
- (int) minuteOfHour
 
1683
- (NSInteger) minuteOfHour
1634
1684
{
1635
1685
  int h, m;
1636
1686
  double a, b, d;
1642
1692
  d *= 86400;
1643
1693
  a = abs(d - (_seconds_since_ref + offset(_time_zone, self)));
1644
1694
  b = a / 3600;
1645
 
  h = (int)b;
 
1695
  h = (NSInteger)b;
1646
1696
  h = h * 3600;
1647
1697
  b = a - h;
1648
1698
  b = b / 60;
1649
 
  m = (int)b;
 
1699
  m = (NSInteger)b;
1650
1700
 
1651
1701
  return m;
1652
1702
}
1654
1704
/**
1655
1705
 * Return the month of the year (1 to 12) of the receiving date.
1656
1706
 */
1657
 
- (int) monthOfYear
 
1707
- (NSInteger) monthOfYear
1658
1708
{
1659
1709
  int m, d, y;
1660
1710
  NSTimeInterval        when;
1668
1718
/**
1669
1719
 * Return the second of the minute (0 to 59) of the receiving date.
1670
1720
 */
1671
 
- (int) secondOfMinute
 
1721
- (NSInteger) secondOfMinute
1672
1722
{
1673
1723
  int h, m, s;
1674
1724
  double a, b, c, d;
1680
1730
  d *= 86400;
1681
1731
  a = abs(d - (_seconds_since_ref + offset(_time_zone, self)));
1682
1732
  b = a / 3600;
1683
 
  h = (int)b;
 
1733
  h = (NSInteger)b;
1684
1734
  h = h * 3600;
1685
1735
  b = a - h;
1686
1736
  b = b / 60;
1687
 
  m = (int)b;
 
1737
  m = (NSInteger)b;
1688
1738
  m = m * 60;
1689
1739
  c = a - h - m;
1690
 
  s = (int)c;
 
1740
  s = (NSInteger)c;
1691
1741
 
1692
1742
  return s;
1693
1743
}
1696
1746
 * Return the year of the 'common' era of the receiving date.
1697
1747
 * The era starts at 1 A.D.
1698
1748
 */
1699
 
- (int) yearOfCommonEra
 
1749
- (NSInteger) yearOfCommonEra
1700
1750
{
1701
1751
  int m, d, y;
1702
1752
  NSTimeInterval        when;
1712
1762
 * Its use is deprecated ... it simply calls
1713
1763
 * -dateByAddingYears:months:days:hours:minutes:seconds:
1714
1764
 */
1715
 
- (NSCalendarDate*) addYear: (int)year
1716
 
                      month: (int)month
1717
 
                        day: (int)day
1718
 
                       hour: (int)hour
1719
 
                     minute: (int)minute
1720
 
                     second: (int)second
 
1765
- (NSCalendarDate*) addYear: (NSInteger)year
 
1766
                      month: (NSInteger)month
 
1767
                        day: (NSInteger)day
 
1768
                       hour: (NSInteger)hour
 
1769
                     minute: (NSInteger)minute
 
1770
                     second: (NSInteger)second
1721
1771
{
1722
1772
  return [self dateByAddingYears: year
1723
1773
                          months: month
1783
1833
    }
1784
1834
}
1785
1835
 
 
1836
#define MAX_FLD_WIDTH 99
 
1837
 
 
1838
static void outputValueWithFormat(int v, char *fldfmt, DescriptionInfo *info)
 
1839
{
 
1840
  char  cbuf[MAX_FLD_WIDTH + 1];
 
1841
  int   idx = 0;
 
1842
 
 
1843
  sprintf((char*)cbuf, fldfmt, v);
 
1844
  Grow(info, strlen((char*)cbuf));
 
1845
  while (cbuf[idx] != '\0')
 
1846
    {
 
1847
      info->t[info->offset++] = cbuf[idx++];
 
1848
    }
 
1849
}
 
1850
 
1786
1851
- (void) _format: (NSString*)fmt
1787
1852
          locale: (NSDictionary*)locale
1788
1853
            info: (DescriptionInfo*)info
1814
1879
      BOOL      mname = NO;
1815
1880
      BOOL      dname = NO;
1816
1881
      BOOL      twelve = NO;
 
1882
      BOOL      hspc = NO;
 
1883
      char      fldfmt[8];
 
1884
      int       fmtlen = 0;
 
1885
      int       width = 0;
1817
1886
 
1818
1887
      // Only care about a format specifier
1819
1888
      if (f[i] == '%')
1820
1889
        {
1821
1890
          i++;
 
1891
          fldfmt[fmtlen++] = '%'; // start format with %
 
1892
          while (fmtlen < 5 && f[i] >= '0' && f[i] <= '9') // field width specified
 
1893
            {
 
1894
              fldfmt[fmtlen++] = f[i];
 
1895
              width = 10 * width + f[i] - '0';
 
1896
              i++;
 
1897
            }
 
1898
          if (fmtlen >= 5 || width > MAX_FLD_WIDTH)
 
1899
            {
 
1900
              // ignore formats that specify field width greater than the max allowed
 
1901
              i -= fmtlen; // set i back so all ignored characters will be copied
 
1902
            }
 
1903
 
1822
1904
          // check the character that comes after
1823
1905
          switch (f[i++])
1824
1906
            {
1875
1957
                v = info->yd;
1876
1958
                if (ycent)
1877
1959
                  {
1878
 
                    if (v >= 0 && v <= 9999)
1879
 
                      {
1880
 
                        Grow(info, 4);
1881
 
                        info->t[info->offset+3] = (v%10) + '0';
1882
 
                        v /= 10;
1883
 
                        info->t[info->offset+2] = (v%10) + '0';
1884
 
                        v /= 10;
1885
 
                        info->t[info->offset+1] = (v%10) + '0';
1886
 
                        v /= 10;
1887
 
                        info->t[info->offset+0] = (v%10) + '0';
1888
 
                        info->offset += 4;
1889
 
                      }
1890
 
                    else
1891
 
                      {
1892
 
                        unsigned char   tmp[16];
1893
 
                        int             idx = 0;
1894
 
 
1895
 
                        sprintf((char*)tmp, "%d", v);
1896
 
                        Grow(info, strlen((char*)tmp));
1897
 
                        while (tmp[idx] != '\0')
1898
 
                          {
1899
 
                            info->t[info->offset++] = tmp[idx++];
1900
 
                          }
 
1960
                    if (fmtlen == 1) // no format width specified; supply default
 
1961
                      {
 
1962
                        fldfmt[fmtlen++] = '0';
 
1963
                        fldfmt[fmtlen++] = '4';
1901
1964
                      }
1902
1965
                  }
1903
1966
                else
1904
1967
                  {
1905
 
                    Grow(info, 2);
1906
1968
                    if (v < 0) v = -v;
1907
1969
                    v = v % 100;
1908
 
                    info->t[info->offset+1] = (v%10) + '0';
1909
 
                    v /= 10;
1910
 
                    info->t[info->offset+0] = (v%10) + '0';
1911
 
                    info->offset += 2;
 
1970
                    if (fmtlen == 1) // no format width specified; supply default
 
1971
                      {
 
1972
                        fldfmt[fmtlen++] = '0';
 
1973
                        fldfmt[fmtlen++] = '2';
 
1974
                      }
1912
1975
                  }
 
1976
                  fldfmt[fmtlen++] = 'd';
 
1977
                  fldfmt[fmtlen++] = 0;
 
1978
                  outputValueWithFormat(v, fldfmt, info);
1913
1979
                break;
1914
1980
 
1915
1981
                // is it the month
1944
2010
                if (mtag == NO)
1945
2011
                  {
1946
2012
                    v = info->md;
1947
 
                    Grow(info, 2);
1948
2013
                    v = v % 100;
1949
 
                    info->t[info->offset+1] = (v%10) + '0';
1950
 
                    v /= 10;
1951
 
                    info->t[info->offset+0] = (v%10) + '0';
1952
 
                    info->offset += 2;
 
2014
                    if (fmtlen == 1) // no format width specified; supply default
 
2015
                      {
 
2016
                        fldfmt[fmtlen++] = '0';
 
2017
                        fldfmt[fmtlen++] = '2';
 
2018
                      }
 
2019
                    fldfmt[fmtlen++] = 'd';
 
2020
                    fldfmt[fmtlen++] = 0;
 
2021
                    outputValueWithFormat(v, fldfmt, info);
1953
2022
                  }
1954
2023
                break;
1955
2024
 
1956
2025
              case 'd':         // day of month with leading zero
1957
2026
                v = info->dom;
1958
 
                Grow(info, 2);
1959
2027
                v = v % 100;
1960
 
                info->t[info->offset+1] = (v%10) + '0';
1961
 
                v /= 10;
1962
 
                info->t[info->offset+0] = (v%10) + '0';
1963
 
                info->offset += 2;
 
2028
                    if (fmtlen == 1) // no format width specified; supply default
 
2029
                      {
 
2030
                        fldfmt[fmtlen++] = '0';
 
2031
                        fldfmt[fmtlen++] = '2';
 
2032
                      }
 
2033
                    fldfmt[fmtlen++] = 'd';
 
2034
                    fldfmt[fmtlen++] = 0;
 
2035
                    outputValueWithFormat(v, fldfmt, info);
1964
2036
                break;
1965
2037
 
1966
2038
              case 'e':         // day of month with leading space
1967
2039
                v = info->dom;
1968
 
                Grow(info, 2);
1969
2040
                v = v % 100;
1970
 
                if (v%10 == '0')
1971
 
                  {
1972
 
                    info->t[info->offset+1] = ' ';
1973
 
                  }
1974
 
                else
1975
 
                  {
1976
 
                    info->t[info->offset+1] = (v%10) + '0';
1977
 
                  }
1978
 
                v /= 10;
1979
 
                info->t[info->offset+0] = (v%10) + '0';
1980
 
                info->offset += 2;
 
2041
                    if (fmtlen == 1) // no format width specified; supply default
 
2042
                      {
 
2043
                        fldfmt[fmtlen++] = '1'; // no leading space, just like Cocoa
 
2044
                      }
 
2045
                    fldfmt[fmtlen++] = 'd';
 
2046
                    fldfmt[fmtlen++] = 0;
 
2047
                    outputValueWithFormat(v, fldfmt, info);
1981
2048
                break;
1982
2049
 
1983
2050
              case 'F':         // milliseconds
1989
2056
                  s = fabs(s);
1990
2057
                  s -= floor(s);
1991
2058
                  s *= 1000.0;
1992
 
                  v = (int)(s + 0.5);
 
2059
                  v = (NSInteger)(s + 0.5);
1993
2060
                }
1994
 
                Grow(info, 3);
1995
 
                info->t[info->offset+2] = (v%10) + '0';
1996
 
                v /= 10;
1997
 
                info->t[info->offset+1] = (v%10) + '0';
1998
 
                v /= 10;
1999
 
                info->t[info->offset+0] = (v%10) + '0';
2000
 
                info->offset += 3;
 
2061
                if (fmtlen == 1) // no format width specified; supply default
 
2062
                  {
 
2063
                    fldfmt[fmtlen++] = '0';
 
2064
                    fldfmt[fmtlen++] = '3';
 
2065
                  }
 
2066
                fldfmt[fmtlen++] = 'd';
 
2067
                fldfmt[fmtlen++] = 0;
 
2068
                outputValueWithFormat(v, fldfmt, info);
2001
2069
                break;
2002
2070
 
2003
2071
              case 'j':         // day of year
2004
2072
                v = [self dayOfYear];
2005
 
                Grow(info, 3);
2006
 
                info->t[info->offset+2] = (v%10) + '0';
2007
 
                v /= 10;
2008
 
                info->t[info->offset+1] = (v%10) + '0';
2009
 
                v /= 10;
2010
 
                info->t[info->offset+0] = (v%10) + '0';
2011
 
                info->offset += 3;
 
2073
                if (fmtlen == 1) // no format width specified; supply default
 
2074
                  {
 
2075
                    fldfmt[fmtlen++] = '0';
 
2076
                    fldfmt[fmtlen++] = '3';
 
2077
                  }
 
2078
                fldfmt[fmtlen++] = 'd';
 
2079
                fldfmt[fmtlen++] = 0;
 
2080
                outputValueWithFormat(v, fldfmt, info);
2012
2081
                break;
2013
2082
 
2014
2083
                // is it the week-day
2044
2113
                    }
2045
2114
                  if (dtag == NO)
2046
2115
                    {
2047
 
                      info->t[info->offset+0] = (v%10) + '0';
2048
 
                      info->offset += 1;
 
2116
                      if (fmtlen == 1) // no format width specified; supply default
 
2117
                        {
 
2118
                          fldfmt[fmtlen++] = '1';
 
2119
                          }
 
2120
                      fldfmt[fmtlen++] = 'd';
 
2121
                      fldfmt[fmtlen++] = 0;
 
2122
                      outputValueWithFormat(v, fldfmt, info);
2049
2123
                    }
2050
2124
                }
2051
2125
                break;
2053
2127
                // is it the hour
2054
2128
              case 'I':
2055
2129
                twelve = YES;
 
2130
              case 'k':
 
2131
                if (twelve == NO)
 
2132
                  hspc = YES;
2056
2133
              case 'H':
2057
2134
                v = info->hd;
2058
2135
                if (twelve == YES)
2059
2136
                  {
2060
 
                    if (info->hd == 12)
 
2137
                    if (info->hd == 12 || info->hd == 0)
2061
2138
                      {
2062
2139
                        v = 12;
2063
2140
                      }
2066
2143
                        v = v % 12;
2067
2144
                      }
2068
2145
                  }
2069
 
                Grow(info, 2);
2070
 
                info->t[info->offset+1] = (v%10) + '0';
2071
 
                v /= 10;
2072
 
                info->t[info->offset+0] = (v%10) + '0';
2073
 
                info->offset += 2;
 
2146
                if (fmtlen == 1) // no format width specified; supply default
 
2147
                  {
 
2148
                    if (hspc == YES)
 
2149
                      fldfmt[fmtlen++] = '2'; // ensure a leading space
 
2150
                    else
 
2151
                      {
 
2152
                        fldfmt[fmtlen++] = '0';
 
2153
                        fldfmt[fmtlen++] = '2';
 
2154
                      }
 
2155
 
 
2156
                  }
 
2157
                fldfmt[fmtlen++] = 'd';
 
2158
                fldfmt[fmtlen++] = 0;
 
2159
                if (GSPrivateDefaultsFlag(GSMacOSXCompatible)
 
2160
                    && hspc == YES)
 
2161
                  {
 
2162
                    Grow(info, 2);
 
2163
                    info->t[info->offset++] = '%';
 
2164
                    info->t[info->offset++] = f[i-1];
 
2165
                    break;
 
2166
                  }
 
2167
                else
 
2168
                  outputValueWithFormat(v, fldfmt, info);
2074
2169
                break;
2075
2170
 
2076
2171
                // is it the minute
2077
2172
              case 'M':
2078
2173
                v = info->mnd;
2079
 
                Grow(info, 2);
2080
 
                info->t[info->offset+1] = (v%10) + '0';
2081
 
                v /= 10;
2082
 
                info->t[info->offset+0] = (v%10) + '0';
2083
 
                info->offset += 2;
 
2174
                if (fmtlen == 1) // no format width specified; supply default
 
2175
                  {
 
2176
                    fldfmt[fmtlen++] = '0';
 
2177
                    fldfmt[fmtlen++] = '2';
 
2178
                  }
 
2179
                fldfmt[fmtlen++] = 'd';
 
2180
                fldfmt[fmtlen++] = 0;
 
2181
                outputValueWithFormat(v, fldfmt, info);
2084
2182
                break;
2085
2183
 
2086
2184
                // is it the second
2087
2185
              case 'S':
2088
2186
                v = info->sd;
2089
 
                Grow(info, 2);
2090
 
                info->t[info->offset+1] = (v%10) + '0';
2091
 
                v /= 10;
2092
 
                info->t[info->offset+0] = (v%10) + '0';
2093
 
                info->offset += 2;
 
2187
                if (fmtlen == 1) // no format width specified; supply default
 
2188
                  {
 
2189
                    fldfmt[fmtlen++] = '0';
 
2190
                    fldfmt[fmtlen++] = '2';
 
2191
                  }
 
2192
                fldfmt[fmtlen++] = 'd';
 
2193
                fldfmt[fmtlen++] = 0;
 
2194
                outputValueWithFormat(v, fldfmt, info);
2094
2195
                break;
2095
2196
 
2096
2197
                // Is it the am/pm indicator
2204
2305
 *     %B   full month name according to locale
2205
2306
 *   </item>
2206
2307
 *   <item>
2207
 
 *     %d   day of month as decimal number (leading zero)
 
2308
 *     %d   day of month as two digit decimal number (leading zero)
2208
2309
 *   </item>
2209
2310
 *   <item>
2210
 
 *     %e   day of month as decimal number (leading space)
 
2311
 *     %e   day of month as decimal number (without leading zero)
2211
2312
 *   </item>
2212
2313
 *   <item>
2213
2314
 *     %F   milliseconds (000 to 999)
2222
2323
 *     %j   day of year as a decimal number
2223
2324
 *   </item>
2224
2325
 *   <item>
 
2326
 *     %k   same as %H with leading space instead of zero
 
2327
 *   </item>
 
2328
 *   <item>
2225
2329
 *     %m   month as decimal number
2226
2330
 *   </item>
2227
2331
 *   <item>
2264
2368
 *     %%   literal % character
2265
2369
 *   </item>
2266
2370
 * </list>
 
2371
 *
 
2372
 * <p>NB.  If GSMacOSCompatible is set to YES, the %k specifier is not
 
2373
 * recognized.</p>
2267
2374
 */
2268
2375
- (NSString*) descriptionWithCalendarFormat: (NSString*)format
2269
2376
                                     locale: (NSDictionary*)locale
2402
2509
/**
2403
2510
 * Returns the number of the last day of the month in the specified year.
2404
2511
 */
2405
 
- (int) lastDayOfGregorianMonth: (int)month year: (int)year
 
2512
- (NSInteger) lastDayOfGregorianMonth: (NSInteger)month year: (NSInteger)year
2406
2513
{
2407
2514
  return lastDayOfGregorianMonth(month, year);
2408
2515
}
2411
2518
 * Returns the number of days since the start of the era for the specified
2412
2519
 * day, month, and year.
2413
2520
 */
2414
 
- (int) absoluteGregorianDay: (int)day month: (int)month year: (int)year
 
2521
- (NSInteger) absoluteGregorianDay: (NSInteger)day
 
2522
                             month: (NSInteger)month
 
2523
                              year: (NSInteger)year
2415
2524
{
2416
2525
  return absoluteGregorianDay(day, month, year);
2417
2526
}
2420
2529
 * Given a day number since the start of the era, returns the date as a
2421
2530
 * day, month, and year.
2422
2531
 */
2423
 
- (void) gregorianDateFromAbsolute: (int)d
2424
 
                               day: (int *)day
2425
 
                             month: (int *)month
2426
 
                              year: (int *)year
 
2532
- (void) gregorianDateFromAbsolute: (NSInteger)d
 
2533
                               day: (NSInteger *)day
 
2534
                             month: (NSInteger *)month
 
2535
                              year: (NSInteger *)year
2427
2536
{
2428
 
  gregorianDateFromAbsolute(d, day, month, year);
 
2537
  int   dd, mm, yy;
 
2538
 
 
2539
  gregorianDateFromAbsolute(d, &dd, &mm, &yy);
 
2540
  *day = dd;
 
2541
  *month = mm;
 
2542
  *year = yy;
2429
2543
}
2430
2544
 
2431
2545
@end
2436
2550
 */
2437
2551
@implementation NSCalendarDate (OPENSTEP)
2438
2552
 
2439
 
/**
2440
 
 * <p>Returns a calendar date formed by adding the specified offsets to the
2441
 
 * receiver.  The offsets are added in order, years, then months, then
2442
 
 * days, then hours then minutes then seconds, so if you add 1 month and
2443
 
 * forty days to 20th September, the result will be 9th November.
2444
 
 * </p>
2445
 
 * <p>This method understands leap years and tries to adjust for daylight
2446
 
 * savings time changes so that it preserves expected clock time.
2447
 
 * </p>
2448
 
 */
2449
 
- (NSCalendarDate*) dateByAddingYears: (int)years
2450
 
                               months: (int)months
2451
 
                                 days: (int)days
2452
 
                                hours: (int)hours
2453
 
                              minutes: (int)minutes
2454
 
                              seconds: (int)seconds
 
2553
- (NSCalendarDate*) dateByAddingYears: (NSInteger)years
 
2554
                               months: (NSInteger)months
 
2555
                                 days: (NSInteger)days
 
2556
                                hours: (NSInteger)hours
 
2557
                              minutes: (NSInteger)minutes
 
2558
                              seconds: (NSInteger)seconds
2455
2559
{
2456
2560
  NSCalendarDate        *c;
2457
2561
  NSTimeInterval        s;
2561
2665
   */
2562
2666
  s = GSTime(day, month, year, hour, minute, second, mil);
2563
2667
  s -= oldOffset;
2564
 
  c = [NSCalendarDate alloc];
2565
 
  c->_calendar_format = cformat;
2566
 
  c->_time_zone = RETAIN([self timeZone]);
 
2668
  c = [NSCalendarDateClass alloc];
 
2669
  c->_calendar_format = [_calendar_format copy];
 
2670
  c->_time_zone = [_time_zone copy];
2567
2671
  c->_seconds_since_ref = s;
2568
2672
 
2569
2673
  /*
2603
2707
 * hours is null, then the value returned in minutes will be increased
2604
2708
 * by 60.
2605
2709
 */
2606
 
- (void) years: (int*)years
2607
 
        months: (int*)months
2608
 
          days: (int*)days
2609
 
         hours: (int*)hours
2610
 
       minutes: (int*)minutes
2611
 
       seconds: (int*)seconds
 
2710
- (void) years: (NSInteger*)years
 
2711
        months: (NSInteger*)months
 
2712
          days: (NSInteger*)days
 
2713
         hours: (NSInteger*)hours
 
2714
       minutes: (NSInteger*)minutes
 
2715
       seconds: (NSInteger*)seconds
2612
2716
     sinceDate: (NSDate*)date
2613
2717
{
2614
2718
  NSCalendarDate        *start;
2624
2728
  /* FIXME What if the two dates are in different time zones?
2625
2729
    How about daylight savings time?
2626
2730
   */
2627
 
  if ([date isKindOfClass: [NSCalendarDate class]])
 
2731
  if ([date isKindOfClass: NSCalendarDateClass])
2628
2732
    {
2629
2733
      tmp = (NSCalendarDate*)RETAIN(date);
2630
2734
    }
2631
2735
  else if ([date isKindOfClass: [NSDate class]])
2632
2736
    {
2633
 
      tmp = [[NSCalendarDate alloc] initWithTimeIntervalSinceReferenceDate:
 
2737
      tmp = [[NSCalendarDateClass alloc] initWithTimeIntervalSinceReferenceDate:
2634
2738
        [date timeIntervalSinceReferenceDate]];
2635
2739
    }
2636
2740
  else