2001-12-17 14:31:42 +00:00
|
|
|
|
/** Time zone management. -*- Mode: ObjC -*-
|
2002-09-30 16:55:28 +00:00
|
|
|
|
Copyright (C) 1997-2002 Free Software Foundation, Inc.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
Written by: Yoo C. Chung <wacko@laplace.snu.ac.kr>
|
|
|
|
|
Date: June 1997
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
Rewrite large chunks by: Richard Frith-Macdonald <rfm@gnu.org>
|
2002-09-30 16:55:28 +00:00
|
|
|
|
Date: September 2002
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
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.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
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.
|
2005-02-22 11:22:44 +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
|
2005-05-22 03:32:16 +00:00
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
|
|
<title>NSTimeZone class reference</title>
|
2006-05-24 08:27:39 +00:00
|
|
|
|
$Date$ $Revision$
|
2001-12-18 16:54:15 +00:00
|
|
|
|
*/
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-10-11 03:08:54 +00:00
|
|
|
|
/* Use the system time zones if available. In other cases, use an
|
|
|
|
|
implementation independent of the system, since POSIX functions for
|
|
|
|
|
time zones are woefully inadequate for implementing NSTimeZone.
|
|
|
|
|
Time zone names can be different from system to system, but usually
|
|
|
|
|
the user has already set up his timezone independant of GNUstep, so we
|
|
|
|
|
should respect that information.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
The local time zone can be specified with:
|
|
|
|
|
1) the user defaults database
|
|
|
|
|
2) the GNUSTEP_TZ environment variable
|
|
|
|
|
3) the file LOCAL_TIME_FILE in _time_zone_path()
|
|
|
|
|
4) the TZ environment variable
|
2004-10-11 03:08:54 +00:00
|
|
|
|
5) TZDEFAULT defined in tzfile.h on platforms which have it
|
|
|
|
|
6) tzset() & tznam[] for platforms which have it
|
|
|
|
|
7) Windows registry, for Win32 systems
|
|
|
|
|
8) or the fallback time zone (which is UTC)
|
2000-01-05 14:53:03 +00:00
|
|
|
|
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.
|
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
Files & File System Heirarchy info:
|
|
|
|
|
===================================
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
Default place for the NSTimeZone directory is _time_zone_path():
|
|
|
|
|
{$(GNUSTEP_SYSTEM_ROOT)Libary/Libraries/Resources/TIME_ZONE_DIR}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
LOCAL_TIME_FILE is a text file with the name of the time zone file.
|
|
|
|
|
|
|
|
|
|
ZONES_DIR is a sub-directory under TIME_ZONE_DIR
|
|
|
|
|
|
|
|
|
|
(dir) ../System/Library/Libraries/Resources/..
|
|
|
|
|
(dir) NSTimeZone
|
|
|
|
|
(file) localtime {text; time zone eg Australia/Perth}
|
|
|
|
|
(dir) zones
|
|
|
|
|
|
|
|
|
|
Note that full zone info is required, especially the various "GMT"
|
|
|
|
|
files which are created especially for OPENSTEP compatibility.
|
|
|
|
|
Zone info comes from the Olson time database.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
FIXME?: use leap seconds? */
|
|
|
|
|
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "config.h"
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/preface.h"
|
2004-02-08 09:42:38 +00:00
|
|
|
|
#include "GNUstepBase/GSLock.h"
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2003-09-04 03:28:14 +00:00
|
|
|
|
#include <time.h>
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSArray.h"
|
|
|
|
|
#include "Foundation/NSCoder.h"
|
|
|
|
|
#include "Foundation/NSData.h"
|
|
|
|
|
#include "Foundation/NSDate.h"
|
|
|
|
|
#include "Foundation/NSDictionary.h"
|
|
|
|
|
#include "Foundation/NSException.h"
|
2004-05-21 15:39:02 +00:00
|
|
|
|
#include "Foundation/NSFileManager.h"
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSLock.h"
|
|
|
|
|
#include "Foundation/NSObject.h"
|
|
|
|
|
#include "Foundation/NSProcessInfo.h"
|
|
|
|
|
#include "Foundation/NSString.h"
|
|
|
|
|
#include "Foundation/NSUserDefaults.h"
|
|
|
|
|
#include "Foundation/NSUtilities.h"
|
|
|
|
|
#include "Foundation/NSZone.h"
|
|
|
|
|
#include "Foundation/NSBundle.h"
|
|
|
|
|
#include "Foundation/NSMapTable.h"
|
|
|
|
|
#include "Foundation/NSThread.h"
|
|
|
|
|
#include "Foundation/NSNotification.h"
|
|
|
|
|
#include "Foundation/NSPortCoder.h"
|
|
|
|
|
#include "Foundation/NSTimeZone.h"
|
|
|
|
|
#include "Foundation/NSByteOrder.h"
|
|
|
|
|
#include "Foundation/NSDebug.h"
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/GSCategories.h"
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "GSConfig.h"
|
2006-03-13 16:06:34 +00:00
|
|
|
|
#include "GSPrivate.h"
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2004-10-26 19:08:17 +00:00
|
|
|
|
#ifdef HAVE_TZHEAD
|
2004-10-11 03:08:54 +00:00
|
|
|
|
#include <tzfile.h>
|
|
|
|
|
#else
|
1997-09-01 21:59:51 +00:00
|
|
|
|
#define NOID
|
2004-10-11 03:08:54 +00:00
|
|
|
|
#include "nstzfile.h"
|
|
|
|
|
#endif
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/* Directory that contains the time zone data.
|
|
|
|
|
Expected in Resources directory for library bundle. */
|
1999-04-23 02:54:45 +00:00
|
|
|
|
#define TIME_ZONE_DIR @"NSTimeZones"
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2004-12-21 23:20:32 +00:00
|
|
|
|
/* Name of time zone abbreviation (plist) dictionary. */
|
|
|
|
|
#define ABBREV_DICT @"abbreviations"
|
|
|
|
|
|
|
|
|
|
/* Name of time zone abbreviation map. It is a text file
|
1997-09-01 21:59:51 +00:00
|
|
|
|
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. */
|
2004-12-21 23:20:32 +00:00
|
|
|
|
#define ABBREV_MAP @"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
|
|
|
|
|
2004-10-11 03:08:54 +00:00
|
|
|
|
/* Many systems have this file */
|
|
|
|
|
#define SYSTEM_TIME_FILE @"/etc/localtime"
|
|
|
|
|
|
2006-04-12 19:41:44 +00:00
|
|
|
|
/* If TZDIR told us where the zoneinfo files are, don't append anything else */
|
|
|
|
|
#ifdef TZDIR
|
|
|
|
|
#define POSIX_TZONES @""
|
|
|
|
|
#else
|
2006-02-21 15:44:04 +00:00
|
|
|
|
#define POSIX_TZONES @"posix/"
|
2006-04-12 19:41:44 +00:00
|
|
|
|
#endif
|
2006-02-21 15:44:04 +00:00
|
|
|
|
|
2004-10-11 03:08:54 +00:00
|
|
|
|
/* Possible location of system time zone files */
|
|
|
|
|
static NSString *tzdir = nil;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
@class GSAbsTimeZone;
|
|
|
|
|
@class GSTimeZoneDetail;
|
|
|
|
|
@class GSAbsTimeZoneDetail;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
@class GSPlaceholderTimeZone;
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Information for abstract placeholder class.
|
|
|
|
|
*/
|
|
|
|
|
static GSPlaceholderTimeZone *defaultPlaceholderTimeZone;
|
|
|
|
|
static NSMapTable *placeholderMap;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
/*
|
|
|
|
|
* Temporary structure for holding time zone details.
|
|
|
|
|
* This is the format in the data object.
|
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
|
struct ttinfo
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2004-02-29 21:17:40 +00:00
|
|
|
|
char offset[4]; // Seconds east of UTC
|
|
|
|
|
unsigned char isdst; // Daylight savings time?
|
2002-10-01 10:25:40 +00:00
|
|
|
|
unsigned char abbr_idx; // Index into time zone abbreviations string
|
2004-07-01 23:24:35 +00:00
|
|
|
|
} __attribute__((packed));
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
/*
|
|
|
|
|
* And this is the structure used in the time zone instances.
|
|
|
|
|
*/
|
|
|
|
|
typedef struct {
|
2006-01-11 08:37:16 +00:00
|
|
|
|
int32_t offset;
|
2002-10-01 10:25:40 +00:00
|
|
|
|
BOOL isdst;
|
|
|
|
|
unsigned char abbr_idx;
|
|
|
|
|
char pad[2];
|
|
|
|
|
NSString *abbreviation;
|
|
|
|
|
} TypeInfo;
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
@interface GSTimeZone : NSTimeZone
|
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
NSString *timeZoneName;
|
2006-02-21 15:44:04 +00:00
|
|
|
|
NSArray *abbreviations;
|
2002-10-01 10:25:40 +00:00
|
|
|
|
NSData *timeZoneData;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
unsigned int n_trans;
|
|
|
|
|
unsigned int n_types;
|
2006-01-11 08:37:16 +00:00
|
|
|
|
int32_t *trans;
|
2002-10-01 10:25:40 +00:00
|
|
|
|
TypeInfo *types;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
unsigned char *idxs;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2006-02-22 09:30:55 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
2004-02-29 21:17:40 +00:00
|
|
|
|
@interface GSWindowsTimeZone : NSTimeZone
|
|
|
|
|
{
|
|
|
|
|
@public
|
|
|
|
|
NSString *timeZoneName;
|
|
|
|
|
NSString *daylightZoneName;
|
|
|
|
|
NSString *timeZoneNameAbbr;
|
|
|
|
|
NSString *daylightZoneNameAbbr;
|
|
|
|
|
LONG Bias;
|
|
|
|
|
LONG StandardBias;
|
|
|
|
|
LONG DaylightBias;
|
|
|
|
|
SYSTEMTIME StandardDate;
|
|
|
|
|
SYSTEMTIME DaylightDate;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
#endif
|
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
|
|
|
|
|
2004-12-21 23:20:32 +00:00
|
|
|
|
/* one-to-one abbreviation to time zone name dictionary. */
|
|
|
|
|
static NSMutableDictionary *abbreviationDictionary = nil;
|
|
|
|
|
/* one-to-many abbreviation to time zone name dictionary. */
|
|
|
|
|
static NSMutableDictionary *abbreviationMap = nil;
|
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-04-10 03:27:01 +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-04-10 03:27:01 +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
|
|
|
|
|
2003-04-28 02:29:49 +00:00
|
|
|
|
/* Return path to a TimeZone directory file */
|
2004-12-21 23:20:32 +00:00
|
|
|
|
static NSString *_time_zone_path(NSString *subpath, NSString *type)
|
2003-04-28 02:29:49 +00:00
|
|
|
|
{
|
|
|
|
|
NSBundle *gbundle;
|
2004-12-21 23:20:32 +00:00
|
|
|
|
if (type == nil)
|
|
|
|
|
type = @"";
|
2003-04-28 02:29:49 +00:00
|
|
|
|
gbundle = [NSBundle bundleForLibrary: @"gnustep-base"];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
return [gbundle pathForResource: subpath
|
2004-12-21 23:20:32 +00:00
|
|
|
|
ofType: type
|
2003-04-28 02:29:49 +00:00
|
|
|
|
inDirectory: TIME_ZONE_DIR];
|
|
|
|
|
}
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2001-01-31 11:29:55 +00:00
|
|
|
|
@interface GSPlaceholderTimeZone : NSTimeZone
|
|
|
|
|
@end
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
@interface GSAbsTimeZone : NSTimeZone
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
@public
|
|
|
|
|
NSString *name;
|
|
|
|
|
id detail;
|
|
|
|
|
int offset; // Offset from UTC in seconds.
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-02-27 09:35:19 +00:00
|
|
|
|
- (id) initWithOffset: (int)anOffset name: (NSString*)aName;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
@end
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
@interface NSLocalTimeZone : NSTimeZone
|
|
|
|
|
@end
|
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
@interface GSTimeZoneDetail : NSTimeZoneDetail
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
NSTimeZone *timeZone; // Time zone which created this object.
|
|
|
|
|
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
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
@interface GSAbsTimeZoneDetail : NSTimeZoneDetail
|
|
|
|
|
{
|
|
|
|
|
GSAbsTimeZone *zone; // Time zone which created this object.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithTimeZone: (GSAbsTimeZone*)aZone;
|
|
|
|
|
@end
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1997-11-03 14:30:13 +00:00
|
|
|
|
/* Private methods for obtaining resource file names. */
|
|
|
|
|
@interface NSTimeZone (Private)
|
1999-08-25 16:12:36 +00:00
|
|
|
|
+ (NSString*) getTimeZoneFile: (NSString*)name;
|
1997-11-03 14:30:13 +00:00
|
|
|
|
@end
|
|
|
|
|
|
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.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2006-06-04 06:42:10 +00:00
|
|
|
|
GSNOSUPERDEALLOC; // placeholders never get deallocated.
|
2001-01-31 11:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (id) initWithName: (NSString*)name data: (NSData*)data
|
2001-01-31 11:29:55 +00:00
|
|
|
|
{
|
|
|
|
|
NSTimeZone *zone;
|
2002-10-01 10:25:40 +00:00
|
|
|
|
unsigned length = [name length];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
if (length == 0)
|
|
|
|
|
{
|
|
|
|
|
NSLog(@"Disallowed null time zone name");
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
if (length == 15 && [name isEqual: @"NSLocalTimeZone"])
|
2001-01-31 11:29:55 +00:00
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
zone = RETAIN(localTimeZone);
|
2002-09-30 17:14:51 +00:00
|
|
|
|
DESTROY(self);
|
|
|
|
|
return zone;
|
2001-01-31 11:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
|
2001-01-31 15:10:41 +00:00
|
|
|
|
/*
|
2001-05-02 11:52:43 +00:00
|
|
|
|
* Return a cached time zone if possible.
|
2002-10-01 10:25:40 +00:00
|
|
|
|
* NB. if data of cached zone does not match new data ... don't use cache
|
2001-01-31 15:10:41 +00:00
|
|
|
|
*/
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
|
|
|
|
zone = [zoneDictionary objectForKey: name];
|
2002-10-01 10:31:51 +00:00
|
|
|
|
if (data != nil && [data isEqual: [zone data]] == NO)
|
2002-10-01 10:25:40 +00:00
|
|
|
|
{
|
|
|
|
|
zone = nil;
|
|
|
|
|
}
|
2001-05-02 11:52:43 +00:00
|
|
|
|
IF_NO_GC(RETAIN(zone));
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
2002-10-01 10:25:40 +00:00
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
if (zone == nil)
|
2001-01-31 15:10:41 +00:00
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
unichar c;
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
2006-02-27 09:35:19 +00:00
|
|
|
|
if ((length == 3
|
|
|
|
|
&& ([name isEqualToString: @"GMT"] == YES
|
|
|
|
|
|| [name isEqualToString: @"UTC"] == YES
|
|
|
|
|
|| [name isEqualToString: @"UCT"] == YES))
|
|
|
|
|
|| (length == 4
|
|
|
|
|
&& ([name isEqualToString: @"GMT0"] == YES
|
|
|
|
|
|| [name isEqualToString: @"Zulu"] == YES))
|
|
|
|
|
|| (length == 9 && [name isEqualToString: @"Universal"] == YES))
|
|
|
|
|
{
|
|
|
|
|
// Synonyms for GMT
|
|
|
|
|
zone = [[GSAbsTimeZone alloc] initWithOffset: 0 name: name];
|
|
|
|
|
}
|
|
|
|
|
else if (length == 5 && [name hasPrefix: @"GMT"] == YES
|
|
|
|
|
&& ((c = [name characterAtIndex: 3]) == '+' || c == '-')
|
|
|
|
|
&& ((c = [name characterAtIndex: 4]) >= '0' && c <= '9'))
|
|
|
|
|
{
|
|
|
|
|
// GMT-9 to GMT+9
|
|
|
|
|
i = (c - '0') * 60 * 60;
|
|
|
|
|
if ([name characterAtIndex: 3] == '-')
|
|
|
|
|
{
|
|
|
|
|
i = -i;
|
|
|
|
|
}
|
|
|
|
|
zone = [[GSAbsTimeZone alloc] initWithOffset: i name: name];
|
|
|
|
|
}
|
|
|
|
|
else if (length == 6 && [name hasPrefix: @"GMT"] == YES
|
|
|
|
|
&& ((c = [name characterAtIndex: 3]) == '+' || c == '-')
|
|
|
|
|
&& ((c = [name characterAtIndex: 4]) == '0' || c == '1')
|
|
|
|
|
&& ((c = [name characterAtIndex: 5]) >= '0' && c <= '4'))
|
|
|
|
|
{
|
|
|
|
|
// GMT-14 to GMT-10 and GMT+10 to GMT+14
|
|
|
|
|
i = (c - '0') * 60 * 60;
|
|
|
|
|
if ([name characterAtIndex: 4] == '1')
|
|
|
|
|
{
|
|
|
|
|
i += 60 * 60 * 10;
|
|
|
|
|
}
|
|
|
|
|
if ([name characterAtIndex: 3] == '-')
|
|
|
|
|
{
|
|
|
|
|
i = -i;
|
|
|
|
|
}
|
|
|
|
|
zone = [[GSAbsTimeZone alloc] initWithOffset: i name: name];
|
|
|
|
|
}
|
|
|
|
|
else if (length == 8 && [name hasPrefix: @"GMT"] == YES
|
2002-10-01 10:25:40 +00:00
|
|
|
|
&& ((c = [name characterAtIndex: 3]) == '+' || c == '-'))
|
2001-01-31 11:29:55 +00:00
|
|
|
|
{
|
2006-02-27 09:35:19 +00:00
|
|
|
|
// GMT+NNNN and GMT-NNNN
|
2002-10-01 10:25:40 +00:00
|
|
|
|
c = [name characterAtIndex: 4];
|
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
|
{
|
|
|
|
|
i = c - '0';
|
|
|
|
|
c = [name characterAtIndex: 5];
|
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
|
{
|
|
|
|
|
i = i * 10 + (c - '0');
|
|
|
|
|
c = [name characterAtIndex: 6];
|
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
|
{
|
|
|
|
|
i = i * 6 + (c - '0');
|
|
|
|
|
c = [name characterAtIndex: 7];
|
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
|
{
|
|
|
|
|
i = i * 10 + (c - '0');
|
2006-02-27 09:35:19 +00:00
|
|
|
|
i = i * 60;
|
|
|
|
|
if ([name characterAtIndex: 3] == '-')
|
|
|
|
|
{
|
|
|
|
|
i = -i;
|
|
|
|
|
}
|
|
|
|
|
zone = [[GSAbsTimeZone alloc] initWithOffset: i
|
|
|
|
|
name: nil];
|
2002-10-01 10:25:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
if (zone == nil && length > 19
|
2005-11-06 07:13:33 +00:00
|
|
|
|
&& [name hasPrefix: @"NSAbsoluteTimeZone: "] == YES)
|
2002-10-01 10:25:40 +00:00
|
|
|
|
{
|
|
|
|
|
i = [[name substringFromIndex: 19] intValue];
|
|
|
|
|
|
2006-02-27 09:35:19 +00:00
|
|
|
|
zone = [[GSAbsTimeZone alloc] initWithOffset: i name: nil];
|
2001-01-31 15:10:41 +00:00
|
|
|
|
}
|
2002-10-01 10:25:40 +00:00
|
|
|
|
|
|
|
|
|
if (zone == nil)
|
2001-01-31 15:10:41 +00:00
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
if (data == nil)
|
2001-01-31 11:29:55 +00:00
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
NSString *fileName;
|
|
|
|
|
const char *str = [name UTF8String];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
/* Make sure that only time zone files are accessed.
|
|
|
|
|
FIXME: Make this more robust. */
|
|
|
|
|
if ((str)[0] == '/' || strchr(str, '.') != NULL)
|
2001-01-31 11:29:55 +00:00
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
NSLog(@"Disallowed time zone name `%@'.", name);
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return nil;
|
|
|
|
|
}
|
2001-01-31 11:29:55 +00:00
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
fileName = [NSTimeZoneClass getTimeZoneFile: name];
|
2005-10-09 11:32:10 +00:00
|
|
|
|
if (fileName == nil
|
2005-11-06 07:13:33 +00:00
|
|
|
|
|| ![[NSFileManager defaultManager] fileExistsAtPath: fileName])
|
2006-02-22 09:30:55 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
2004-02-29 21:17:40 +00:00
|
|
|
|
{
|
2005-11-06 07:13:33 +00:00
|
|
|
|
zone = [[GSWindowsTimeZone alloc] initWithName: name data: 0];
|
2004-02-29 21:17:40 +00:00
|
|
|
|
RELEASE(self);
|
|
|
|
|
return zone;
|
|
|
|
|
}
|
|
|
|
|
#else
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
NSLog(@"Unknown time zone name `%@'.", name);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
2004-02-29 21:17:40 +00:00
|
|
|
|
#endif
|
2002-09-30 16:54:29 +00:00
|
|
|
|
data = [NSData dataWithContentsOfFile: fileName];
|
2001-01-31 15:10:41 +00:00
|
|
|
|
}
|
2006-02-22 09:30:55 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
2005-11-06 07:13:33 +00:00
|
|
|
|
if (!data)
|
|
|
|
|
zone = [[GSWindowsTimeZone alloc] initWithName: name data: data];
|
|
|
|
|
else
|
2004-02-29 21:17:40 +00:00
|
|
|
|
#endif
|
2002-09-30 16:54:29 +00:00
|
|
|
|
zone = [[GSTimeZone alloc] initWithName: name data: data];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2002-09-30 16:54:29 +00:00
|
|
|
|
RELEASE(self);
|
2001-01-31 11:29:55 +00:00
|
|
|
|
return zone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) release
|
|
|
|
|
{
|
|
|
|
|
return; // placeholders never get released.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) retain
|
|
|
|
|
{
|
|
|
|
|
return self; // placeholders never get retained.
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSLocalTimeZone
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (NSString*) abbreviation
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] abbreviation];
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (NSString*) abbreviationForDate: (NSDate*)aDate
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] abbreviationForDate: aDate];
|
1998-03-12 14:21:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (id) autorelease
|
1998-03-12 14:21:20 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return self;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
- (NSData*) data
|
|
|
|
|
{
|
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] data];
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
[aCoder encodeObject: @"NSLocalTimeZone"];
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (id) init
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return self;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (BOOL) isDaylightSavingTime
|
2001-01-30 20:47:05 +00:00
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] isDaylightSavingTime];
|
2001-01-30 20:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (BOOL) isDaylightSavingTimeForDate: (NSDate*)aDate
|
2001-01-30 20:47:05 +00:00
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] isDaylightSavingTimeForDate: aDate];
|
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
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (int) secondsFromGMT
|
|
|
|
|
{
|
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] secondsFromGMT];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (int) secondsFromGMTForDate: (NSDate*)aDate
|
|
|
|
|
{
|
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] secondsFromGMTForDate: aDate];
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
- (NSArray*) timeZoneDetailArray
|
|
|
|
|
{
|
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] timeZoneDetailArray];
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)date
|
|
|
|
|
{
|
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] timeZoneDetailForDate: date];
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 17:14:51 +00:00
|
|
|
|
- (NSString*) timeZoneName
|
|
|
|
|
{
|
|
|
|
|
return [[NSTimeZoneClass defaultTimeZone] timeZoneName];
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
@end
|
2004-02-29 21:17:40 +00:00
|
|
|
|
|
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
@implementation GSAbsTimeZone
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
2003-02-13 13:31:59 +00:00
|
|
|
|
static int uninitialisedOffset = 100000;
|
1999-08-25 16:12:36 +00:00
|
|
|
|
static NSMapTable *absolutes = 0;
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
if (self == [GSAbsTimeZone class])
|
1999-08-25 16:12:36 +00:00
|
|
|
|
{
|
|
|
|
|
absolutes = NSCreateMapTable(NSIntMapKeyCallBacks,
|
2002-09-30 16:54:29 +00:00
|
|
|
|
NSNonOwnedPointerMapValueCallBacks, 0);
|
1999-08-25 16:12:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (NSString*) abbreviationForDate: (NSDate*)aDate
|
|
|
|
|
{
|
|
|
|
|
return name;
|
|
|
|
|
}
|
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
2003-02-13 13:31:59 +00:00
|
|
|
|
if (offset != uninitialisedOffset)
|
|
|
|
|
{
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
[zone_mutex lock];
|
2006-01-11 09:32:13 +00:00
|
|
|
|
NSMapRemove(absolutes, (void*)(uintptr_t)offset);
|
2003-02-13 13:31:59 +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];
|
|
|
|
|
}
|
|
|
|
|
|
2006-02-27 09:35:19 +00:00
|
|
|
|
- (id) initWithOffset: (int)anOffset name: (NSString*)aName
|
1999-08-25 16:12:36 +00:00
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
GSAbsTimeZone *z;
|
|
|
|
|
int extra;
|
|
|
|
|
int sign = anOffset >= 0 ? 1 : -1;
|
|
|
|
|
|
2003-02-13 13:31:59 +00:00
|
|
|
|
/*
|
|
|
|
|
* Set the uninitialised offset so that dealloc before full
|
|
|
|
|
* initialisation won't remove the timezeone for offset 0 from cache.
|
|
|
|
|
*/
|
|
|
|
|
offset = uninitialisedOffset;
|
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
/*
|
|
|
|
|
* Round the offset to the nearest minute, (for MacOS-X compatibility)
|
|
|
|
|
* and ensure it is no more than 18 hours.
|
|
|
|
|
*/
|
|
|
|
|
anOffset *= sign;
|
|
|
|
|
extra = anOffset % 60;
|
|
|
|
|
if (extra < 30)
|
|
|
|
|
{
|
|
|
|
|
anOffset -= extra;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
anOffset += 60 - extra;
|
|
|
|
|
}
|
|
|
|
|
if (anOffset > 64800)
|
|
|
|
|
{
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
anOffset *= sign;
|
1999-08-25 16:12:36 +00:00
|
|
|
|
|
2001-01-30 20:47:05 +00:00
|
|
|
|
if (zone_mutex != nil)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
2006-01-11 09:32:13 +00:00
|
|
|
|
z = (GSAbsTimeZone*)NSMapGet(absolutes, (void*)(uintptr_t)anOffset);
|
2002-09-30 16:54:29 +00:00
|
|
|
|
if (z != nil)
|
1999-08-25 16:12:36 +00:00
|
|
|
|
{
|
1999-09-28 19:35:09 +00:00
|
|
|
|
IF_NO_GC(RETAIN(z));
|
1999-08-25 16:12:36 +00:00
|
|
|
|
RELEASE(self);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-02-27 09:35:19 +00:00
|
|
|
|
if (aName == nil)
|
2002-10-01 10:25:40 +00:00
|
|
|
|
{
|
2006-02-27 09:35:19 +00:00
|
|
|
|
if (anOffset % 60 == 0)
|
|
|
|
|
{
|
|
|
|
|
char s = (anOffset >= 0) ? '+' : '-';
|
|
|
|
|
int i = (anOffset >= 0) ? anOffset / 60 : -anOffset / 60;
|
|
|
|
|
int h = i / 60;
|
|
|
|
|
int m = i % 60;
|
|
|
|
|
char buf[9];
|
|
|
|
|
|
|
|
|
|
sprintf(buf, "GMT%c%02d%02d", s, h, m);
|
|
|
|
|
name = [[NSString alloc] initWithUTF8String: buf];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Should never happen now we round to the minute
|
|
|
|
|
* for MacOS-X compatibnility.
|
|
|
|
|
*/
|
|
|
|
|
name = [[NSString alloc] initWithFormat: @"NSAbsoluteTimeZone:%d",
|
|
|
|
|
anOffset];
|
|
|
|
|
}
|
2002-10-01 10:25:40 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-02-27 09:35:19 +00:00
|
|
|
|
name = [aName copy];
|
2002-10-01 10:25:40 +00:00
|
|
|
|
}
|
|
|
|
|
detail = [[GSAbsTimeZoneDetail alloc] initWithTimeZone: self];
|
2002-09-30 16:54:29 +00:00
|
|
|
|
offset = anOffset;
|
|
|
|
|
z = self;
|
2006-01-11 09:32:13 +00:00
|
|
|
|
NSMapInsert(absolutes, (void*)(uintptr_t)anOffset, (void*)z);
|
2002-09-30 16:54:29 +00:00
|
|
|
|
[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)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
[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
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (BOOL) isDaylightSavingTimeZoneForDate: (NSDate*)aDate
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (int) secondsFromGMTForDate: (NSDate*)aDate
|
|
|
|
|
{
|
|
|
|
|
return offset;
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-07 11:19:34 +00:00
|
|
|
|
- (NSArray*) timeZoneDetailArray
|
1997-10-17 13:35:52 +00:00
|
|
|
|
{
|
2005-03-07 11:19:34 +00:00
|
|
|
|
return [NSArray arrayWithObject: detail];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
2005-02-22 11:22:44 +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
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
- (NSString*) timeZoneName
|
|
|
|
|
{
|
|
|
|
|
return name;
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@end
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
@implementation GSTimeZoneDetail
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
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);
|
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
|
|
|
|
|
{
|
|
|
|
|
timeZone = RETAIN(aZone);
|
2002-09-30 16:54:29 +00:00
|
|
|
|
abbrev = anAbbrev; // NB. Depend on this being retained in aZone
|
2001-01-30 12:05:02 +00:00
|
|
|
|
offset = anOffset;
|
|
|
|
|
is_dst = isDST;
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +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
|
|
|
|
}
|
2005-02-22 11:22:44 +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
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSString*) timeZoneAbbreviation
|
|
|
|
|
{
|
|
|
|
|
return abbrev;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
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
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1995-08-23 16:13:42 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
|
|
|
|
|
@implementation GSAbsTimeZoneDetail
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
- (NSString*) abbreviation
|
|
|
|
|
{
|
|
|
|
|
return zone->name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) abbreviationForDate: (NSDate*)aDate
|
|
|
|
|
{
|
|
|
|
|
return zone->name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
RELEASE(zone);
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithTimeZone: (GSAbsTimeZone*)aZone
|
|
|
|
|
{
|
|
|
|
|
zone = RETAIN(aZone);
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
- (BOOL) isDaylightSavingTimeZone
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
- (BOOL) isDaylightSavingTimeZoneForDate: (NSDate*)aDate
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
- (NSString*) name
|
|
|
|
|
{
|
|
|
|
|
return zone->name;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
- (NSString*) timeZoneAbbreviation
|
|
|
|
|
{
|
|
|
|
|
return zone->name;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
- (NSArray*) timeZoneDetailArray
|
|
|
|
|
{
|
|
|
|
|
return [zone timeZoneDetailArray];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)date
|
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (int) timeZoneSecondsFromGMT
|
|
|
|
|
{
|
|
|
|
|
return zone->offset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (int) timeZoneSecondsFromGMTForDate: (NSDate*)aDate
|
|
|
|
|
{
|
|
|
|
|
return zone->offset;
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
2002-08-20 10:22:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>
|
2004-10-11 03:08:54 +00:00
|
|
|
|
* The local time zone is obtained from, in order of preference:<br/ >
|
2004-02-29 21:17:40 +00:00
|
|
|
|
* 1) the user defaults database: NSGlobalDomain "Local Time Zone"<br/ >
|
|
|
|
|
* 2) the GNUSTEP_TZ environment variable<br/ >
|
|
|
|
|
* 3) the file "localtime" in System/Library/Libraries/Resources/NSTimeZone<br/ >
|
|
|
|
|
* 4) the TZ environment variable<br/ >
|
2004-10-11 03:08:54 +00:00
|
|
|
|
* 5) The system zone settings (typically in /etc/localtime)<br/ >
|
|
|
|
|
* 6) tzset and tznam on platforms which have it<br/ >
|
|
|
|
|
* 7) Windows registry, on Win32 systems<br/ >
|
|
|
|
|
* 8) or the fallback time zone (which is UTC)<br/ >
|
2004-02-29 21:17:40 +00:00
|
|
|
|
* </p>
|
|
|
|
|
* <p>If the GNUstep time zone datafiles become too out of date, one
|
2002-08-20 10:22:05 +00:00
|
|
|
|
* can download an updated database from <uref
|
|
|
|
|
* url="ftp://elsie.nci.nih.gov/pub/">ftp://elsie.nci.nih.gov/pub/</uref>
|
|
|
|
|
* and compile it as specified in the README file in the
|
|
|
|
|
* NSTimeZones directory.
|
2002-10-01 10:25:40 +00:00
|
|
|
|
* </p>
|
|
|
|
|
* <p>Time zone names in NSDates should be GMT, MET etc. not
|
2002-08-20 10:22:05 +00:00
|
|
|
|
* Europe/Berlin, America/Washington etc.
|
2002-10-01 10:25:40 +00:00
|
|
|
|
* </p>
|
2002-10-04 12:32:27 +00:00
|
|
|
|
* <p>The problem with this is that various time zones may use the
|
2002-08-20 10:22:05 +00:00
|
|
|
|
* same abbreviation (e.g. Australia/Brisbane and
|
|
|
|
|
* America/New_York both use EST), and some time zones
|
|
|
|
|
* may have different rules for daylight saving time even if the
|
|
|
|
|
* abbreviation and offsets from UTC are the same.
|
2002-10-01 10:25:40 +00:00
|
|
|
|
* </p>
|
|
|
|
|
* <p>The problems with depending on the OS for providing time zone
|
2004-10-11 03:08:54 +00:00
|
|
|
|
* info are that time zone names may vary
|
2002-08-20 10:22:05 +00:00
|
|
|
|
* wildly between OSes (this could be a big problem when
|
|
|
|
|
* archiving is used between different systems).
|
|
|
|
|
* </p>
|
2004-02-29 21:17:40 +00:00
|
|
|
|
* <p>Win32: Time zone names read from the registry are different
|
|
|
|
|
* from other GNUstep installations. Be careful when moving data
|
|
|
|
|
* between platforms in this case.
|
|
|
|
|
* </p>
|
2002-08-20 10:22:05 +00:00
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@implementation NSTimeZone
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
2004-12-21 23:20:32 +00:00
|
|
|
|
* Returns a dictionary containing time zone abbreviations and their
|
|
|
|
|
* corresponding time zone names. More than one time zone may be associated
|
|
|
|
|
* with a single abbreviation. In this case, the dictionary contains only
|
2005-02-22 11:22:44 +00:00
|
|
|
|
* one (usually the most common) time zone name for the abbreviation.
|
2004-02-29 21:17:40 +00:00
|
|
|
|
*/
|
2001-01-30 12:05:02 +00:00
|
|
|
|
+ (NSDictionary*) abbreviationDictionary
|
|
|
|
|
{
|
2004-12-21 23:20:32 +00:00
|
|
|
|
if (abbreviationDictionary != nil)
|
2006-02-21 15:44:04 +00:00
|
|
|
|
{
|
|
|
|
|
return abbreviationDictionary;
|
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
|
|
|
|
if (abbreviationDictionary == nil)
|
|
|
|
|
{
|
|
|
|
|
CREATE_AUTORELEASE_POOL(pool);
|
|
|
|
|
NSString *path;
|
|
|
|
|
|
|
|
|
|
path = _time_zone_path (ABBREV_DICT, @"plist");
|
|
|
|
|
if (path != nil)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Fast mechanism ... load prebuilt data from file so we don't
|
|
|
|
|
* need to load in all time zones.
|
|
|
|
|
*/
|
|
|
|
|
abbreviationDictionary
|
|
|
|
|
= RETAIN([[NSString stringWithContentsOfFile: path] propertyList]);
|
|
|
|
|
}
|
|
|
|
|
if (abbreviationDictionary == nil)
|
|
|
|
|
{
|
|
|
|
|
NSMutableDictionary *md;
|
|
|
|
|
NSString *name;
|
|
|
|
|
NSEnumerator *names;
|
2004-12-21 23:20:32 +00:00
|
|
|
|
|
2006-02-21 15:44:04 +00:00
|
|
|
|
/*
|
|
|
|
|
* Slow fallback ... load all time zones and generate
|
|
|
|
|
* abbreviation dictionary from them.
|
|
|
|
|
*/
|
|
|
|
|
md = [[NSMutableDictionary alloc] init];
|
|
|
|
|
names = [[NSTimeZone knownTimeZoneNames] objectEnumerator];
|
|
|
|
|
while ((name = [names nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
NSTimeZone *zone;
|
|
|
|
|
|
|
|
|
|
if ((zone = [NSTimeZone timeZoneWithName: name]))
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *details;
|
|
|
|
|
NSTimeZoneDetail *detail;
|
|
|
|
|
|
|
|
|
|
details = [[zone timeZoneDetailArray] objectEnumerator];
|
|
|
|
|
while ((detail = [details nextObject]) != nil)
|
|
|
|
|
{
|
2006-02-21 17:13:19 +00:00
|
|
|
|
[md setObject: name
|
|
|
|
|
forKey: [detail timeZoneAbbreviation]];
|
2006-02-21 15:44:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[md makeImmutableCopyOnFail: NO];
|
|
|
|
|
abbreviationDictionary = md;
|
|
|
|
|
}
|
|
|
|
|
RELEASE(pool);
|
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
2004-12-21 23:20:32 +00:00
|
|
|
|
{
|
2006-02-21 15:44:04 +00:00
|
|
|
|
[zone_mutex unlock];
|
2004-12-21 23:20:32 +00:00
|
|
|
|
}
|
2006-02-21 15:44:04 +00:00
|
|
|
|
return abbreviationDictionary;
|
2001-01-30 12:05:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
2004-12-21 23:20:32 +00:00
|
|
|
|
* Returns a dictionary that maps abbreviations to the array
|
|
|
|
|
* containing all the time zone names that use the abbreviation.
|
2004-02-29 21:17:40 +00:00
|
|
|
|
*/
|
2001-01-30 12:05:02 +00:00
|
|
|
|
+ (NSDictionary*) abbreviationMap
|
|
|
|
|
{
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/* 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. */
|
2004-12-21 23:20:32 +00:00
|
|
|
|
if (abbreviationMap != nil)
|
2006-02-21 15:44:04 +00:00
|
|
|
|
{
|
|
|
|
|
return abbreviationMap;
|
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
|
|
|
|
if (abbreviationMap == nil)
|
|
|
|
|
{
|
|
|
|
|
CREATE_AUTORELEASE_POOL(pool);
|
|
|
|
|
NSMutableDictionary *md;
|
|
|
|
|
NSMutableArray *ma;
|
|
|
|
|
NSString *the_name;
|
|
|
|
|
NSString *the_abbrev;
|
|
|
|
|
FILE *file;
|
|
|
|
|
char abbrev[80];
|
|
|
|
|
char name[80];
|
|
|
|
|
NSString *path;
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
2006-02-21 15:44:04 +00:00
|
|
|
|
/*
|
|
|
|
|
* Read dictionary from file... fast mechanism because we don't have
|
|
|
|
|
* to create all timezoneas and parse all their data files.
|
|
|
|
|
*/
|
|
|
|
|
md = [NSMutableDictionary dictionaryWithCapacity: 100];
|
|
|
|
|
path = _time_zone_path (ABBREV_MAP, nil);
|
|
|
|
|
if (path != nil)
|
|
|
|
|
{
|
2005-10-11 19:09:26 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
2006-02-21 15:44:04 +00:00
|
|
|
|
unichar mode[3];
|
|
|
|
|
|
|
|
|
|
mode[0] = 'r';
|
|
|
|
|
mode[1] = 'b';
|
|
|
|
|
mode[2] = '\0';
|
|
|
|
|
|
|
|
|
|
file = _wfopen((const unichar*)[path fileSystemRepresentation], mode);
|
2001-01-30 12:05:02 +00:00
|
|
|
|
#else
|
2006-02-21 15:44:04 +00:00
|
|
|
|
file = fopen([path fileSystemRepresentation], "r");
|
2001-01-30 12:05:02 +00:00
|
|
|
|
#endif
|
2006-02-21 15:44:04 +00:00
|
|
|
|
if (file == NULL)
|
|
|
|
|
{
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
|
|
|
|
[NSException
|
|
|
|
|
raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Failed to open time zone abbreviation map."];
|
|
|
|
|
}
|
|
|
|
|
while (fscanf(file, "%79s %79s", abbrev, name) == 2)
|
|
|
|
|
{
|
|
|
|
|
the_name = [[NSString alloc] initWithUTF8String: name];
|
|
|
|
|
the_abbrev = [[NSString alloc] initWithUTF8String: abbrev];
|
|
|
|
|
ma = [md objectForKey: the_abbrev];
|
|
|
|
|
if (ma == nil)
|
|
|
|
|
{
|
|
|
|
|
ma = [[NSMutableArray alloc] initWithCapacity: 1];
|
|
|
|
|
[md setObject: ma forKey: the_abbrev];
|
|
|
|
|
RELEASE(ma);
|
|
|
|
|
}
|
|
|
|
|
RELEASE(the_abbrev);
|
2006-02-21 17:13:19 +00:00
|
|
|
|
if ([ma containsObject: the_name] == NO)
|
|
|
|
|
{
|
|
|
|
|
[ma addObject: the_name];
|
|
|
|
|
}
|
2006-02-21 15:44:04 +00:00
|
|
|
|
RELEASE(the_name);
|
|
|
|
|
}
|
|
|
|
|
fclose(file);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSString *name;
|
2006-02-21 17:13:19 +00:00
|
|
|
|
NSEnumerator *names;
|
2006-02-21 15:44:04 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Slow fallback mechanism ... go through all time names
|
|
|
|
|
* so we load all the time zone data and generate the info
|
|
|
|
|
* we need from it.
|
|
|
|
|
*/
|
2006-02-21 17:13:19 +00:00
|
|
|
|
names = [[NSTimeZone knownTimeZoneNames] objectEnumerator];
|
|
|
|
|
while ((name = [names nextObject]) != nil)
|
2006-02-21 15:44:04 +00:00
|
|
|
|
{
|
2006-02-21 17:13:19 +00:00
|
|
|
|
NSTimeZone *zone;
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
2006-02-21 17:13:19 +00:00
|
|
|
|
if ((zone = [NSTimeZone timeZoneWithName: name]) != nil)
|
|
|
|
|
{
|
|
|
|
|
NSEnumerator *details;
|
|
|
|
|
NSTimeZoneDetail *detail;
|
|
|
|
|
|
|
|
|
|
details = [[zone timeZoneDetailArray] objectEnumerator];
|
|
|
|
|
while ((detail = [details nextObject]) != nil)
|
2006-02-21 15:44:04 +00:00
|
|
|
|
{
|
2006-02-21 17:13:19 +00:00
|
|
|
|
the_abbrev = [detail timeZoneAbbreviation];
|
|
|
|
|
ma = [md objectForKey: the_abbrev];
|
|
|
|
|
if (ma == nil)
|
2006-02-21 15:44:04 +00:00
|
|
|
|
{
|
2006-02-21 17:13:19 +00:00
|
|
|
|
ma = [[NSMutableArray alloc] initWithCapacity: 1];
|
|
|
|
|
[md setObject: ma forKey: the_abbrev];
|
|
|
|
|
RELEASE(ma);
|
|
|
|
|
}
|
|
|
|
|
if ([ma containsObject: name] == NO)
|
|
|
|
|
{
|
|
|
|
|
[ma addObject: name];
|
2006-02-21 15:44:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Special case: Add the system time zone if
|
|
|
|
|
* it doesn't exist in the map */
|
|
|
|
|
the_abbrev = [systemTimeZone abbreviation];
|
|
|
|
|
ma = [md objectForKey: the_abbrev];
|
|
|
|
|
if (ma == nil)
|
|
|
|
|
{
|
|
|
|
|
ma = [NSMutableArray new];
|
|
|
|
|
[md setObject: ma forKey: the_abbrev];
|
|
|
|
|
RELEASE(ma);
|
|
|
|
|
}
|
|
|
|
|
the_name = [systemTimeZone timeZoneName];
|
|
|
|
|
if ([ma containsObject: the_name] == NO)
|
2001-01-30 12:05:02 +00:00
|
|
|
|
{
|
2006-02-21 15:44:04 +00:00
|
|
|
|
[ma addObject: the_name];
|
2001-01-30 12:05:02 +00:00
|
|
|
|
}
|
2006-02-21 15:44:04 +00:00
|
|
|
|
|
|
|
|
|
[md makeImmutableCopyOnFail: NO];
|
|
|
|
|
abbreviationMap = RETAIN(md);
|
|
|
|
|
RELEASE(pool);
|
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
2001-01-30 12:05:02 +00:00
|
|
|
|
}
|
2004-10-11 03:08:54 +00:00
|
|
|
|
|
2004-12-21 23:20:32 +00:00
|
|
|
|
return abbreviationMap;
|
2001-01-30 12:05:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-11-05 03:47:03 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns an array of all known time zone names.
|
|
|
|
|
*/
|
|
|
|
|
+ (NSArray*) knownTimeZoneNames
|
|
|
|
|
{
|
|
|
|
|
static NSArray *namesArray = nil;
|
|
|
|
|
|
|
|
|
|
/* We create the array only when we need it to reduce overhead. */
|
|
|
|
|
if (namesArray != nil)
|
2006-02-21 15:44:04 +00:00
|
|
|
|
{
|
|
|
|
|
return namesArray;
|
|
|
|
|
}
|
2004-11-05 03:47:03 +00:00
|
|
|
|
|
2006-02-21 15:44:04 +00:00
|
|
|
|
if (zone_mutex != nil)
|
2004-11-05 03:47:03 +00:00
|
|
|
|
{
|
2006-02-21 15:44:04 +00:00
|
|
|
|
[zone_mutex lock];
|
2004-11-05 03:47:03 +00:00
|
|
|
|
}
|
2006-02-21 15:44:04 +00:00
|
|
|
|
if (namesArray == nil)
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
NSMutableArray *ma;
|
|
|
|
|
NSArray *regionsArray;
|
|
|
|
|
|
|
|
|
|
ma = [NSMutableArray new];
|
|
|
|
|
regionsArray = [self timeZoneArray];
|
2004-11-05 03:47:03 +00:00
|
|
|
|
|
2006-02-21 15:44:04 +00:00
|
|
|
|
for (i = 0; i < [regionsArray count]; i++)
|
|
|
|
|
{
|
|
|
|
|
NSArray *names = [regionsArray objectAtIndex: i];
|
|
|
|
|
|
|
|
|
|
[ma addObjectsFromArray: names];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[ma makeImmutableCopyOnFail: NO];
|
|
|
|
|
namesArray = ma;
|
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
2004-11-05 03:47:03 +00:00
|
|
|
|
return namesArray;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
2006-05-24 08:27:39 +00:00
|
|
|
|
* in the default zone extremely efficiently.
|
2001-01-31 11:29:55 +00:00
|
|
|
|
*/
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return the default time zone for this process.
|
|
|
|
|
*/
|
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)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
if (defaultTimeZone == nil)
|
|
|
|
|
{
|
|
|
|
|
zone = [self systemTimeZone];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (zone_mutex != nil)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
zone = AUTORELEASE(RETAIN(defaultTimeZone));
|
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
else
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
zone = defaultTimeZone;
|
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
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];
|
|
|
|
|
|
2004-02-08 09:42:38 +00:00
|
|
|
|
zone_mutex = [GSLazyRecursiveLock new];
|
2001-01-30 20:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return a proxy to the default time zone for this process.
|
|
|
|
|
*/
|
2001-01-30 20:47:05 +00:00
|
|
|
|
+ (NSTimeZone*) localTimeZone
|
|
|
|
|
{
|
|
|
|
|
return localTimeZone;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* Destroy the system time zone so that it will be recreated
|
|
|
|
|
* next time it is used.
|
|
|
|
|
*/
|
2001-01-30 20:47:05 +00:00
|
|
|
|
+ (void) resetSystemTimeZone
|
|
|
|
|
{
|
|
|
|
|
if (zone_mutex != nil)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
DESTROY(systemTimeZone);
|
|
|
|
|
if (zone_mutex != nil)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* Set the default time zone to be used for this process.
|
|
|
|
|
*/
|
2001-01-30 20:47:05 +00:00
|
|
|
|
+ (void) setDefaultTimeZone: (NSTimeZone*)aTimeZone
|
|
|
|
|
{
|
2002-09-30 17:14:51 +00:00
|
|
|
|
if (aTimeZone != defaultTimeZone)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
2002-09-30 17:14:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* We can't make the localTimeZone the default since that would
|
|
|
|
|
* cause recursion ...
|
|
|
|
|
*/
|
|
|
|
|
if (aTimeZone == localTimeZone)
|
|
|
|
|
{
|
|
|
|
|
aTimeZone = [self systemTimeZone];
|
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
|
|
|
|
ASSIGN(defaultTimeZone, aTimeZone);
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
2002-09-30 16:54:29 +00:00
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the current system time zone for the process.
|
|
|
|
|
*/
|
2001-01-30 20:47:05 +00:00
|
|
|
|
+ (NSTimeZone*) systemTimeZone
|
|
|
|
|
{
|
|
|
|
|
NSTimeZone *zone = nil;
|
|
|
|
|
|
|
|
|
|
if (zone_mutex != nil)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
if (systemTimeZone == nil)
|
|
|
|
|
{
|
|
|
|
|
NSString *localZoneString = nil;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* setup default value in case something goes wrong.
|
|
|
|
|
*/
|
|
|
|
|
systemTimeZone = RETAIN([NSTimeZoneClass timeZoneForSecondsFromGMT: 0]);
|
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/*
|
|
|
|
|
* Try to get timezone from user defaults database
|
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
|
localZoneString = [[NSUserDefaults standardUserDefaults]
|
2000-01-05 14:53:03 +00:00
|
|
|
|
stringForKey: LOCALDBKEY];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/*
|
|
|
|
|
* Try to get timezone from GNUSTEP_TZ environment variable.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (localZoneString == nil)
|
2000-01-05 14:53:03 +00:00
|
|
|
|
{
|
|
|
|
|
localZoneString = [[[NSProcessInfo processInfo]
|
|
|
|
|
environment] objectForKey: @"GNUSTEP_TZ"];
|
|
|
|
|
}
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/*
|
|
|
|
|
* Try to get timezone from LOCAL_TIME_FILE.
|
|
|
|
|
*/
|
1997-10-17 13:35:52 +00:00
|
|
|
|
if (localZoneString == nil)
|
2000-01-05 14:53:03 +00:00
|
|
|
|
{
|
2004-12-21 23:20:32 +00:00
|
|
|
|
NSString *f = _time_zone_path(LOCAL_TIME_FILE, nil);
|
2001-01-30 20:47:05 +00:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
}
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/*
|
2004-10-11 03:08:54 +00:00
|
|
|
|
* Try to get timezone from standard unix environment variable.
|
2004-02-29 21:17:40 +00:00
|
|
|
|
*/
|
2003-09-04 03:28:14 +00:00
|
|
|
|
if (localZoneString == nil)
|
|
|
|
|
{
|
2004-10-11 03:08:54 +00:00
|
|
|
|
localZoneString = [[[NSProcessInfo processInfo]
|
|
|
|
|
environment] objectForKey: @"TZ"];
|
2003-09-04 03:28:14 +00:00
|
|
|
|
}
|
2004-10-11 03:08:54 +00:00
|
|
|
|
if (localZoneString == nil)
|
|
|
|
|
{
|
|
|
|
|
/* Get the zone name from the localtime file, assuming the file
|
|
|
|
|
is a symlink to the time zone. Getting the actual data (which
|
|
|
|
|
is easier) doesn't help, since we won't know the name itself. */
|
2004-10-26 19:08:17 +00:00
|
|
|
|
#if defined(HAVE_TZHEAD) && defined(TZDEFAULT)
|
2006-02-21 15:44:04 +00:00
|
|
|
|
tzdir = RETAIN([NSString stringWithUTF8String: TZDIR]);
|
|
|
|
|
localZoneString = [NSString stringWithUTF8String: TZDEFAULT];
|
2004-10-11 03:08:54 +00:00
|
|
|
|
localZoneString = [localZoneString stringByResolvingSymlinksInPath];
|
2003-09-04 03:28:14 +00:00
|
|
|
|
#else
|
2004-10-11 03:08:54 +00:00
|
|
|
|
NSFileManager *dflt = [NSFileManager defaultManager];
|
2005-11-06 07:13:33 +00:00
|
|
|
|
|
2004-10-11 03:08:54 +00:00
|
|
|
|
if ([dflt fileExistsAtPath: SYSTEM_TIME_FILE])
|
|
|
|
|
{
|
|
|
|
|
localZoneString = SYSTEM_TIME_FILE;
|
2005-11-06 07:13:33 +00:00
|
|
|
|
localZoneString
|
|
|
|
|
= [localZoneString stringByResolvingSymlinksInPath];
|
2004-10-11 03:08:54 +00:00
|
|
|
|
/* Guess what tzdir is */
|
|
|
|
|
tzdir = [localZoneString stringByDeletingLastPathComponent];
|
|
|
|
|
while ([tzdir length] > 2
|
2005-11-06 07:13:33 +00:00
|
|
|
|
&& [dflt fileExistsAtPath:
|
|
|
|
|
[tzdir stringByAppendingPathComponent: @"GMT"]] == NO)
|
|
|
|
|
{
|
|
|
|
|
tzdir = [tzdir stringByDeletingLastPathComponent];
|
|
|
|
|
}
|
2004-10-11 03:08:54 +00:00
|
|
|
|
if ([tzdir length] > 2)
|
2005-11-06 07:13:33 +00:00
|
|
|
|
{
|
|
|
|
|
RETAIN(tzdir);
|
|
|
|
|
}
|
2004-10-11 03:08:54 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
localZoneString = tzdir = nil;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2005-02-22 11:22:44 +00:00
|
|
|
|
if (localZoneString != nil && [localZoneString hasPrefix: tzdir])
|
2004-10-11 03:08:54 +00:00
|
|
|
|
{
|
|
|
|
|
/* This must be the time zone name */
|
2005-11-06 07:13:33 +00:00
|
|
|
|
localZoneString = AUTORELEASE([localZoneString mutableCopy]);
|
2004-10-11 03:08:54 +00:00
|
|
|
|
[(NSMutableString *)localZoneString deletePrefix: tzdir];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
if ([localZoneString hasPrefix: @"/"])
|
2004-10-11 03:08:54 +00:00
|
|
|
|
{
|
|
|
|
|
[(NSMutableString *)localZoneString deletePrefix: @"/"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2005-11-06 07:13:33 +00:00
|
|
|
|
{
|
|
|
|
|
localZoneString = nil;
|
|
|
|
|
}
|
2004-10-11 03:08:54 +00:00
|
|
|
|
}
|
|
|
|
|
#if HAVE_TZSET
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/*
|
2004-10-11 03:08:54 +00:00
|
|
|
|
* Try to get timezone from tzset and tzname
|
2004-02-29 21:17:40 +00:00
|
|
|
|
*/
|
2000-01-05 14:53:03 +00:00
|
|
|
|
if (localZoneString == nil)
|
|
|
|
|
{
|
2004-10-11 03:08:54 +00:00
|
|
|
|
tzset();
|
|
|
|
|
if (tzname[0] != NULL && *tzname[0] != '\0')
|
2006-02-21 15:44:04 +00:00
|
|
|
|
localZoneString = [NSString stringWithUTF8String: tzname[0]];
|
2000-01-05 14:53:03 +00:00
|
|
|
|
}
|
2003-09-04 03:28:14 +00:00
|
|
|
|
#endif
|
2004-02-29 21:17:40 +00:00
|
|
|
|
|
2006-02-22 09:30:55 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/*
|
|
|
|
|
* Try to get timezone from windows registry.
|
|
|
|
|
*/
|
|
|
|
|
{
|
|
|
|
|
HKEY regkey;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2005-11-06 07:13:33 +00:00
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
|
|
|
|
"SYSTEM\\CurrentControlSet\\Control\\TimeZoneInformation",
|
|
|
|
|
0,
|
|
|
|
|
KEY_READ,
|
|
|
|
|
®key))
|
2004-02-29 21:17:40 +00:00
|
|
|
|
{
|
2004-05-21 15:39:02 +00:00
|
|
|
|
char buf[255];
|
|
|
|
|
DWORD bufsize=255;
|
2004-02-29 21:17:40 +00:00
|
|
|
|
DWORD type;
|
2005-11-06 07:13:33 +00:00
|
|
|
|
|
|
|
|
|
if (ERROR_SUCCESS == RegQueryValueExA(regkey,
|
|
|
|
|
"StandardName",
|
|
|
|
|
0,
|
|
|
|
|
&type,
|
|
|
|
|
buf,
|
|
|
|
|
&bufsize))
|
2004-02-29 21:17:40 +00:00
|
|
|
|
{
|
2005-11-06 07:13:33 +00:00
|
|
|
|
bufsize = strlen(buf);
|
2004-02-29 21:17:40 +00:00
|
|
|
|
while (bufsize && isspace(buf[bufsize-1]))
|
|
|
|
|
{
|
|
|
|
|
bufsize--;
|
|
|
|
|
}
|
2005-11-06 07:13:33 +00:00
|
|
|
|
localZoneString
|
2006-02-21 18:41:59 +00:00
|
|
|
|
= [NSString stringWithCString: buf length: bufsize];
|
2004-02-29 21:17:40 +00:00
|
|
|
|
}
|
|
|
|
|
RegCloseKey(regkey);
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (localZoneString != nil)
|
2000-01-05 14:53:03 +00:00
|
|
|
|
{
|
2004-10-11 03:08:54 +00:00
|
|
|
|
NSDebugLLog (@"NSTimeZone", @"Using zone %@", localZoneString);
|
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
|
|
|
|
}
|
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns an array of all the known regions.<br />
|
|
|
|
|
* There are 24 elements, of course, one for each time zone.
|
|
|
|
|
* Each element contains an array of NSStrings which are
|
|
|
|
|
* the region names.
|
|
|
|
|
*/
|
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
|
|
|
|
static NSArray *regionsArray = nil;
|
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/* We create the array only when we need it to reduce overhead. */
|
2001-01-30 12:05:02 +00:00
|
|
|
|
if (regionsArray != nil)
|
2006-02-21 15:44:04 +00:00
|
|
|
|
{
|
|
|
|
|
return regionsArray;
|
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
|
|
|
|
if (regionsArray == nil)
|
|
|
|
|
{
|
|
|
|
|
CREATE_AUTORELEASE_POOL(pool);
|
|
|
|
|
int index, i;
|
|
|
|
|
char name[80];
|
|
|
|
|
FILE *fp;
|
|
|
|
|
NSMutableArray *temp_array[24];
|
|
|
|
|
NSString *path;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 24; i++)
|
|
|
|
|
{
|
|
|
|
|
temp_array[i] = [NSMutableArray array];
|
|
|
|
|
}
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
2006-02-21 15:44:04 +00:00
|
|
|
|
path = _time_zone_path (REGIONS_FILE, nil);
|
|
|
|
|
if (path != nil)
|
|
|
|
|
{
|
2005-10-11 19:09:26 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
2006-02-21 15:44:04 +00:00
|
|
|
|
unichar mode[3];
|
|
|
|
|
|
|
|
|
|
mode[0] = 'r';
|
|
|
|
|
mode[1] = 'b';
|
|
|
|
|
mode[2] = '\0';
|
|
|
|
|
|
|
|
|
|
fp = _wfopen((const unichar*)[path fileSystemRepresentation], mode);
|
2001-01-30 12:05:02 +00:00
|
|
|
|
#else
|
2006-02-21 15:44:04 +00:00
|
|
|
|
fp = fopen([path fileSystemRepresentation], "r");
|
2001-01-30 12:05:02 +00:00
|
|
|
|
#endif
|
2006-02-21 15:44:04 +00:00
|
|
|
|
if (fp == NULL)
|
|
|
|
|
{
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
|
|
|
|
[NSException
|
|
|
|
|
raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Failed to open time zone regions array file."];
|
|
|
|
|
}
|
|
|
|
|
while (fscanf(fp, "%d %s", &index, name) == 2)
|
|
|
|
|
{
|
|
|
|
|
[temp_array[index]
|
|
|
|
|
addObject: [NSString stringWithUTF8String: name]];
|
|
|
|
|
}
|
|
|
|
|
fclose(fp);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-02-21 17:13:19 +00:00
|
|
|
|
NSString *zonedir = [NSTimeZone getTimeZoneFile: @"WET"];
|
2006-02-21 15:44:04 +00:00
|
|
|
|
|
2006-02-21 17:13:19 +00:00
|
|
|
|
if (tzdir != nil)
|
2006-02-21 15:44:04 +00:00
|
|
|
|
{
|
2006-02-21 17:13:19 +00:00
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
2006-02-21 15:44:04 +00:00
|
|
|
|
NSDirectoryEnumerator *enumerator;
|
|
|
|
|
NSString *name;
|
|
|
|
|
|
2006-02-21 17:13:19 +00:00
|
|
|
|
zonedir = [zonedir stringByDeletingLastPathComponent];
|
2006-02-21 15:44:04 +00:00
|
|
|
|
enumerator = [mgr enumeratorAtPath: zonedir];
|
|
|
|
|
while ((name = [enumerator nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
NSTimeZone *zone = nil;
|
|
|
|
|
BOOL isDir;
|
|
|
|
|
|
|
|
|
|
// FIXME: check file validity.
|
|
|
|
|
|
2006-02-21 17:13:19 +00:00
|
|
|
|
path = [zonedir stringByAppendingPathComponent: name];
|
2006-02-21 15:44:04 +00:00
|
|
|
|
if ([mgr fileExistsAtPath: path isDirectory: &isDir]
|
|
|
|
|
&& isDir == NO)
|
|
|
|
|
{
|
|
|
|
|
zone = [zoneDictionary objectForKey: name];
|
|
|
|
|
if (zone == nil)
|
|
|
|
|
{
|
|
|
|
|
NSData *data;
|
|
|
|
|
|
|
|
|
|
data = [NSData dataWithContentsOfFile: path];
|
|
|
|
|
zone = [[self alloc] initWithName: name data: data];
|
|
|
|
|
AUTORELEASE(zone);
|
|
|
|
|
}
|
|
|
|
|
if (zone != nil)
|
|
|
|
|
{
|
|
|
|
|
int offset;
|
|
|
|
|
NSArray *details;
|
|
|
|
|
NSTimeZoneDetail *detail;
|
|
|
|
|
NSEnumerator *e;
|
|
|
|
|
|
|
|
|
|
details = [zone timeZoneDetailArray];
|
|
|
|
|
e = [details objectEnumerator];
|
|
|
|
|
|
|
|
|
|
while ((detail = [e nextObject]) != nil)
|
|
|
|
|
{
|
|
|
|
|
if ([detail isDaylightSavingTime] == NO)
|
|
|
|
|
{
|
|
|
|
|
break; // Found a standard time
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (detail == nil && [details count] > 0)
|
|
|
|
|
{
|
|
|
|
|
// If no standard time
|
|
|
|
|
detail = [details objectAtIndex: 0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offset = [detail secondsFromGMT];
|
|
|
|
|
if (offset < 0)
|
|
|
|
|
{
|
|
|
|
|
offset = -offset;
|
|
|
|
|
offset %= (60 * 60 * 24);
|
|
|
|
|
offset = -offset;
|
|
|
|
|
offset += (60 * 60 * 24);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
offset %= (60 * 60 * 24);
|
|
|
|
|
}
|
|
|
|
|
offset /= (60 * 60);
|
|
|
|
|
|
|
|
|
|
[temp_array[offset] addObject: name];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
regionsArray = [[NSArray alloc] initWithObjects: temp_array count: 24];
|
|
|
|
|
RELEASE(pool);
|
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return regionsArray;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Return a timezone for the specified offset from GMT.<br />
|
|
|
|
|
* The timezone returned does <em>not</em> use daylight savings time.
|
|
|
|
|
* The actual timezone returned has an offset rounded to the nearest
|
|
|
|
|
* minute.<br />
|
|
|
|
|
* Time zones with an offset of more than +/- 18 hours are disallowed,
|
|
|
|
|
* and nil is returned.
|
|
|
|
|
*/
|
1999-08-25 16:12:36 +00:00
|
|
|
|
+ (NSTimeZone*) timeZoneForSecondsFromGMT: (int)seconds
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
NSTimeZone *zone;
|
|
|
|
|
|
2006-02-27 09:35:19 +00:00
|
|
|
|
zone = [[GSAbsTimeZone alloc] initWithOffset: seconds name: nil];
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return AUTORELEASE(zone);
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* Returns a timezone for the specified abbreviation. The same abbreviations
|
2004-02-29 21:17:40 +00:00
|
|
|
|
* are used in different regions so this isn't particularly useful.<br />
|
|
|
|
|
* Calls NSTimeZone-abbreviation dictionary an so uses a lot of memory.
|
2002-09-30 16:54:29 +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;
|
2006-02-21 17:13:19 +00:00
|
|
|
|
NSString *name;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2006-02-21 17:13:19 +00:00
|
|
|
|
name = [[self abbreviationDictionary] objectForKey: abbreviation];
|
|
|
|
|
if (name == nil)
|
|
|
|
|
{
|
|
|
|
|
zone = nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
zone = [self timeZoneWithName: name data: nil];
|
|
|
|
|
}
|
2001-01-30 20:47:05 +00:00
|
|
|
|
return zone;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a timezone for the specified name.
|
|
|
|
|
*/
|
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
|
|
|
|
|
2002-09-30 17:14:51 +00:00
|
|
|
|
zone = [defaultPlaceholderTimeZone initWithName: aTimeZoneName data: nil];
|
2001-01-31 11:29:55 +00:00
|
|
|
|
return AUTORELEASE(zone);
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
2004-02-29 21:17:40 +00:00
|
|
|
|
* Returns a timezone for aTimeZoneName, created from the supplied
|
|
|
|
|
* time zone data. Data must be in TZ format as per the Olson database.
|
2002-09-30 16:54:29 +00:00
|
|
|
|
*/
|
2004-03-28 11:13:36 +00:00
|
|
|
|
+ (NSTimeZone*) timeZoneWithName: (NSString*)name data: (NSData*)data
|
2001-01-30 20:47:05 +00:00
|
|
|
|
{
|
2002-09-30 17:14:51 +00:00
|
|
|
|
NSTimeZone *zone;
|
|
|
|
|
|
2004-03-28 11:13:36 +00:00
|
|
|
|
zone = [defaultPlaceholderTimeZone initWithName: name data: data];
|
2002-09-30 17:14:51 +00:00
|
|
|
|
return AUTORELEASE(zone);
|
2001-01-30 20:47:05 +00:00
|
|
|
|
}
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the abbreviation for this timezone now.
|
|
|
|
|
* Invokes -abbreviationForDate:
|
|
|
|
|
*/
|
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
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the abbreviation for this timezone at aDate. This may differ
|
|
|
|
|
* depending on whether daylight savings time is in effect or not.
|
|
|
|
|
*/
|
|
|
|
|
- (NSString*) abbreviationForDate: (NSDate*)aDate
|
1995-08-23 16:13:42 +00:00
|
|
|
|
{
|
2001-01-30 12:05:02 +00:00
|
|
|
|
NSTimeZoneDetail *detail;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
NSString *abbr;
|
|
|
|
|
|
|
|
|
|
detail = [self timeZoneDetailForDate: aDate];
|
|
|
|
|
abbr = [detail timeZoneAbbreviation];
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return abbr;
|
1995-08-23 16:13:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the Class for this object
|
|
|
|
|
*/
|
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
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the data with which the receiver was initialised.
|
|
|
|
|
*/
|
|
|
|
|
- (NSData*) data
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the name of this object.
|
|
|
|
|
*/
|
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
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (id) init
|
|
|
|
|
{
|
2002-09-30 17:14:51 +00:00
|
|
|
|
return [self initWithName: @"NSLocalTimeZone" data: nil];
|
2002-09-30 16:54:29 +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];
|
2002-09-30 17:14:51 +00:00
|
|
|
|
self = [self initWithName: name data: nil];
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
1995-08-23 16:13:42 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initialise a timezone with the supplied name. May return a cached
|
|
|
|
|
* timezone object rather than the newly created one.
|
|
|
|
|
*/
|
2001-01-30 20:47:05 +00:00
|
|
|
|
- (id) initWithName: (NSString*)name
|
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return [self initWithName: name data: nil];
|
2001-01-30 20:47:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initialises a time zone object using the supplied data object.<br />
|
|
|
|
|
* This method is intended for internal use by the NSTimeZone
|
|
|
|
|
* class cluster.
|
|
|
|
|
* Don't use it ... use -initWithName: instead.
|
|
|
|
|
*/
|
2001-01-30 20:47:05 +00:00
|
|
|
|
- (id) initWithName: (NSString*)name data: (NSData*)data
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented: _cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a boolean indicating whether daylight savings time is in
|
|
|
|
|
* effect now. Invokes -isDaylightSavingTimeForDate:
|
|
|
|
|
*/
|
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
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns a boolean indicating whether daylight savings time is in
|
|
|
|
|
* effect for this time zone at aDate.
|
|
|
|
|
*/
|
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;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
BOOL isDST;
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
|
|
|
|
detail = [self timeZoneDetailForDate: aDate];
|
2002-09-30 16:54:29 +00:00
|
|
|
|
isDST = [detail isDaylightSavingTimeZone];
|
|
|
|
|
|
|
|
|
|
return isDST;
|
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
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns TRUE if the time zones have the same name.
|
|
|
|
|
*/
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (BOOL) isEqualToTimeZone: (NSTimeZone*)aTimeZone
|
|
|
|
|
{
|
|
|
|
|
if (aTimeZone == self)
|
|
|
|
|
return YES;
|
2002-10-01 10:25:40 +00:00
|
|
|
|
if ([[self name] isEqual: [aTimeZone name]] == NO)
|
|
|
|
|
return NO;
|
|
|
|
|
if (([self data] == nil && [aTimeZone data] == nil)
|
|
|
|
|
|| [[self name] isEqual: [aTimeZone name]] == YES)
|
2001-01-30 12:05:02 +00:00
|
|
|
|
return YES;
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the name of the timezone
|
|
|
|
|
*/
|
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)
|
2002-10-01 10:25:40 +00:00
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
2001-01-31 05:58:59 +00:00
|
|
|
|
return [super replacementObjectForPortCoder: aCoder];
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the number of seconds by which the receiver differs
|
|
|
|
|
* from Greenwich Mean Time at the current date and time.<br />
|
|
|
|
|
* Invokes -secondsFromGMTForDate:
|
|
|
|
|
*/
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (int) secondsFromGMT
|
|
|
|
|
{
|
|
|
|
|
return [self secondsFromGMTForDate: [NSDate date]];
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2002-09-28 09:30:38 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the number of seconds by which the receiver differs
|
2002-09-30 16:54:29 +00:00
|
|
|
|
* from Greenwich Mean Time at the date aDate.<br />
|
2005-11-06 13:53:40 +00:00
|
|
|
|
* If the time zone uses daylight savings time, the returned value
|
2002-09-28 09:30:38 +00:00
|
|
|
|
* will vary at different times of year.
|
|
|
|
|
*/
|
2002-09-30 16:54:29 +00:00
|
|
|
|
- (int) secondsFromGMTForDate: (NSDate*)aDate
|
2001-01-30 12:05:02 +00:00
|
|
|
|
{
|
|
|
|
|
NSTimeZoneDetail *detail;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
int offset;
|
2001-01-30 12:05:02 +00:00
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
detail = [self timeZoneDetailForDate: aDate];
|
|
|
|
|
offset = [detail timeZoneSecondsFromGMT];
|
|
|
|
|
|
|
|
|
|
return offset;
|
1997-10-17 13:35:52 +00:00
|
|
|
|
}
|
1997-11-03 14:30:13 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* DEPRECATED: see NSTimeZoneDetail
|
2004-02-29 21:17:40 +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
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* DEPRECATED: see NSTimeZoneDetail
|
2004-02-29 21:17:40 +00:00
|
|
|
|
*/
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)date
|
|
|
|
|
{
|
|
|
|
|
return [self subclassResponsibility: _cmd];
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the name of this timezone.
|
|
|
|
|
*/
|
2001-01-30 12:05:02 +00:00
|
|
|
|
- (NSString*) timeZoneName
|
|
|
|
|
{
|
|
|
|
|
return [self name];
|
|
|
|
|
}
|
|
|
|
|
|
1997-10-17 13:35:52 +00:00
|
|
|
|
@end
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
/**
|
2006-02-22 09:30:55 +00:00
|
|
|
|
* This class serves no useful purpose in GNUstep other than to provide
|
|
|
|
|
* a backup mechanism for handling abbreviations where the precomputed
|
|
|
|
|
* data files cannot be found. It is provided primarily for backward
|
|
|
|
|
* compatibility with the OpenStep spec. It is missing entirely from MacOS-X.
|
2002-10-01 10:25:40 +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
|
|
|
|
{
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return [NSString stringWithFormat: @"%@(%@, %s%d)", [self name],
|
|
|
|
|
[self timeZoneAbbreviation],
|
|
|
|
|
([self isDaylightSavingTimeZone]? "IS_DST, ": ""),
|
|
|
|
|
[self timeZoneSecondsFromGMT]];
|
1997-11-03 14:30:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* DEPRECATED: Class is no longer used.
|
2004-02-29 21:17:40 +00:00
|
|
|
|
*/
|
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
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* DEPRECATED: Class is no longer used.
|
2004-02-29 21:17:40 +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
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* DEPRECATED: Class is no longer used.
|
2004-02-29 21:17:40 +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
|
|
|
|
|
2006-02-21 17:13:19 +00:00
|
|
|
|
/**
|
|
|
|
|
* Common locations for timezone info on unix systems.
|
|
|
|
|
*/
|
|
|
|
|
static NSString *zoneDirs[] = {
|
2006-04-12 19:41:44 +00:00
|
|
|
|
#ifdef TZDIR
|
2006-04-17 14:00:05 +00:00
|
|
|
|
@TZDIR,
|
2006-04-12 19:41:44 +00:00
|
|
|
|
#endif
|
2006-02-21 17:13:19 +00:00
|
|
|
|
@"/usr/share/zoneinfo",
|
|
|
|
|
@"/usr/lib/zoneinfo",
|
|
|
|
|
@"/usr/local/share/zoneinfo",
|
|
|
|
|
@"/usr/local/lib/zoneinfo",
|
|
|
|
|
@"/etc/zoneinfo",
|
|
|
|
|
@"/usr/local/etc/zoneinfo"
|
|
|
|
|
};
|
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns the path to the named zone info file.
|
|
|
|
|
*/
|
1999-08-25 16:12:36 +00:00
|
|
|
|
+ (NSString*) getTimeZoneFile: (NSString *)name
|
1997-10-18 19:49:50 +00:00
|
|
|
|
{
|
2006-02-21 17:13:19 +00:00
|
|
|
|
static BOOL beenHere = NO;
|
2004-10-11 03:08:54 +00:00
|
|
|
|
NSString *dir = nil;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
|
2006-02-21 17:13:19 +00:00
|
|
|
|
if (beenHere == NO && tzdir == nil)
|
|
|
|
|
{
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
|
|
|
|
if (beenHere == NO && tzdir == nil)
|
|
|
|
|
{
|
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
|
|
|
NSString *zonedir = nil;
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(zoneDirs)/sizeof(zoneDirs[0]); i++)
|
|
|
|
|
{
|
|
|
|
|
BOOL isDir;
|
|
|
|
|
|
|
|
|
|
zonedir
|
|
|
|
|
= [zoneDirs[i] stringByAppendingPathComponent: POSIX_TZONES];
|
|
|
|
|
if ([mgr fileExistsAtPath: zonedir isDirectory: &isDir] && isDir)
|
|
|
|
|
{
|
|
|
|
|
tzdir = RETAIN(zonedir);
|
|
|
|
|
break; // use first one
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
beenHere = YES;
|
|
|
|
|
}
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
/* Use the system zone info if possible, otherwise, use our installed
|
2004-10-11 03:08:54 +00:00
|
|
|
|
info. */
|
|
|
|
|
if (tzdir && [[NSFileManager defaultManager] fileExistsAtPath:
|
2006-02-21 17:13:19 +00:00
|
|
|
|
[tzdir stringByAppendingPathComponent: name]] == YES)
|
|
|
|
|
{
|
|
|
|
|
dir = tzdir;
|
|
|
|
|
}
|
2004-10-11 03:08:54 +00:00
|
|
|
|
if (dir == nil)
|
2006-02-21 17:13:19 +00:00
|
|
|
|
{
|
|
|
|
|
dir = _time_zone_path (ZONES_DIR, nil);
|
|
|
|
|
}
|
2003-04-28 02:29:49 +00:00
|
|
|
|
return [dir stringByAppendingPathComponent: name];
|
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
|
2002-09-30 16:54:29 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
|
2006-02-22 09:30:55 +00:00
|
|
|
|
#if defined(__MINGW32__)
|
2004-02-29 21:17:40 +00:00
|
|
|
|
/* Timezone information data as stored in the registry */
|
|
|
|
|
typedef struct TZI_format {
|
|
|
|
|
LONG Bias;
|
|
|
|
|
LONG StandardBias;
|
|
|
|
|
LONG DaylightBias;
|
|
|
|
|
SYSTEMTIME StandardDate;
|
|
|
|
|
SYSTEMTIME DaylightDate;
|
|
|
|
|
} TZI;
|
|
|
|
|
|
|
|
|
|
static inline unsigned int
|
|
|
|
|
lastDayOfGregorianMonth(int month, int year)
|
|
|
|
|
{
|
|
|
|
|
switch (month)
|
|
|
|
|
{
|
|
|
|
|
case 2:
|
|
|
|
|
if ((((year % 4) == 0) && ((year % 100) != 0))
|
|
|
|
|
|| ((year % 400) == 0))
|
|
|
|
|
return 29;
|
|
|
|
|
else
|
|
|
|
|
return 28;
|
|
|
|
|
case 4:
|
|
|
|
|
case 6:
|
|
|
|
|
case 9:
|
|
|
|
|
case 11: return 30;
|
|
|
|
|
default: return 31;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* IMPORT from NSCalendar date */
|
|
|
|
|
void
|
|
|
|
|
GSBreakTime(NSTimeInterval when, int *year, int *month, int *day,
|
|
|
|
|
int *hour, int *minute, int *second, int *mil);
|
2006-03-10 10:46:37 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
|
2005-11-05 16:20:19 +00:00
|
|
|
|
|
|
|
|
|
/* FIXME
|
2005-11-06 07:13:33 +00:00
|
|
|
|
* It's not unicode ... which is OK as the timezone registry
|
2005-11-05 16:20:19 +00:00
|
|
|
|
* names are ascii ... but we ought to be consistent.
|
|
|
|
|
*/
|
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
@implementation GSWindowsTimeZone
|
|
|
|
|
|
|
|
|
|
- (NSString*) abbreviationForDate: (NSDate*)aDate
|
|
|
|
|
{
|
2005-11-06 07:13:33 +00:00
|
|
|
|
if ([self isDaylightSavingTimeForDate: aDate])
|
2004-02-29 21:17:40 +00:00
|
|
|
|
return daylightZoneNameAbbr;
|
|
|
|
|
return timeZoneNameAbbr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSData*) data
|
|
|
|
|
{
|
2005-11-06 07:13:33 +00:00
|
|
|
|
return 0;
|
2004-02-29 21:17:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
RELEASE(timeZoneName);
|
|
|
|
|
RELEASE(daylightZoneName);
|
|
|
|
|
RELEASE(timeZoneNameAbbr);
|
|
|
|
|
RELEASE(daylightZoneNameAbbr);
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithName: (NSString*)name data: (NSData*)data
|
|
|
|
|
{
|
2005-11-06 07:13:33 +00:00
|
|
|
|
HKEY regDirKey;
|
|
|
|
|
BOOL isNT = NO;
|
|
|
|
|
BOOL regFound = NO;
|
|
|
|
|
|
|
|
|
|
/* Open the key in the local machine hive where
|
|
|
|
|
* the time zone data is stored. */
|
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
|
|
|
|
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
|
|
|
|
|
0,
|
|
|
|
|
KEY_READ,
|
|
|
|
|
®DirKey))
|
|
|
|
|
{
|
|
|
|
|
isNT = YES;
|
|
|
|
|
regFound = YES;
|
|
|
|
|
}
|
2004-02-29 21:17:40 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2005-11-06 07:13:33 +00:00
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
|
|
|
|
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones",
|
|
|
|
|
0,
|
|
|
|
|
KEY_READ,
|
|
|
|
|
®DirKey))
|
|
|
|
|
{
|
|
|
|
|
regFound = YES;
|
|
|
|
|
}
|
2004-02-29 21:17:40 +00:00
|
|
|
|
}
|
2004-05-21 15:39:02 +00:00
|
|
|
|
|
|
|
|
|
if (regFound)
|
2005-11-06 07:13:33 +00:00
|
|
|
|
{
|
|
|
|
|
/* Iterate over all subKeys in the registry to find the right one.
|
|
|
|
|
Unfortunately name is a localized value. The keys in the registry are
|
|
|
|
|
unlocalized names. */
|
|
|
|
|
CHAR achKey[255]; // buffer for subkey name
|
|
|
|
|
DWORD cbName; // size of name string
|
|
|
|
|
CHAR achClass[MAX_PATH] = ""; // buffer for class name
|
|
|
|
|
DWORD cchClassName = MAX_PATH; // size of class string
|
|
|
|
|
DWORD cSubKeys=0; // number of subkeys
|
|
|
|
|
DWORD cbMaxSubKey; // longest subkey size
|
|
|
|
|
DWORD cchMaxClass; // longest class string
|
|
|
|
|
DWORD cValues; // number of values for key
|
|
|
|
|
DWORD cchMaxValue; // longest value name
|
|
|
|
|
DWORD cbMaxValueData; // longest value data
|
|
|
|
|
DWORD cbSecurityDescriptor; // size of security descriptor
|
|
|
|
|
FILETIME ftLastWriteTime; // last write time
|
|
|
|
|
DWORD i;
|
|
|
|
|
DWORD retCode;
|
|
|
|
|
BOOL tzFound = NO;
|
|
|
|
|
|
|
|
|
|
/* Get the class name and the value count. */
|
|
|
|
|
retCode = RegQueryInfoKeyA(
|
|
|
|
|
regDirKey, // key handle
|
|
|
|
|
achClass, // buffer for class name
|
|
|
|
|
&cchClassName, // size of class string
|
|
|
|
|
NULL, // reserved
|
|
|
|
|
&cSubKeys, // number of subkeys
|
|
|
|
|
&cbMaxSubKey, // longest subkey size
|
|
|
|
|
&cchMaxClass, // longest class string
|
|
|
|
|
&cValues, // number of values for this key
|
|
|
|
|
&cchMaxValue, // longest value name
|
|
|
|
|
&cbMaxValueData, // longest value data
|
|
|
|
|
&cbSecurityDescriptor, // security descriptor
|
|
|
|
|
&ftLastWriteTime); // last write time
|
|
|
|
|
|
|
|
|
|
if (cSubKeys && (retCode == ERROR_SUCCESS))
|
|
|
|
|
{
|
|
|
|
|
const char *cName = [name cString];
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < cSubKeys && !tzFound; i++)
|
|
|
|
|
{
|
|
|
|
|
cbName = 255;
|
|
|
|
|
|
|
|
|
|
retCode = RegEnumKeyExA(regDirKey,
|
|
|
|
|
i,
|
|
|
|
|
achKey,
|
|
|
|
|
&cbName,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL,
|
|
|
|
|
&ftLastWriteTime);
|
|
|
|
|
if (retCode == ERROR_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
char keyBuffer[16384];
|
|
|
|
|
HKEY regKey;
|
|
|
|
|
|
|
|
|
|
if (isNT)
|
|
|
|
|
{
|
|
|
|
|
sprintf(keyBuffer, "SOFTWARE\\Microsoft\\Windows NT"
|
|
|
|
|
"\\CurrentVersion\\Time Zones\\%s", achKey);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sprintf(keyBuffer, "SOFTWARE\\Microsoft\\Windows"
|
|
|
|
|
"\\CurrentVersion\\Time Zones\\%s", achKey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
|
|
|
|
keyBuffer,
|
|
|
|
|
0,
|
|
|
|
|
KEY_READ,
|
|
|
|
|
®Key))
|
|
|
|
|
{
|
|
|
|
|
char buf[256];
|
|
|
|
|
char standardName[256];
|
|
|
|
|
char daylightName[256];
|
|
|
|
|
DWORD bufsize;
|
|
|
|
|
DWORD type;
|
|
|
|
|
|
|
|
|
|
/* check standardname */
|
|
|
|
|
standardName[0]='\0';
|
|
|
|
|
bufsize=sizeof(buf);
|
|
|
|
|
if (ERROR_SUCCESS == RegQueryValueExA(regKey,
|
|
|
|
|
"Std",
|
|
|
|
|
0,
|
|
|
|
|
&type,
|
|
|
|
|
buf,
|
|
|
|
|
&bufsize))
|
2005-02-22 11:22:44 +00:00
|
|
|
|
{
|
2005-11-06 07:13:33 +00:00
|
|
|
|
strcpy(standardName, buf);
|
|
|
|
|
if (strcmp(standardName, cName) == 0)
|
|
|
|
|
tzFound = YES;
|
2004-05-21 15:39:02 +00:00
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2005-11-06 07:13:33 +00:00
|
|
|
|
/* check daylightname */
|
|
|
|
|
daylightName[0]='\0';
|
|
|
|
|
bufsize = sizeof(buf);
|
|
|
|
|
if (ERROR_SUCCESS == RegQueryValueExA(regKey,
|
|
|
|
|
"Dlt",
|
|
|
|
|
0,
|
|
|
|
|
&type,
|
|
|
|
|
buf,
|
|
|
|
|
&bufsize))
|
|
|
|
|
{
|
|
|
|
|
strcpy(daylightName, buf);
|
|
|
|
|
if (strcmp(daylightName, cName) == 0)
|
|
|
|
|
tzFound = YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tzFound)
|
|
|
|
|
{
|
|
|
|
|
/* Read in the time zone data */
|
|
|
|
|
bufsize = sizeof(buf);
|
|
|
|
|
if (ERROR_SUCCESS == RegQueryValueExA(regKey,
|
|
|
|
|
"TZI",
|
|
|
|
|
0,
|
|
|
|
|
&type,
|
|
|
|
|
buf,
|
|
|
|
|
&bufsize))
|
|
|
|
|
{
|
|
|
|
|
TZI *tzi = (void*)buf;
|
|
|
|
|
Bias = tzi->Bias;
|
|
|
|
|
StandardBias = tzi->StandardBias;
|
|
|
|
|
DaylightBias = tzi->DaylightBias;
|
|
|
|
|
StandardDate = tzi->StandardDate;
|
|
|
|
|
DaylightDate = tzi->DaylightDate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set the standard name for the time zone. */
|
|
|
|
|
if (strlen(standardName))
|
|
|
|
|
{
|
|
|
|
|
int a, b;
|
|
|
|
|
|
|
|
|
|
ASSIGN(timeZoneName,
|
2006-02-21 15:44:04 +00:00
|
|
|
|
[NSString stringWithUTF8String: standardName]);
|
2005-11-06 07:13:33 +00:00
|
|
|
|
|
|
|
|
|
/* Abbr generated here is IMHO a
|
|
|
|
|
* bit suspicous but I kept it */
|
|
|
|
|
for (a = 0, b = 0; standardName[a]; a++)
|
|
|
|
|
{
|
|
|
|
|
if (isupper(standardName[a]))
|
|
|
|
|
standardName[b++] = standardName[a];
|
|
|
|
|
}
|
|
|
|
|
standardName[b] = 0;
|
|
|
|
|
ASSIGN(timeZoneNameAbbr,
|
2006-02-21 15:44:04 +00:00
|
|
|
|
[NSString stringWithUTF8String: standardName]);
|
2005-11-06 07:13:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set the daylight savings name for the time zone. */
|
|
|
|
|
if (strlen(daylightName))
|
|
|
|
|
{
|
|
|
|
|
int a, b;
|
|
|
|
|
|
|
|
|
|
ASSIGN(daylightZoneName,
|
2006-02-21 15:44:04 +00:00
|
|
|
|
[NSString stringWithUTF8String: daylightName]);
|
2005-11-06 07:13:33 +00:00
|
|
|
|
|
|
|
|
|
/* Abbr generated here is IMHO
|
|
|
|
|
* a bit suspicous but I kept it */
|
|
|
|
|
for (a = 0, b = 0; daylightName[a]; a++)
|
|
|
|
|
{
|
|
|
|
|
if (isupper(daylightName[a]))
|
|
|
|
|
daylightName[b++] = daylightName[a];
|
|
|
|
|
}
|
|
|
|
|
daylightName[b] = 0;
|
|
|
|
|
ASSIGN(daylightZoneNameAbbr,
|
2006-02-21 15:44:04 +00:00
|
|
|
|
[NSString stringWithUTF8String: daylightName]);
|
2005-11-06 07:13:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
RegCloseKey(regKey);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
RegCloseKey(regDirKey);
|
|
|
|
|
}
|
2004-02-29 21:17:40 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isDaylightSavingTimeForDate: (NSDate*)aDate
|
|
|
|
|
{
|
|
|
|
|
int year, month, day, hour, minute, second, mil;
|
|
|
|
|
int dow;
|
|
|
|
|
int daylightdate, count, maxdate;
|
|
|
|
|
NSTimeInterval when;
|
|
|
|
|
|
|
|
|
|
if (DaylightDate.wMonth == 0)
|
|
|
|
|
return NO;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
when = [aDate timeIntervalSinceReferenceDate] - Bias*60;
|
|
|
|
|
|
|
|
|
|
GSBreakTime(when, &year, &month, &day, &hour, &minute, &second, &mil);
|
|
|
|
|
|
|
|
|
|
// Before April or after October is Std
|
|
|
|
|
if (month < DaylightDate.wMonth || month > StandardDate.wMonth)
|
|
|
|
|
return NO;
|
|
|
|
|
// After April and before October is DST
|
|
|
|
|
if (month > DaylightDate.wMonth && month < StandardDate.wMonth)
|
|
|
|
|
return YES;
|
2006-03-10 10:46:37 +00:00
|
|
|
|
dow = ((int)((when / 86400.0) + GREGORIAN_REFERENCE)) % 7;
|
2004-02-29 21:17:40 +00:00
|
|
|
|
if (dow < 0)
|
|
|
|
|
dow += 7;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-02-29 21:17:40 +00:00
|
|
|
|
if (month == DaylightDate.wMonth /* April */)
|
|
|
|
|
{
|
|
|
|
|
daylightdate = day - dow + DaylightDate.wDayOfWeek;
|
|
|
|
|
maxdate = lastDayOfGregorianMonth(DaylightDate.wMonth, year)-7;
|
|
|
|
|
while (daylightdate > 7)
|
|
|
|
|
daylightdate-=7;
|
|
|
|
|
if (daylightdate < 1)
|
|
|
|
|
daylightdate += 7;
|
|
|
|
|
count=DaylightDate.wDay;
|
|
|
|
|
while (count>1 && daylightdate < maxdate)
|
|
|
|
|
{
|
|
|
|
|
daylightdate+=7;
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
if (day > daylightdate)
|
|
|
|
|
return YES;
|
|
|
|
|
if (day < daylightdate)
|
|
|
|
|
return NO;
|
|
|
|
|
if (hour > DaylightDate.wHour)
|
|
|
|
|
return YES;
|
|
|
|
|
if (hour < DaylightDate.wHour)
|
|
|
|
|
return NO;
|
|
|
|
|
if (minute > DaylightDate.wMinute)
|
|
|
|
|
return YES;
|
|
|
|
|
if (minute < DaylightDate.wMinute)
|
|
|
|
|
return NO;
|
|
|
|
|
if (second > DaylightDate.wSecond)
|
|
|
|
|
return YES;
|
|
|
|
|
if (second < DaylightDate.wSecond)
|
|
|
|
|
return NO;
|
|
|
|
|
if (mil >= DaylightDate.wMilliseconds)
|
|
|
|
|
return YES;
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
if (month == StandardDate.wMonth /* October */)
|
|
|
|
|
{
|
|
|
|
|
daylightdate = day - dow + StandardDate.wDayOfWeek;
|
|
|
|
|
maxdate = lastDayOfGregorianMonth(StandardDate.wMonth, year)-7;
|
|
|
|
|
while (daylightdate > 7)
|
|
|
|
|
daylightdate-=7;
|
|
|
|
|
if (daylightdate < 1)
|
|
|
|
|
daylightdate += 7;
|
|
|
|
|
count=StandardDate.wDay;
|
|
|
|
|
while (count>1 && daylightdate < maxdate)
|
|
|
|
|
{
|
|
|
|
|
daylightdate+=7;
|
|
|
|
|
count--;
|
|
|
|
|
}
|
|
|
|
|
if (day > daylightdate)
|
|
|
|
|
return NO;
|
|
|
|
|
if (day < daylightdate)
|
|
|
|
|
return YES;
|
|
|
|
|
if (hour > StandardDate.wHour)
|
|
|
|
|
return NO;
|
|
|
|
|
if (hour < StandardDate.wHour)
|
|
|
|
|
return YES;
|
|
|
|
|
if (minute > StandardDate.wMinute)
|
|
|
|
|
return NO;
|
|
|
|
|
if (minute < StandardDate.wMinute)
|
|
|
|
|
return YES;
|
|
|
|
|
if (second > StandardDate.wSecond)
|
|
|
|
|
return NO;
|
|
|
|
|
if (second < StandardDate.wSecond)
|
|
|
|
|
return YES;
|
|
|
|
|
if (mil >= StandardDate.wMilliseconds)
|
|
|
|
|
return NO;
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
return NO; // Never reached
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) name
|
|
|
|
|
{
|
|
|
|
|
return timeZoneName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (int) secondsFromGMTForDate: (NSDate*)aDate
|
|
|
|
|
{
|
2005-11-06 07:13:33 +00:00
|
|
|
|
if ([self isDaylightSavingTimeForDate: aDate])
|
2004-02-29 21:17:40 +00:00
|
|
|
|
return -Bias*60 - DaylightBias*60;
|
|
|
|
|
return -Bias*60 - StandardBias*60;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray*) timeZoneDetailArray
|
|
|
|
|
{
|
2005-03-07 11:19:34 +00:00
|
|
|
|
return [NSArray arrayWithObjects:
|
2005-11-06 07:13:33 +00:00
|
|
|
|
[[[GSTimeZoneDetail alloc] initWithTimeZone: self
|
|
|
|
|
withAbbrev: timeZoneNameAbbr
|
|
|
|
|
withOffset: -Bias*60 - StandardBias*60
|
|
|
|
|
withDST: NO] autorelease],
|
|
|
|
|
[[[GSTimeZoneDetail alloc] initWithTimeZone: self
|
|
|
|
|
withAbbrev: daylightZoneNameAbbr
|
|
|
|
|
withOffset: -Bias*60 - DaylightBias*60
|
|
|
|
|
withDST: YES] autorelease], 0];
|
2004-02-29 21:17:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)aDate
|
|
|
|
|
{
|
|
|
|
|
GSTimeZoneDetail *detail;
|
|
|
|
|
int offset;
|
2005-11-06 07:13:33 +00:00
|
|
|
|
BOOL isDST = [self isDaylightSavingTimeForDate: aDate];
|
2004-02-29 21:17:40 +00:00
|
|
|
|
NSString *abbr;
|
|
|
|
|
|
|
|
|
|
if (isDST)
|
|
|
|
|
{
|
|
|
|
|
offset = -Bias*60 - DaylightBias*60;
|
|
|
|
|
abbr = daylightZoneNameAbbr;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
}
|
2004-02-29 21:17:40 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
offset = -Bias*60 - StandardBias*60;
|
|
|
|
|
abbr = timeZoneNameAbbr;
|
|
|
|
|
}
|
|
|
|
|
detail = [GSTimeZoneDetail alloc];
|
|
|
|
|
detail = [detail initWithTimeZone: self
|
|
|
|
|
withAbbrev: abbr
|
|
|
|
|
withOffset: offset
|
|
|
|
|
withDST: isDST];
|
|
|
|
|
return detail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) timeZoneName
|
|
|
|
|
{
|
|
|
|
|
return timeZoneName;
|
|
|
|
|
}
|
|
|
|
|
@end
|
2006-02-22 09:30:55 +00:00
|
|
|
|
#endif // __MINGW32__
|
2004-02-29 21:17:40 +00:00
|
|
|
|
|
|
|
|
|
|
2002-09-30 16:54:29 +00:00
|
|
|
|
@implementation GSTimeZone
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Perform a binary search of a transitions table to locate the index
|
|
|
|
|
* of the transition to use for a particular time interval since 1970.<br />
|
|
|
|
|
* We locate the index of the highest transition before the date, or zero
|
|
|
|
|
* if there is no transition before it.
|
|
|
|
|
*/
|
2002-10-01 10:25:40 +00:00
|
|
|
|
static TypeInfo*
|
2002-09-30 16:54:29 +00:00
|
|
|
|
chop(NSTimeInterval since, GSTimeZone *zone)
|
|
|
|
|
{
|
2006-01-11 08:37:16 +00:00
|
|
|
|
int32_t when = (int32_t)since;
|
|
|
|
|
int32_t *trans = zone->trans;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
unsigned hi = zone->n_trans;
|
|
|
|
|
unsigned lo = 0;
|
2003-01-03 20:14:47 +00:00
|
|
|
|
unsigned int i;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
|
|
|
|
|
if (hi == 0 || trans[0] > when)
|
|
|
|
|
{
|
|
|
|
|
unsigned n_types = zone->n_types;
|
|
|
|
|
|
|
|
|
|
/*
|
2002-10-01 10:25:40 +00:00
|
|
|
|
* If the first transition is greater than our date,
|
2002-09-30 16:54:29 +00:00
|
|
|
|
* we locate the first non-DST transition and use that offset,
|
|
|
|
|
* or just use the first transition.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < n_types; i++)
|
|
|
|
|
{
|
|
|
|
|
if (zone->types[i].isdst == 0)
|
|
|
|
|
{
|
|
|
|
|
return &zone->types[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return &zone->types[0];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (i = hi/2; hi != lo; i = (hi + lo)/2)
|
|
|
|
|
{
|
|
|
|
|
if (when < trans[i])
|
|
|
|
|
{
|
|
|
|
|
hi = i;
|
|
|
|
|
}
|
|
|
|
|
else if (when > trans[i])
|
|
|
|
|
{
|
|
|
|
|
lo = ++i;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* If we went off the top of the table or the closest transition
|
|
|
|
|
* was later than our date, we step back to find the last
|
|
|
|
|
* transition before our date.
|
|
|
|
|
*/
|
2003-01-03 20:14:47 +00:00
|
|
|
|
if (i > 0 && (i == zone->n_trans || trans[i] > when))
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
return &zone->types[zone->idxs[i]];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NSTimeZoneDetail*
|
2002-10-01 10:25:40 +00:00
|
|
|
|
newDetailInZoneForType(GSTimeZone *zone, TypeInfo *type)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
GSTimeZoneDetail *detail;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
detail = [GSTimeZoneDetail alloc];
|
2002-09-30 16:54:29 +00:00
|
|
|
|
detail = [detail initWithTimeZone: zone
|
2002-10-01 10:25:40 +00:00
|
|
|
|
withAbbrev: type->abbreviation
|
|
|
|
|
withOffset: type->offset
|
|
|
|
|
withDST: type->isdst];
|
2002-09-30 16:54:29 +00:00
|
|
|
|
return detail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) abbreviationForDate: (NSDate*)aDate
|
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
TypeInfo *type = chop([aDate timeIntervalSince1970], self);
|
2002-09-30 16:54:29 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
return type->abbreviation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSData*) data
|
|
|
|
|
{
|
|
|
|
|
return timeZoneData;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
RELEASE(timeZoneName);
|
2002-10-01 10:25:40 +00:00
|
|
|
|
RELEASE(timeZoneData);
|
2006-02-21 15:44:04 +00:00
|
|
|
|
RELEASE(abbreviations);
|
2002-10-01 10:25:40 +00:00
|
|
|
|
if (types != 0)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), types);
|
2002-09-30 16:54:29 +00:00
|
|
|
|
}
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initWithName: (NSString*)name data: (NSData*)data
|
|
|
|
|
{
|
|
|
|
|
static NSString *fileException = @"GSTimeZoneFileException";
|
|
|
|
|
|
|
|
|
|
timeZoneName = [name copy];
|
2002-10-01 10:25:40 +00:00
|
|
|
|
timeZoneData = [data copy];
|
2002-09-30 16:54:29 +00:00
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
const void *bytes = [timeZoneData bytes];
|
|
|
|
|
unsigned length = [timeZoneData length];
|
|
|
|
|
void *buf;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
unsigned pos = 0;
|
|
|
|
|
unsigned i, charcnt;
|
|
|
|
|
unsigned char *abbr;
|
|
|
|
|
struct tzhead *header;
|
|
|
|
|
|
|
|
|
|
if (length < sizeof(struct tzhead))
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: fileException
|
|
|
|
|
format: @"File is too small"];
|
|
|
|
|
}
|
|
|
|
|
header = (struct tzhead *)(bytes + pos);
|
|
|
|
|
pos += sizeof(struct tzhead);
|
2004-10-11 03:08:54 +00:00
|
|
|
|
#ifdef TZ_MAGIC
|
2002-09-30 16:54:29 +00:00
|
|
|
|
if (memcmp(header->tzh_magic, TZ_MAGIC, strlen(TZ_MAGIC)) != 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: fileException
|
|
|
|
|
format: @"TZ_MAGIC is incorrect"];
|
|
|
|
|
}
|
2004-10-11 03:08:54 +00:00
|
|
|
|
#endif
|
2006-01-11 08:37:16 +00:00
|
|
|
|
n_trans = GSSwapBigI32ToHost(*(int32_t*)header->tzh_timecnt);
|
|
|
|
|
n_types = GSSwapBigI32ToHost(*(int32_t*)header->tzh_typecnt);
|
|
|
|
|
charcnt = GSSwapBigI32ToHost(*(int32_t*)header->tzh_charcnt);
|
2002-10-01 10:25:40 +00:00
|
|
|
|
|
|
|
|
|
i = pos;
|
2006-01-11 08:37:16 +00:00
|
|
|
|
i += sizeof(int32_t)*n_trans;
|
2002-10-01 10:25:40 +00:00
|
|
|
|
if (i > length)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: fileException
|
|
|
|
|
format: @"Transitions list is truncated"];
|
|
|
|
|
}
|
2002-10-01 10:25:40 +00:00
|
|
|
|
i += n_trans;
|
|
|
|
|
if (i > length)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
[NSException raise: fileException
|
|
|
|
|
format: @"Transition indexes are truncated"];
|
2002-09-30 16:54:29 +00:00
|
|
|
|
}
|
2002-10-01 10:25:40 +00:00
|
|
|
|
i += sizeof(struct ttinfo)*n_types;
|
|
|
|
|
if (i > length)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: fileException
|
|
|
|
|
format: @"Types list is truncated"];
|
|
|
|
|
}
|
2002-10-01 10:25:40 +00:00
|
|
|
|
if (i + charcnt > length)
|
2002-09-30 16:54:29 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: fileException
|
|
|
|
|
format: @"Abbreviations list is truncated"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2002-10-01 10:25:40 +00:00
|
|
|
|
* Now calculate size we need to store the information
|
|
|
|
|
* for efficient access ... not the same saze as the data
|
|
|
|
|
* we received.
|
2002-09-30 16:54:29 +00:00
|
|
|
|
*/
|
2006-01-11 08:37:16 +00:00
|
|
|
|
i = n_trans * (sizeof(int32_t)+1) + n_types * sizeof(TypeInfo);
|
2002-10-01 10:25:40 +00:00
|
|
|
|
buf = NSZoneMalloc(NSDefaultMallocZone(), i);
|
|
|
|
|
types = (TypeInfo*)buf;
|
|
|
|
|
buf += (n_types * sizeof(TypeInfo));
|
2006-01-11 08:37:16 +00:00
|
|
|
|
trans = (int32_t*)buf;
|
|
|
|
|
buf += (n_trans * sizeof(int32_t));
|
2002-10-01 10:25:40 +00:00
|
|
|
|
idxs = (unsigned char*)buf;
|
|
|
|
|
|
|
|
|
|
/* Read in transitions. */
|
|
|
|
|
for (i = 0; i < n_trans; i++)
|
|
|
|
|
{
|
2006-01-11 08:37:16 +00:00
|
|
|
|
trans[i] = GSSwapBigI32ToHost(*(int32_t*)(bytes + pos));
|
|
|
|
|
pos += sizeof(int32_t);
|
2002-10-01 10:25:40 +00:00
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < n_trans; i++)
|
|
|
|
|
{
|
|
|
|
|
idxs[i] = *(unsigned char*)(bytes + pos);
|
|
|
|
|
pos++;
|
|
|
|
|
}
|
2002-09-30 16:54:29 +00:00
|
|
|
|
for (i = 0; i < n_types; i++)
|
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
struct ttinfo *ptr = (struct ttinfo*)(bytes + pos);
|
2002-09-30 16:54:29 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
types[i].isdst = (ptr->isdst != 0 ? YES : NO);
|
|
|
|
|
types[i].abbr_idx = ptr->abbr_idx;
|
|
|
|
|
types[i].offset = decode(ptr->offset);
|
|
|
|
|
pos += sizeof(struct ttinfo);
|
2002-09-30 16:54:29 +00:00
|
|
|
|
}
|
2005-07-08 11:48:37 +00:00
|
|
|
|
abbr = (unsigned char*)(bytes + pos);
|
2002-10-01 10:25:40 +00:00
|
|
|
|
{
|
2006-02-21 15:44:04 +00:00
|
|
|
|
id abbrevs[charcnt];
|
|
|
|
|
unsigned count = 0;
|
|
|
|
|
unsigned used = 0;
|
2002-10-01 10:25:40 +00:00
|
|
|
|
|
|
|
|
|
memset(abbrevs, '\0', sizeof(id)*charcnt);
|
|
|
|
|
for (i = 0; i < n_types; i++)
|
|
|
|
|
{
|
|
|
|
|
int loc = types[i].abbr_idx;
|
|
|
|
|
|
|
|
|
|
if (abbrevs[loc] == nil)
|
|
|
|
|
{
|
2005-07-08 11:48:37 +00:00
|
|
|
|
abbrevs[loc]
|
2006-02-21 15:44:04 +00:00
|
|
|
|
= [[NSString alloc] initWithUTF8String: (char*)abbr + loc];
|
|
|
|
|
count++;
|
2002-10-01 10:25:40 +00:00
|
|
|
|
}
|
2006-02-21 15:44:04 +00:00
|
|
|
|
types[i].abbreviation = abbrevs[loc];
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Now we have created all the abbreviations, we put them in an
|
|
|
|
|
* array for easy access later and easy deallocation if/when
|
|
|
|
|
* the receiver is deallocated.
|
|
|
|
|
*/
|
|
|
|
|
i = charcnt;
|
|
|
|
|
while (i-- > count)
|
|
|
|
|
{
|
|
|
|
|
if (abbrevs[i] != nil)
|
2002-10-01 10:25:40 +00:00
|
|
|
|
{
|
2006-02-21 15:44:04 +00:00
|
|
|
|
while (abbrevs[used] != nil)
|
|
|
|
|
{
|
|
|
|
|
used++;
|
|
|
|
|
}
|
|
|
|
|
abbrevs[used] = abbrevs[i];
|
|
|
|
|
abbrevs[i] = nil;
|
|
|
|
|
if (++used >= count)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
2002-10-01 10:25:40 +00:00
|
|
|
|
}
|
2006-02-21 15:44:04 +00:00
|
|
|
|
}
|
|
|
|
|
abbreviations = [[NSArray alloc] initWithObjects: abbrevs count: count];
|
|
|
|
|
while (count-- > 0)
|
|
|
|
|
{
|
|
|
|
|
RELEASE(abbrevs[count]);
|
2002-10-01 10:25:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2002-09-30 16:54:29 +00:00
|
|
|
|
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex lock];
|
|
|
|
|
}
|
|
|
|
|
[zoneDictionary setObject: self forKey: timeZoneName];
|
|
|
|
|
if (zone_mutex != nil)
|
|
|
|
|
{
|
|
|
|
|
[zone_mutex unlock];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
DESTROY(self);
|
|
|
|
|
NSLog(@"Unable to obtain time zone `%@'... %@", name, localException);
|
|
|
|
|
if ([localException name] != fileException)
|
|
|
|
|
{
|
|
|
|
|
[localException raise];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isDaylightSavingTimeForDate: (NSDate*)aDate
|
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
TypeInfo *type = chop([aDate timeIntervalSince1970], self);
|
2002-09-30 16:54:29 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
return type->isdst;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) name
|
|
|
|
|
{
|
|
|
|
|
return timeZoneName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (int) secondsFromGMTForDate: (NSDate*)aDate
|
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
TypeInfo *type = chop([aDate timeIntervalSince1970], self);
|
2002-09-30 16:54:29 +00:00
|
|
|
|
|
2002-10-01 10:25:40 +00:00
|
|
|
|
return type->offset;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSArray*) timeZoneDetailArray
|
|
|
|
|
{
|
|
|
|
|
NSTimeZoneDetail *details[n_types];
|
|
|
|
|
unsigned i;
|
|
|
|
|
NSArray *array;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n_types; i++)
|
|
|
|
|
{
|
|
|
|
|
details[i] = newDetailInZoneForType(self, &types[i]);
|
|
|
|
|
}
|
|
|
|
|
array = [NSArray arrayWithObjects: details count: n_types];
|
|
|
|
|
for (i = 0; i < n_types; i++)
|
|
|
|
|
{
|
|
|
|
|
RELEASE(details[i]);
|
|
|
|
|
}
|
|
|
|
|
return array;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSTimeZoneDetail*) timeZoneDetailForDate: (NSDate*)aDate
|
|
|
|
|
{
|
2002-10-01 10:25:40 +00:00
|
|
|
|
TypeInfo *type;
|
2002-09-30 16:54:29 +00:00
|
|
|
|
NSTimeZoneDetail *detail;
|
|
|
|
|
|
|
|
|
|
type = chop([aDate timeIntervalSince1970], self);
|
|
|
|
|
detail = newDetailInZoneForType(self, type);
|
|
|
|
|
return AUTORELEASE(detail);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) timeZoneName
|
|
|
|
|
{
|
|
|
|
|
return timeZoneName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|