1997-09-01 21:59:51 +00:00
|
|
|
|
/* Time zone management. -*- Mode: ObjC -*-
|
|
|
|
|
Copyright (C) 1997 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
|
|
Written by: Yoo C. Chung <wacko@laplace.snu.ac.kr>
|
|
|
|
|
Date: June 1997
|
|
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
1997-10-17 13:35:52 +00:00
|
|
|
|
This library is free software; you can redistribute it and/or
|
1997-09-01 21:59:51 +00:00
|
|
|
|
modify it under the terms of the GNU Library General Public License
|
|
|
|
|
as published by the Free Software Foundation; either version 2 of
|
|
|
|
|
the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful, but
|
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
1997-10-17 13:35:52 +00:00
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1997-10-17 13:35:52 +00:00
|
|
|
|
You should have received a copy of the GNU Library General Public
|
1997-09-01 21:59:51 +00:00
|
|
|
|
License along with this library; if not, write to the Free Software
|
1999-08-25 16:12:36 +00:00
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
/* We use a implementation independent of the system, since POSIX
|
|
|
|
|
functions for time zones are woefully inadequate for implementing
|
|
|
|
|
NSTimeZone, and time zone names can be different from system to
|
|
|
|
|
system.
|
|
|
|
|
|
|
|
|
|
We do not use a dictionary for storing time zones, since such a
|
|
|
|
|
dictionary would be VERY large (~500K). And we would have to use a
|
|
|
|
|
complicated object determining whether we're using daylight savings
|
1997-11-03 14:30:13 +00:00
|
|
|
|
time and such for every entry in the dictionary. (Though we will
|
|
|
|
|
eventually have to change the implementation to prevent the year
|
|
|
|
|
2038 problem.)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
The local time zone can be specified with the user defaults
|
2000-01-05 14:53:03 +00:00
|
|
|
|
database, the GNUSTEP_TZ environment variable, the file LOCAL_TIME_FILE,
|
|
|
|
|
the TZ environment variable, or the fallback time zone (which is UTC),
|
|
|
|
|
with the ones listed first having precedence.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
Any time zone must be a file name in ZONES_DIR.
|
|
|
|
|
|
|
|
|
|
FIXME?: use leap seconds? */
|
|
|
|
|
|
1997-11-06 00:51:23 +00:00
|
|
|
|
#include <config.h>
|
1998-12-20 21:27:47 +00:00
|
|
|
|
#include <base/preface.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <Foundation/NSArray.h>
|
|
|
|
|
#include <Foundation/NSCoder.h>
|
2001-01-31 15:10:41 +00:00
|
|
|
|
#include <Foundation/NSData.h>
|
1997-10-17 13:35:52 +00:00
|
|
|
|
#include <Foundation/NSDate.h>
|
|
|
|
|
#include <Foundation/NSDictionary.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#include <Foundation/NSException.h>
|
|
|
|
|
#include <Foundation/NSLock.h>
|
|
|
|
|
#include <Foundation/NSObject.h>
|
|
|
|
|
#include <Foundation/NSProcessInfo.h>
|
1997-10-17 13:35:52 +00:00
|
|
|
|
#include <Foundation/NSString.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#include <Foundation/NSUserDefaults.h>
|
|
|
|
|
#include <Foundation/NSUtilities.h>
|
|
|
|
|
#include <Foundation/NSZone.h>
|
1997-10-18 19:49:50 +00:00
|
|
|
|
#include <Foundation/NSBundle.h>
|
1999-08-25 16:12:36 +00:00
|
|
|
|
#include <Foundation/NSMapTable.h>
|
2001-01-30 20:47:05 +00:00
|
|
|
|
#include <Foundation/NSThread.h>
|
|
|
|
|
#include <Foundation/NSNotification.h>
|
2001-01-31 05:58:59 +00:00
|
|
|
|
#include <Foundation/NSPortCoder.h>
|
2001-03-08 14:48:27 +00:00
|
|
|
|
#include <Foundation/NSTimeZone.h>
|
2001-01-31 11:29:55 +00:00
|
|
|
|
#include <Foundation/NSDebug.h>
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
#define NOID
|
|
|
|
|
#include "tzfile.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Key for local time zone in user defaults. */
|
1997-11-28 20:13:58 +00:00
|
|
|
|
#define LOCALDBKEY @"Local Time Zone"
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* Directory that contains the time zone data. */
|
1999-04-23 02:54:45 +00:00
|
|
|
|
#define TIME_ZONE_DIR @"NSTimeZones"
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* Location of time zone abbreviation dictionary. It is a text file
|
|
|
|
|
with each line comprised of the abbreviation, a whitespace, and the
|
|
|
|
|
name. Neither the abbreviation nor the name can contain
|
|
|
|
|
whitespace, and each line must not be longer than 80 characters. */
|
1997-10-18 19:49:50 +00:00
|
|
|
|
#define ABBREV_DICT @"abbreviations"
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* File holding regions grouped by latitude. It is a text file with
|
|
|
|
|
each line comprised of the latitude region, whitespace, and the
|
1997-11-03 14:30:13 +00:00
|
|
|
|
name. Neither the abbreviation nor the name can contain
|
1997-09-01 21:59:51 +00:00
|
|
|
|
whitespace, and each line must not be longer than 80 characters. */
|
1997-10-18 19:49:50 +00:00
|
|
|
|
#define REGIONS_FILE @"regions"
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1997-10-17 13:35:52 +00:00
|
|
|
|
/* Name of the file that contains the name of the local time zone. */
|
1997-10-18 19:49:50 +00:00
|
|
|
|
#define LOCAL_TIME_FILE @"localtime"
|
1997-10-17 13:35:52 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* Directory that contains the actual time zones. */
|
1997-11-28 20:13:58 +00:00
|
|
|
|
#define ZONES_DIR @"zones/"
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@class NSInternalTimeTransition;
|
|
|
|
|
@class NSConcreteTimeZone;
|
|
|
|
|
@class NSConcreteAbsoluteTimeZone;
|
|
|
|
|
@class NSConcreteTimeZoneDetail;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
@class GSPlaceholderTimeZone;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Information for abstract placeholder class.
|
|
|
|
|
*/
|
|
|
|
|
static GSPlaceholderTimeZone *defaultPlaceholderTimeZone;
|
|
|
|
|
static NSMapTable *placeholderMap;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* Temporary structure for holding time zone details. */
|
|
|
|
|
struct ttinfo
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-31 15:10:41 +00:00
|
|
|
|
char offset[4]; // Seconds east of UTC
|
1997-09-01 21:59:51 +00:00
|
|
|
|
BOOL isdst; // Daylight savings time?
|
|
|
|
|
char abbr_idx; // Index into time zone abbreviations string
|
|
|
|
|
};
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
static NSTimeZone *defaultTimeZone = nil;
|
|
|
|
|
static NSTimeZone *localTimeZone = nil;
|
|
|
|
|
static NSTimeZone *systemTimeZone = nil;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* Dictionary for time zones. Each time zone must have a unique
|
|
|
|
|
name. */
|
|
|
|
|
static NSMutableDictionary *zoneDictionary;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* Fake one-to-one abbreviation to time zone name dictionary. */
|
|
|
|
|
static NSDictionary *fake_abbrev_dict;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* Lock for creating time zones. */
|
2001-01-30 20:47:05 +00:00
|
|
|
|
static NSRecursiveLock *zone_mutex = nil;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
static Class NSTimeZoneClass;
|
2001-01-31 11:29:55 +00:00
|
|
|
|
static Class GSPlaceholderTimeZoneClass;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* Decode the four bytes at PTR as a signed integer in network byte order.
|
|
|
|
|
Based on code included in the GNU C Library 2.0.3. */
|
|
|
|
|
static inline int
|
|
|
|
|
decode (const void *ptr)
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#if defined(WORDS_BIGENDIAN) && SIZEOF_INT == 4
|
2001-03-23 18:48:55 +00:00
|
|
|
|
#if NEED_WORD_ALIGNMENT
|
|
|
|
|
int value;
|
|
|
|
|
memcpy(&value, ptr, sizeof(int));
|
|
|
|
|
return value;
|
|
|
|
|
#else
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return *(const int *) ptr;
|
2001-03-23 18:48:55 +00:00
|
|
|
|
#endif
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#else /* defined(WORDS_BIGENDIAN) && SIZEOF_INT == 4 */
|
|
|
|
|
const unsigned char *p = ptr;
|
|
|
|
|
int result = *p & (1 << (CHAR_BIT - 1)) ? ~0 : 0;
|
|
|
|
|
|
|
|
|
|
result = (result << 8) | *p++;
|
|
|
|
|
result = (result << 8) | *p++;
|
|
|
|
|
result = (result << 8) | *p++;
|
|
|
|
|
result = (result << 8) | *p++;
|
|
|
|
|
return result;
|
|
|
|
|
#endif /* defined(WORDS_BIGENDIAN) && SIZEOF_INT == 4 */
|
|
|
|
|
}
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
|
|
|
|
|
1997-11-03 14:30:13 +00:00
|
|
|
|
/* Object enumerator for NSInternalAbbrevDict. */
|
|
|
|
|
@interface NSInternalAbbrevDictObjectEnumerator : NSEnumerator
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *dict_enum;
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (id) initWithDict: (NSDictionary*)aDict;
|
1997-11-03 14:30:13 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* Front end that actually uses [NSTimeZone abbrebiationMap]. */
|
|
|
|
|
@interface NSInternalAbbrevDict : NSDictionary
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@interface NSInternalTimeTransition : NSObject
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
int trans_time; // When the transition occurs
|
|
|
|
|
char detail_index; // Index of time zone detail
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (id) initWithTime: (int)aTime withIndex: (char)anIndex;
|
|
|
|
|
- (int) transTime;
|
|
|
|
|
- (char) detailIndex;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
@interface GSPlaceholderTimeZone : NSTimeZone
|
|
|
|
|
@end
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
@interface NSConcreteTimeZone : NSTimeZone
|
|
|
|
|
{
|
2001-01-31 11:29:55 +00:00
|
|
|
|
NSString *name;
|
|
|
|
|
NSArray *transitions; // Transition times and rules
|
|
|
|
|
NSArray *details; // Time zone details
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (id) initWithName: (NSString*)aName
|
|
|
|
|
withTransitions: (NSArray*)trans
|
|
|
|
|
withDetails: (NSArray*)zoneDetails;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
@end
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@interface NSConcreteAbsoluteTimeZone : NSTimeZone
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSString *name;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
id detail;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
int offset; // Offset from UTC in seconds.
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (id) initWithOffset: (int)anOffset;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
@end
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
@interface NSLocalTimeZone : NSTimeZone
|
|
|
|
|
@end
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
@interface NSConcreteTimeZoneDetail : NSTimeZoneDetail
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
1997-10-24 16:58:20 +00:00
|
|
|
|
NSTimeZone *timeZone; // Time zone which created this object.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
NSString *abbrev; // Abbreviation for time zone detail.
|
|
|
|
|
int offset; // Offset from UTC in seconds.
|
|
|
|
|
BOOL is_dst; // Is it daylight savings time?
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (id) initWithTimeZone: (NSTimeZone*)aZone
|
|
|
|
|
withAbbrev: (NSString*)anAbbrev
|
|
|
|
|
withOffset: (int)anOffset
|
|
|
|
|
withDST: (BOOL)isDST;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
@end
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1997-11-03 14:30:13 +00:00
|
|
|
|
/* Private methods for obtaining resource file names. */
|
|
|
|
|
@interface NSTimeZone (Private)
|
2001-01-30 20:47:05 +00:00
|
|
|
|
+ (void) _becomeThreaded: (NSNotification*)notification;
|
1999-08-25 16:12:36 +00:00
|
|
|
|
+ (NSString*) getAbbreviationFile;
|
|
|
|
|
+ (NSString*) getRegionsFile;
|
|
|
|
|
+ (NSString*) getTimeZoneFile: (NSString*)name;
|
1997-11-03 14:30:13 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSInternalAbbrevDictObjectEnumerator
|
|
|
|
|
|
1999-05-27 09:52:49 +00:00
|
|
|
|
- (void) dealloc
|
1997-11-03 14:30:13 +00:00
|
|
|
|
{
|
1999-05-27 09:52:49 +00:00
|
|
|
|
RELEASE(dict_enum);
|
1997-11-03 14:30:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-05-27 09:52:49 +00:00
|
|
|
|
- (id) initWithDict: (NSDictionary*)aDict
|
1997-11-03 14:30:13 +00:00
|
|
|
|
{
|
1999-05-27 09:52:49 +00:00
|
|
|
|
dict_enum = RETAIN([aDict objectEnumerator]);
|
1997-11-03 14:30:13 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1999-05-27 09:52:49 +00:00
|
|
|
|
- (id) nextObject
|
1997-11-03 14:30:13 +00:00
|
|
|
|
{
|
|
|
|
|
id object;
|
|
|
|
|
|
|
|
|
|
object = [dict_enum nextObject];
|
|
|
|
|
if (object != nil)
|
|
|
|
|
return [object objectAtIndex: 0];
|
|
|
|
|
else
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@implementation NSInternalAbbrevDict
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)zone
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return NSAllocateObject(self, 0, zone);
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
1999-05-27 09:52:49 +00:00
|
|
|
|
- (id) init
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return self;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (unsigned) count
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return [[NSTimeZone abbreviationMap] count];
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-05-27 09:52:49 +00:00
|
|
|
|
- (NSEnumerator*) keyEnumerator
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return [[NSTimeZone abbreviationMap] keyEnumerator];
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
1999-05-27 09:52:49 +00:00
|
|
|
|
- (NSEnumerator*) objectEnumerator
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1999-05-27 09:52:49 +00:00
|
|
|
|
return AUTORELEASE([[NSInternalAbbrevDictObjectEnumerator alloc]
|
|
|
|
|
initWithDict: [NSTimeZone abbreviationMap]]);
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-05-27 09:52:49 +00:00
|
|
|
|
- (id) objectForKey: (NSString*)key
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return [[[NSTimeZone abbreviationMap] objectForKey: key] objectAtIndex: 0];
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1997-10-17 13:35:52 +00:00
|
|
|
|
@end
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSInternalTimeTransition
|
|
|
|
|
|
1999-05-27 09:52:49 +00:00
|
|
|
|
- (NSString*) description
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1999-08-25 16:12:36 +00:00
|
|
|
|
return [NSString stringWithFormat: @"%@(%d, %d)",
|
|
|
|
|
[self class], trans_time, (int)detail_index];
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (id) initWithTime: (int)aTime withIndex: (char)anIndex
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
[super init];
|
|
|
|
|
trans_time = aTime;
|
|
|
|
|
detail_index = anIndex;
|
|
|
|
|
return self;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (int) transTime
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return trans_time;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (char) detailIndex
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return detail_index;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1997-10-17 13:35:52 +00:00
|
|
|
|
@end
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
|
|
|
|
@implementation GSPlaceholderTimeZone
|
|
|
|
|
|
|
|
|
|
- (id) autorelease
|
|
|
|
|
{
|
|
|
|
|
NSWarnLog(@"-autorelease sent to uninitialised time zone");
|
|
|
|
|
return self; // placeholders never get released.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) objectAtIndex: (unsigned)index
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"attempt to use uninitialised time zone"];
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
return; // placeholders never get deallocated.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithName: (NSString*)name
|
|
|
|
|
{
|
|
|
|
|
NSTimeZone *zone;
|
|
|
|
|
|
2001-01-31 15:10:41 +00:00
|
|
|
|
/*
|
|
|
|
|
* Quick return if it's the local timezone.
|
|
|
|
|
*/
|
2001-01-31 11:29:55 +00:00
|
|
|
|
if ([name isEqual: @"NSLocalTimeZone"])
|
|
|
|
|
{
|
2001-01-31 15:10:41 +00:00
|
|
|
|
return [self initWithName: name data: nil];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-31 15:10:41 +00:00
|
|
|
|
/*
|
|
|
|
|
* Return a chached time zone if possible.
|
|
|
|
|
*/
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
|
|
|
|
zone = [zoneDictionary objectForKey: name];
|
|
|
|
|
if (zone != nil)
|
|
|
|
|
{
|
|
|
|
|
IF_NO_GC(RETAIN(zone));
|
2001-01-31 11:29:55 +00:00
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
2001-01-31 15:10:41 +00:00
|
|
|
|
[zone_mutex unlock];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
}
|
2001-01-31 15:10:41 +00:00
|
|
|
|
return zone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now return an absolute time zone or load one from file.
|
|
|
|
|
*/
|
|
|
|
|
if ([name hasPrefix: @"NSAbsoluteTimeZone:"] == YES)
|
|
|
|
|
{
|
|
|
|
|
int i = [[name substringFromIndex: 19] intValue];
|
|
|
|
|
|
|
|
|
|
zone = [[NSConcreteAbsoluteTimeZone alloc] initWithOffset: i];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSString *fileName;
|
|
|
|
|
NSData *data;
|
|
|
|
|
unsigned length;
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
2001-01-31 15:10:41 +00:00
|
|
|
|
length = [name length];
|
|
|
|
|
if (length == 0)
|
2001-01-31 11:29:55 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"Disallowed null time zone name");
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const char *str = [name lossyCString];
|
|
|
|
|
|
|
|
|
|
/* Make sure that only time zone files are accessed.
|
|
|
|
|
FIXME: Make this more robust. */
|
|
|
|
|
if ((str)[0] == '/' || strchr(str, '.') != NULL)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"Disallowed time zone name `%@'.", name);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-31 15:10:41 +00:00
|
|
|
|
fileName = [NSTimeZoneClass getTimeZoneFile: name];
|
|
|
|
|
if (fileName == nil)
|
2001-01-31 11:29:55 +00:00
|
|
|
|
{
|
2001-01-31 15:10:41 +00:00
|
|
|
|
NSLog(@"Unknown time zone name `%@'.", name);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
data = [NSData dataWithContentsOfFile: fileName];
|
|
|
|
|
zone = [self initWithName: name data: data];
|
|
|
|
|
}
|
|
|
|
|
return zone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithName: (NSString*)name data: (NSData*)data
|
|
|
|
|
{
|
|
|
|
|
NSTimeZone *zone;
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
2001-01-31 15:10:41 +00:00
|
|
|
|
if ([name isEqual: @"NSLocalTimeZone"])
|
|
|
|
|
{
|
|
|
|
|
zone = RETAIN(localTimeZone);
|
|
|
|
|
}
|
|
|
|
|
else if ([name hasPrefix: @"NSAbsoluteTimeZone:"] == YES)
|
|
|
|
|
{
|
|
|
|
|
int i = [[name substringFromIndex: 19] intValue];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
2001-01-31 15:10:41 +00:00
|
|
|
|
zone = [[NSConcreteAbsoluteTimeZone alloc] initWithOffset: i];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
static NSString *fileException = @"fileException";
|
|
|
|
|
static NSString *errMess = @"File read error in NSTimeZone.";
|
|
|
|
|
|
|
|
|
|
zone = nil;
|
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
const void *bytes = [data bytes];
|
|
|
|
|
unsigned length = [data length];
|
|
|
|
|
unsigned pos = 0;
|
|
|
|
|
id transArray;
|
|
|
|
|
id detailsArray;
|
|
|
|
|
int i, n_trans, n_types, names_size;
|
|
|
|
|
id *abbrevsArray;
|
|
|
|
|
char *trans;
|
|
|
|
|
char *type_idxs;
|
|
|
|
|
char *zone_abbrevs;
|
|
|
|
|
struct tzhead *header;
|
|
|
|
|
struct ttinfo *types; // Temporary array for details
|
|
|
|
|
|
|
|
|
|
if (length < sizeof(struct tzhead))
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: fileException format: errMess];
|
|
|
|
|
}
|
|
|
|
|
header = (struct tzhead *)(bytes + pos);
|
|
|
|
|
pos += sizeof(struct tzhead);
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
2001-01-31 15:10:41 +00:00
|
|
|
|
n_trans = decode(header->tzh_timecnt);
|
|
|
|
|
n_types = decode(header->tzh_typecnt);
|
|
|
|
|
names_size = decode(header->tzh_charcnt);
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
|
|
|
|
/* Read in transitions. */
|
2001-01-31 15:10:41 +00:00
|
|
|
|
trans = (char*)(bytes + pos);
|
|
|
|
|
pos += 4*n_trans;
|
|
|
|
|
type_idxs = (char*)(bytes + pos);
|
|
|
|
|
pos += n_trans;
|
|
|
|
|
if (pos > length)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: fileException format: errMess];
|
|
|
|
|
}
|
2001-01-31 11:29:55 +00:00
|
|
|
|
transArray = [NSMutableArray arrayWithCapacity: n_trans];
|
|
|
|
|
for (i = 0; i < n_trans; i++)
|
2001-01-31 15:10:41 +00:00
|
|
|
|
{
|
|
|
|
|
[transArray
|
|
|
|
|
addObject: [[NSInternalTimeTransition alloc]
|
2001-01-31 11:29:55 +00:00
|
|
|
|
initWithTime: decode(trans+(i*4))
|
|
|
|
|
withIndex: type_idxs[i]]];
|
2001-01-31 15:10:41 +00:00
|
|
|
|
}
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
|
|
|
|
/* Read in time zone details. */
|
2001-01-31 15:10:41 +00:00
|
|
|
|
types = (struct ttinfo*)(bytes + pos);
|
|
|
|
|
pos += n_types*sizeof(struct ttinfo);
|
|
|
|
|
if (pos > length)
|
2001-01-31 11:29:55 +00:00
|
|
|
|
{
|
2001-01-31 15:10:41 +00:00
|
|
|
|
[NSException raise: fileException format: errMess];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read in time zone abbreviation strings. */
|
2001-01-31 15:10:41 +00:00
|
|
|
|
zone_abbrevs = (char*)(bytes + pos);
|
|
|
|
|
pos += names_size;
|
|
|
|
|
if (pos > length)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: fileException format: errMess];
|
|
|
|
|
}
|
2001-01-31 11:29:55 +00:00
|
|
|
|
abbrevsArray = NSZoneMalloc(NSDefaultMallocZone(),
|
|
|
|
|
sizeof(id)*names_size);
|
|
|
|
|
memset(abbrevsArray, '\0', sizeof(id)*names_size);
|
|
|
|
|
for (i = 0; i < n_types; i++)
|
|
|
|
|
{
|
2001-01-31 15:10:41 +00:00
|
|
|
|
struct ttinfo *inf = types + i;
|
|
|
|
|
int loc = inf->abbr_idx;
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
2001-01-31 15:10:41 +00:00
|
|
|
|
if (abbrevsArray[loc] == nil)
|
2001-01-31 11:29:55 +00:00
|
|
|
|
{
|
2001-01-31 15:10:41 +00:00
|
|
|
|
abbrevsArray[loc]
|
|
|
|
|
= [NSString stringWithCString: zone_abbrevs+loc];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-31 15:10:41 +00:00
|
|
|
|
|
|
|
|
|
zone = [NSConcreteTimeZone alloc];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
|
|
|
|
/* Create time zone details. */
|
|
|
|
|
detailsArray = [NSMutableArray arrayWithCapacity: n_types];
|
|
|
|
|
for (i = 0; i < n_types; i++)
|
|
|
|
|
{
|
|
|
|
|
NSConcreteTimeZoneDetail *detail;
|
2001-01-31 15:10:41 +00:00
|
|
|
|
struct ttinfo *inf = types + i;
|
|
|
|
|
int off = decode(inf->offset);
|
|
|
|
|
BOOL dst = (inf->isdst > 0) ? YES : NO;
|
|
|
|
|
int idx = inf->abbr_idx;
|
|
|
|
|
id abr = abbrevsArray[idx];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
|
|
|
|
detail = [[NSConcreteTimeZoneDetail alloc]
|
|
|
|
|
initWithTimeZone: zone
|
2001-01-31 15:10:41 +00:00
|
|
|
|
withAbbrev: abr
|
|
|
|
|
withOffset: off
|
|
|
|
|
withDST: dst];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
[detailsArray addObject: detail];
|
|
|
|
|
RELEASE(detail);
|
|
|
|
|
}
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), abbrevsArray);
|
|
|
|
|
|
|
|
|
|
zone = [(id)zone initWithName: name
|
|
|
|
|
withTransitions: transArray
|
|
|
|
|
withDetails: detailsArray];
|
2001-01-31 15:10:41 +00:00
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
2001-01-31 11:29:55 +00:00
|
|
|
|
[zoneDictionary setObject: zone forKey: (NSString*)[zone name]];
|
2001-01-31 15:10:41 +00:00
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
2001-01-31 11:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
DESTROY(zone);
|
|
|
|
|
if ([localException name] != fileException)
|
|
|
|
|
[localException raise];
|
|
|
|
|
NSLog(@"Unable to obtain time zone `%@'.", name);
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return zone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) release
|
|
|
|
|
{
|
|
|
|
|
return; // placeholders never get released.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) retain
|
|
|
|
|
{
|
|
|
|
|
return self; // placeholders never get retained.
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSConcreteTimeZone
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (void) dealloc
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1999-05-27 09:52:49 +00:00
|
|
|
|
RELEASE(name);
|
|
|
|
|
RELEASE(transitions);
|
|
|
|
|
RELEASE(details);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[super dealloc];
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
1999-05-27 09:52:49 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-31 11:29:55 +00:00
|
|
|
|
[aCoder encodeObject: name];
|
1998-03-12 14:21:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (id) initWithName: (NSString*)aName
|
|
|
|
|
withTransitions: (NSArray*)trans
|
|
|
|
|
withDetails: (NSArray*)zoneDetails
|
1998-03-12 14:21:20 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
self = [super init];
|
|
|
|
|
if (self != nil)
|
1999-05-27 09:52:49 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
name = [aName copyWithZone: [self zone]];
|
|
|
|
|
transitions = RETAIN(trans);
|
|
|
|
|
details = RETAIN(zoneDetails);
|
1999-05-27 09:52:49 +00:00
|
|
|
|
}
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return self;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSString*) name
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return name;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSArray*) timeZoneDetailArray
|
|
|
|
|
{
|
|
|
|
|
return details;
|
|
|
|
|
}
|
|
|
|
|
|
1999-05-27 09:52:49 +00:00
|
|
|
|
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)date
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
unsigned index;
|
|
|
|
|
int the_time;
|
|
|
|
|
unsigned count;
|
|
|
|
|
|
|
|
|
|
the_time = (int)[date timeIntervalSince1970];
|
|
|
|
|
count = [transitions count];
|
|
|
|
|
if (count == 0
|
|
|
|
|
|| the_time < [[transitions objectAtIndex: 0] transTime])
|
|
|
|
|
/* Either DATE is before any transitions or there is no transition.
|
|
|
|
|
Return the first non-DST type, or the first one if they are all DST. */
|
|
|
|
|
{
|
|
|
|
|
unsigned detail_count;
|
|
|
|
|
|
|
|
|
|
detail_count = [details count];
|
|
|
|
|
index = 0;
|
|
|
|
|
while (index < detail_count
|
1999-05-27 09:52:49 +00:00
|
|
|
|
&& [[details objectAtIndex: index] isDaylightSavingTimeZone])
|
1997-09-01 21:59:51 +00:00
|
|
|
|
index++;
|
|
|
|
|
if (index == detail_count)
|
|
|
|
|
index = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* Find the first transition after DATE, and then pick the type of
|
|
|
|
|
the transition before it. */
|
|
|
|
|
{
|
|
|
|
|
for (index = 1; index < count; index++)
|
|
|
|
|
if (the_time < [[transitions objectAtIndex: index] transTime])
|
|
|
|
|
break;
|
|
|
|
|
index = [[transitions objectAtIndex: index-1] detailIndex];
|
|
|
|
|
}
|
|
|
|
|
return [details objectAtIndex: index];
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1997-10-17 13:35:52 +00:00
|
|
|
|
@end
|
2001-01-30 20:47:05 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSLocalTimeZone
|
|
|
|
|
|
|
|
|
|
- (id) autorelease
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
2001-01-30 20:47:05 +00:00
|
|
|
|
{
|
2001-01-31 11:29:55 +00:00
|
|
|
|
[aCoder encodeObject: @"NSLocalTimeZone"];
|
2001-01-30 20:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
- (NSString*) name
|
2001-01-30 20:47:05 +00:00
|
|
|
|
{
|
2001-01-31 11:29:55 +00:00
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] name];
|
2001-01-30 20:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
- (void) release
|
2001-01-30 20:47:05 +00:00
|
|
|
|
{
|
2001-01-31 11:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) retain
|
|
|
|
|
{
|
|
|
|
|
return self;
|
2001-01-30 20:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray*) timeZoneDetailArray
|
|
|
|
|
{
|
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] timeZoneDetailArray];
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)date
|
|
|
|
|
{
|
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] timeZoneDetailForDate: date];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSConcreteAbsoluteTimeZone
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
static NSMapTable *absolutes = 0;
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-08-25 16:12:36 +00:00
|
|
|
|
if (self == [NSConcreteAbsoluteTimeZone class])
|
|
|
|
|
{
|
|
|
|
|
absolutes = NSCreateMapTable(NSIntMapKeyCallBacks,
|
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2001-01-30 20:47:05 +00:00
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex lock];
|
2001-01-30 12:05:02 +00:00
|
|
|
|
NSMapRemove(absolutes, (void*)(gsaddr)offset);
|
2001-01-30 20:47:05 +00:00
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex unlock];
|
2001-01-30 12:05:02 +00:00
|
|
|
|
RELEASE(name);
|
|
|
|
|
RELEASE(detail);
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
|
|
|
|
{
|
|
|
|
|
[aCoder encodeObject: name];
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (id) initWithOffset: (int)anOffset
|
|
|
|
|
{
|
|
|
|
|
NSConcreteAbsoluteTimeZone *z;
|
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex lock];
|
1999-08-25 16:12:36 +00:00
|
|
|
|
z = (NSConcreteAbsoluteTimeZone*)NSMapGet(absolutes, (void*)(gsaddr)anOffset);
|
|
|
|
|
if (z)
|
|
|
|
|
{
|
1999-09-28 19:35:09 +00:00
|
|
|
|
IF_NO_GC(RETAIN(z));
|
1999-08-25 16:12:36 +00:00
|
|
|
|
RELEASE(self);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2001-01-31 15:10:41 +00:00
|
|
|
|
self = [super init];
|
|
|
|
|
if (self != nil)
|
|
|
|
|
{
|
|
|
|
|
name = [[NSString alloc] initWithFormat: @"NSAbsoluteTimeZone:%d",
|
|
|
|
|
anOffset];
|
|
|
|
|
detail = [[NSConcreteTimeZoneDetail alloc]
|
|
|
|
|
initWithTimeZone: self withAbbrev: name
|
|
|
|
|
withOffset: anOffset withDST: NO];
|
|
|
|
|
offset = anOffset;
|
|
|
|
|
z = self;
|
|
|
|
|
NSMapInsert(absolutes, (void*)(gsaddr)anOffset, (void*)z);
|
|
|
|
|
[zoneDictionary setObject: self forKey: (NSString*)name];
|
|
|
|
|
}
|
1999-08-25 16:12:36 +00:00
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex unlock];
|
1999-08-25 16:12:36 +00:00
|
|
|
|
return z;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSString*) name
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return name;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
- (NSTimeZone*) timeZoneDetailTimeZone
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
2001-01-31 11:29:55 +00:00
|
|
|
|
return [NSTimeZone arrayWithObject: detail];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)date
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
|
|
|
|
return detail;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSConcreteTimeZoneDetail
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (void) dealloc
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1999-05-27 09:52:49 +00:00
|
|
|
|
RELEASE(timeZone);
|
|
|
|
|
RELEASE(abbrev);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
2000-06-30 11:59:59 +00:00
|
|
|
|
- (id) initWithCoder: (NSCoder*)aDecoder
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
1998-09-02 12:34:38 +00:00
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(id) at: &abbrev];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(int) at: &offset];
|
|
|
|
|
[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &is_dst];
|
|
|
|
|
return self;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
|
|
|
|
- (id) initWithTimeZone: (NSTimeZone*)aZone
|
|
|
|
|
withAbbrev: (NSString*)anAbbrev
|
|
|
|
|
withOffset: (int)anOffset
|
|
|
|
|
withDST: (BOOL)isDST
|
|
|
|
|
{
|
|
|
|
|
[super init];
|
|
|
|
|
timeZone = RETAIN(aZone);
|
|
|
|
|
abbrev = RETAIN(anAbbrev);
|
|
|
|
|
offset = anOffset;
|
|
|
|
|
is_dst = isDST;
|
|
|
|
|
return self;
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (BOOL) isDaylightSavingTimeZone
|
1997-10-24 16:58:20 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return is_dst;
|
1997-10-24 16:58:20 +00:00
|
|
|
|
}
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
|
|
|
|
- (NSString*) name
|
1997-10-24 16:58:20 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return [timeZone name];
|
1997-10-24 16:58:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSString*) timeZoneAbbreviation
|
|
|
|
|
{
|
|
|
|
|
return abbrev;
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (NSArray*) timeZoneDetailArray
|
1997-10-24 16:58:20 +00:00
|
|
|
|
{
|
|
|
|
|
return [timeZone timeZoneDetailArray];
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)date
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return [timeZone timeZoneDetailForDate: date];
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
|
|
|
|
- (int) timeZoneSecondsFromGMT
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return offset;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
|
|
|
|
- (int) timeZoneSecondsFromGMTForDate: (NSDate*)aDate
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
|
|
|
|
return offset;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1995-08-23 16:13:42 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@implementation NSTimeZone
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
+ (NSDictionary*) abbreviationDictionary
|
|
|
|
|
{
|
|
|
|
|
return fake_abbrev_dict;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSDictionary*) abbreviationMap
|
|
|
|
|
{
|
|
|
|
|
/* Instead of creating the abbreviation dictionary when the class is
|
|
|
|
|
initialized, we create it when we first need it, since the
|
|
|
|
|
dictionary can be potentially very large, considering that it's
|
|
|
|
|
almost never used. */
|
|
|
|
|
|
|
|
|
|
static NSMutableDictionary *abbreviationDictionary = nil;
|
|
|
|
|
FILE *file; // For the file containing the abbreviation dictionary
|
|
|
|
|
char abbrev[80], name[80];
|
|
|
|
|
NSString *fileName;
|
|
|
|
|
|
|
|
|
|
if (abbreviationDictionary != nil)
|
|
|
|
|
return abbreviationDictionary;
|
|
|
|
|
|
|
|
|
|
/* Read dictionary from file. */
|
|
|
|
|
abbreviationDictionary = [[NSMutableDictionary alloc] init];
|
|
|
|
|
fileName = [NSTimeZone getAbbreviationFile];
|
|
|
|
|
#if defined(__WIN32__)
|
|
|
|
|
file = fopen([fileName fileSystemRepresentation], "rb");
|
|
|
|
|
#else
|
|
|
|
|
file = fopen([fileName fileSystemRepresentation], "r");
|
|
|
|
|
#endif
|
|
|
|
|
if (file == NULL)
|
|
|
|
|
[NSException
|
|
|
|
|
raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Failed to open time zone abbreviation dictionary."];
|
|
|
|
|
while (fscanf(file, "%79s %79s", abbrev, name) == 2)
|
|
|
|
|
{
|
|
|
|
|
id a, the_name, the_abbrev;
|
|
|
|
|
|
|
|
|
|
the_name = [NSString stringWithCString: name];
|
|
|
|
|
the_abbrev = [NSString stringWithCString: abbrev];
|
|
|
|
|
a = [abbreviationDictionary objectForKey: the_abbrev];
|
|
|
|
|
if (a == nil)
|
|
|
|
|
{
|
|
|
|
|
a = [[NSMutableArray alloc] init];
|
|
|
|
|
[abbreviationDictionary setObject: a forKey: the_abbrev];
|
|
|
|
|
}
|
|
|
|
|
[a addObject: the_name];
|
|
|
|
|
}
|
|
|
|
|
fclose(file);
|
|
|
|
|
|
|
|
|
|
return abbreviationDictionary;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
+ (id) allocWithZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
if (self == NSTimeZoneClass)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* We return a placeholder object that can
|
|
|
|
|
* be converted to a real object when its initialisation method
|
|
|
|
|
* is called.
|
|
|
|
|
*/
|
|
|
|
|
if (z == NSDefaultMallocZone() || z == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* As a special case, we can return a placeholder for a time zone
|
|
|
|
|
* in the default malloc zone extremely efficiently.
|
|
|
|
|
*/
|
|
|
|
|
return defaultPlaceholderTimeZone;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
id obj;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* For anything other than the default zone, we need to
|
|
|
|
|
* locate the correct placeholder in the (lock protected)
|
|
|
|
|
* table of placeholders.
|
|
|
|
|
*/
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
|
|
|
|
obj = (id)NSMapGet(placeholderMap, (void*)z);
|
|
|
|
|
if (obj == nil)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* There is no placeholder object for this zone, so we
|
|
|
|
|
* create a new one and use that.
|
|
|
|
|
*/
|
|
|
|
|
obj = (id)NSAllocateObject(GSPlaceholderTimeZoneClass, 0, z);
|
|
|
|
|
NSMapInsert(placeholderMap, (void*)z, (void*)obj);
|
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return NSAllocateObject(self, 0, z);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
+ (NSTimeZone*) defaultTimeZone
|
2001-01-30 12:05:02 +00:00
|
|
|
|
{
|
2001-01-30 20:47:05 +00:00
|
|
|
|
NSTimeZone *zone;
|
|
|
|
|
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
if (defaultTimeZone == nil)
|
|
|
|
|
{
|
|
|
|
|
zone = [self systemTimeZone];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
zone = AUTORELEASE(RETAIN(defaultTimeZone));
|
|
|
|
|
else
|
|
|
|
|
zone = defaultTimeZone;
|
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
return zone;
|
2001-01-30 12:05:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
+ (void) initialize
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (self == [NSTimeZone class])
|
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
NSTimeZoneClass = self;
|
2001-01-31 11:29:55 +00:00
|
|
|
|
GSPlaceholderTimeZoneClass = [GSPlaceholderTimeZone class];
|
1997-11-03 14:30:13 +00:00
|
|
|
|
zoneDictionary = [[NSMutableDictionary alloc] init];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
/*
|
|
|
|
|
* Set up infrastructure for placeholder timezones.
|
|
|
|
|
*/
|
|
|
|
|
defaultPlaceholderTimeZone = (GSPlaceholderTimeZone*)
|
|
|
|
|
NSAllocateObject(GSPlaceholderTimeZoneClass, 0, NSDefaultMallocZone());
|
|
|
|
|
placeholderMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
|
|
|
|
|
NSNonRetainedObjectMapValueCallBacks, 0);
|
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
localTimeZone = [[NSLocalTimeZone alloc] init];
|
|
|
|
|
[self setDefaultTimeZone: [self systemTimeZone]];
|
|
|
|
|
|
|
|
|
|
fake_abbrev_dict = [[NSInternalAbbrevDict alloc] init];
|
|
|
|
|
if ([NSThread isMultiThreaded])
|
|
|
|
|
{
|
|
|
|
|
[self _becomeThreaded: nil];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
addObserver: self
|
|
|
|
|
selector: @selector(_becomeThreaded:)
|
|
|
|
|
name: NSWillBecomeMultiThreadedNotification
|
|
|
|
|
object: nil];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSTimeZone*) localTimeZone
|
|
|
|
|
{
|
|
|
|
|
return localTimeZone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) resetSystemTimeZone
|
|
|
|
|
{
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
DESTROY(systemTimeZone);
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) setDefaultTimeZone: (NSTimeZone*)aTimeZone
|
|
|
|
|
{
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
ASSIGN(defaultTimeZone, aTimeZone);
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSTimeZone*) systemTimeZone
|
|
|
|
|
{
|
|
|
|
|
NSTimeZone *zone = nil;
|
|
|
|
|
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
if (systemTimeZone == nil)
|
|
|
|
|
{
|
|
|
|
|
NSString *localZoneString = nil;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* setup default value in case something goes wrong.
|
|
|
|
|
*/
|
|
|
|
|
systemTimeZone = RETAIN([NSTimeZoneClass timeZoneForSecondsFromGMT: 0]);
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
localZoneString = [[NSUserDefaults standardUserDefaults]
|
2000-01-05 14:53:03 +00:00
|
|
|
|
stringForKey: LOCALDBKEY];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (localZoneString == nil)
|
2000-01-05 14:53:03 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Try to get timezone from GNUSTEP_TZ environment variable.
|
|
|
|
|
*/
|
|
|
|
|
localZoneString = [[[NSProcessInfo processInfo]
|
|
|
|
|
environment] objectForKey: @"GNUSTEP_TZ"];
|
|
|
|
|
}
|
1997-10-17 13:35:52 +00:00
|
|
|
|
if (localZoneString == nil)
|
2000-01-05 14:53:03 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Try to get timezone from LOCAL_TIME_FILE.
|
|
|
|
|
*/
|
2001-01-30 20:47:05 +00:00
|
|
|
|
NSString *f;
|
2000-01-05 14:53:03 +00:00
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
f = [NSBundle pathForGNUstepResource: LOCAL_TIME_FILE
|
|
|
|
|
ofType: @""
|
|
|
|
|
inDirectory: TIME_ZONE_DIR];
|
|
|
|
|
if (f != nil)
|
2000-01-05 14:53:03 +00:00
|
|
|
|
{
|
2001-01-30 20:47:05 +00:00
|
|
|
|
localZoneString = [NSString stringWithContentsOfFile: f];
|
|
|
|
|
localZoneString = [localZoneString stringByTrimmingSpaces];
|
2000-01-05 14:53:03 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (localZoneString == nil)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Try to get timezone from standard unix environment variable.
|
|
|
|
|
*/
|
|
|
|
|
localZoneString = [[[NSProcessInfo processInfo]
|
|
|
|
|
environment] objectForKey: @"TZ"];
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (localZoneString != nil)
|
2000-01-05 14:53:03 +00:00
|
|
|
|
{
|
2001-01-31 11:29:55 +00:00
|
|
|
|
zone = [defaultPlaceholderTimeZone initWithName: localZoneString];
|
2000-01-05 14:53:03 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
else
|
2000-01-05 14:53:03 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"No local time zone specified.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If local time zone fails to allocate, then allocate something
|
|
|
|
|
* that is sure to succeed (unless we run out of memory, of
|
|
|
|
|
* course).
|
|
|
|
|
*/
|
2001-01-30 20:47:05 +00:00
|
|
|
|
if (zone == nil)
|
1997-10-24 16:58:20 +00:00
|
|
|
|
{
|
1997-11-03 14:30:13 +00:00
|
|
|
|
NSLog(@"Using time zone with absolute offset 0.");
|
2001-01-30 20:47:05 +00:00
|
|
|
|
zone = systemTimeZone;
|
1997-10-24 16:58:20 +00:00
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
ASSIGN(systemTimeZone, zone);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
zone = AUTORELEASE(RETAIN(systemTimeZone));
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
zone = systemTimeZone;
|
|
|
|
|
}
|
|
|
|
|
return zone;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
+ (NSArray*) timeZoneArray
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
/* We create the array only when we need it to reduce overhead. */
|
|
|
|
|
|
|
|
|
|
static NSArray *regionsArray = nil;
|
|
|
|
|
int index, i;
|
|
|
|
|
char name[80];
|
|
|
|
|
FILE *file;
|
|
|
|
|
id temp_array[24];
|
|
|
|
|
NSString *fileName;
|
|
|
|
|
|
|
|
|
|
if (regionsArray != nil)
|
|
|
|
|
return regionsArray;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 24; i++)
|
|
|
|
|
temp_array[i] = [NSMutableArray array];
|
|
|
|
|
|
|
|
|
|
fileName = [NSTimeZoneClass getRegionsFile];
|
|
|
|
|
#if defined(__WIN32__)
|
|
|
|
|
file = fopen([fileName fileSystemRepresentation], "rb");
|
|
|
|
|
#else
|
|
|
|
|
file = fopen([fileName fileSystemRepresentation], "r");
|
|
|
|
|
#endif
|
|
|
|
|
if (file == NULL)
|
|
|
|
|
[NSException
|
|
|
|
|
raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Failed to open time zone regions array file."];
|
|
|
|
|
while (fscanf(file, "%d %s", &index, name) == 2)
|
|
|
|
|
[temp_array[index] addObject: [NSString stringWithCString: name]];
|
|
|
|
|
fclose(file);
|
|
|
|
|
regionsArray = [[NSArray alloc] initWithObjects: temp_array count: 24];
|
|
|
|
|
return regionsArray;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
+ (NSTimeZone*) timeZoneForSecondsFromGMT: (int)seconds
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* We simply return the following because an existing time zone with
|
|
|
|
|
the given offset might not always have the same offset (daylight
|
|
|
|
|
savings time, change in standard time, etc.). */
|
1999-08-25 16:12:36 +00:00
|
|
|
|
return AUTORELEASE([[NSConcreteAbsoluteTimeZone alloc] initWithOffset: seconds]);
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
+ (NSTimeZone*) timeZoneWithAbbreviation: (NSString*)abbreviation
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-30 20:47:05 +00:00
|
|
|
|
NSTimeZone *zone;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
zone = [self timeZoneWithName: [[self abbreviationDictionary]
|
|
|
|
|
objectForKey: abbreviation]];
|
2001-01-30 20:47:05 +00:00
|
|
|
|
return zone;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
+ (NSTimeZone*) timeZoneWithName: (NSString*)aTimeZoneName
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-31 11:29:55 +00:00
|
|
|
|
NSTimeZone *zone;
|
1999-08-25 16:12:36 +00:00
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
zone = [defaultPlaceholderTimeZone initWithName: aTimeZoneName];
|
|
|
|
|
return AUTORELEASE(zone);
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
+ (NSTimeZone*) timeZoneWithName: (NSString*)name data: (NSData*)data
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
|
|
|
|
- (NSString*) abbreviation
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return [self abbreviationForDate: [NSDate date]];
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSString*) abbreviationForDate: (NSDate*)when
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
NSTimeZoneDetail *detail;
|
|
|
|
|
|
|
|
|
|
detail = [self timeZoneDetailForDate: when];
|
|
|
|
|
return [detail timeZoneAbbreviation];
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (Class) classForCoder
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return NSTimeZoneClass;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone*)z
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return RETAIN(self);
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSString*) description
|
|
|
|
|
{
|
|
|
|
|
return [self name];
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
|
|
|
|
{
|
2001-01-31 11:29:55 +00:00
|
|
|
|
[aCoder encodeObject: [self name]];
|
2001-01-30 12:05:02 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (id) initWithCoder: (NSCoder*)aDecoder
|
|
|
|
|
{
|
|
|
|
|
NSString *name;
|
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
name = [aDecoder decodeObject];
|
|
|
|
|
self = [self initWithName: name];
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
- (id) initWithName: (NSString*)name
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithName: (NSString*)name data: (NSData*)data
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (BOOL) isDaylightSavingTime
|
|
|
|
|
{
|
|
|
|
|
return [self isDaylightSavingTimeForDate: [NSDate date]];
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (BOOL) isDaylightSavingTimeForDate: (NSDate*)aDate
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
NSTimeZoneDetail *detail;
|
|
|
|
|
|
|
|
|
|
detail = [self timeZoneDetailForDate: aDate];
|
|
|
|
|
return [detail isDaylightSavingTimeZone];
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (BOOL) isEqual: (id)other
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
if (other == self)
|
|
|
|
|
return YES;
|
|
|
|
|
if ([other isKindOfClass: NSTimeZoneClass] == NO)
|
|
|
|
|
return NO;
|
|
|
|
|
return [self isEqualToTimeZone: other];
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (BOOL) isEqualToTimeZone: (NSTimeZone*)aTimeZone
|
|
|
|
|
{
|
|
|
|
|
if (aTimeZone == self)
|
|
|
|
|
return YES;
|
|
|
|
|
if ([[self name] isEqual: [aTimeZone name]] == YES)
|
|
|
|
|
return YES;
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSString*) name
|
|
|
|
|
{
|
|
|
|
|
return [self subclassResponsibility: _cmd];
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-31 05:58:59 +00:00
|
|
|
|
- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder
|
|
|
|
|
{
|
|
|
|
|
if ([aCoder isByref] == NO)
|
|
|
|
|
return self;
|
|
|
|
|
return [super replacementObjectForPortCoder: aCoder];
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (int) secondsFromGMT
|
|
|
|
|
{
|
|
|
|
|
return [self secondsFromGMTForDate: [NSDate date]];
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (int) secondsFromGMTForDate: (NSDate*)when
|
|
|
|
|
{
|
|
|
|
|
NSTimeZoneDetail *detail;
|
|
|
|
|
|
|
|
|
|
detail = [self timeZoneDetailForDate: when];
|
|
|
|
|
return [detail timeZoneSecondsFromGMT];
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (NSArray*) timeZoneDetailArray
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return [self subclassResponsibility: _cmd];
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)date
|
|
|
|
|
{
|
|
|
|
|
return [self subclassResponsibility: _cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) timeZoneName
|
|
|
|
|
{
|
|
|
|
|
return [self name];
|
|
|
|
|
}
|
|
|
|
|
|
1997-10-17 13:35:52 +00:00
|
|
|
|
@end
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@implementation NSTimeZoneDetail
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (NSString*) description
|
1997-11-03 14:30:13 +00:00
|
|
|
|
{
|
|
|
|
|
return [NSString
|
|
|
|
|
stringWithFormat: @"%@(%@, %s%d)",
|
2001-01-30 12:05:02 +00:00
|
|
|
|
[self name],
|
1997-11-03 14:30:13 +00:00
|
|
|
|
[self timeZoneAbbreviation],
|
|
|
|
|
([self isDaylightSavingTimeZone]? "IS_DST, ": ""),
|
|
|
|
|
[self timeZoneSecondsFromGMT]];
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (BOOL) isDaylightSavingTimeZone
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return NO;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (NSString*) timeZoneAbbreviation
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return [self subclassResponsibility: _cmd];
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
- (int) timeZoneSecondsFromGMT
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
1997-09-01 21:59:51 +00:00
|
|
|
|
[self subclassResponsibility: _cmd];
|
|
|
|
|
return 0;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
1997-10-18 19:49:50 +00:00
|
|
|
|
@implementation NSTimeZone (Private)
|
1997-10-17 13:35:52 +00:00
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
/*
|
|
|
|
|
* When the system becomes multithreaded, we set a flag to say so
|
|
|
|
|
*/
|
|
|
|
|
+ (void) _becomeThreaded: (NSNotification*)notification
|
|
|
|
|
{
|
|
|
|
|
if (zone_mutex == nil)
|
|
|
|
|
{
|
|
|
|
|
zone_mutex = [NSRecursiveLock new];
|
|
|
|
|
}
|
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
|
removeObserver: self
|
|
|
|
|
name: NSWillBecomeMultiThreadedNotification
|
|
|
|
|
object: nil];
|
|
|
|
|
}
|
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
+ (NSString*) getAbbreviationFile
|
1997-10-18 19:49:50 +00:00
|
|
|
|
{
|
|
|
|
|
return [NSBundle pathForGNUstepResource: ABBREV_DICT
|
|
|
|
|
ofType: @""
|
|
|
|
|
inDirectory: TIME_ZONE_DIR];
|
|
|
|
|
}
|
1997-10-17 13:35:52 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
+ (NSString*) getRegionsFile
|
1997-10-18 19:49:50 +00:00
|
|
|
|
{
|
|
|
|
|
return [NSBundle pathForGNUstepResource: REGIONS_FILE
|
|
|
|
|
ofType: @""
|
|
|
|
|
inDirectory: TIME_ZONE_DIR];
|
|
|
|
|
}
|
1997-10-17 13:35:52 +00:00
|
|
|
|
|
1999-08-25 16:12:36 +00:00
|
|
|
|
+ (NSString*) getTimeZoneFile: (NSString *)name
|
1997-10-18 19:49:50 +00:00
|
|
|
|
{
|
2000-06-06 22:12:39 +00:00
|
|
|
|
NSString *dir = [NSString stringWithFormat: @"%@/%@", TIME_ZONE_DIR, ZONES_DIR];
|
|
|
|
|
NSString *path = [NSBundle pathForGNUstepResource: name
|
1999-12-13 12:14:01 +00:00
|
|
|
|
ofType: @""
|
2000-06-06 22:12:39 +00:00
|
|
|
|
inDirectory: dir];
|
1999-12-10 00:59:40 +00:00
|
|
|
|
return path;
|
1997-10-18 19:49:50 +00:00
|
|
|
|
}
|
1997-10-17 13:35:52 +00:00
|
|
|
|
|
1997-10-18 19:49:50 +00:00
|
|
|
|
@end
|