]> err.no Git - sope/blob - sope-gdl1/MySQL4/NSCalendarDate+MySQL4Val.m
renamed categories
[sope] / sope-gdl1 / MySQL4 / NSCalendarDate+MySQL4Val.m
1 /* 
2    NSCalendarDate+MySQL4Val.m
3
4    Copyright (C) 2003-2005 SKYRIX Software AG
5
6    Author: Helge Hess (helge.hess@skyrix.com)
7
8    This file is part of the MySQL4 Adaptor Library
9
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Library General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Library General Public License for more details.
19
20    You should have received a copy of the GNU Library General Public
21    License along with this library; see the file COPYING.LIB.
22    If not, write to the Free Software Foundation,
23    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 */
25
26
27 #import <Foundation/NSString.h>
28 #include "MySQL4Channel.h"
29 #include "common.h"
30
31 #if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
32 @interface NSCalendarDate(UsedPrivates)
33 - (id)initWithTimeIntervalSince1970:(NSTimeInterval)_tv;
34 @end
35 #endif
36
37 static NSString *SQLITE3_DATETIME_FORMAT = @"%b %d %Y %I:%M:%S:000%p";
38
39 @implementation NSCalendarDate(MySQL4Values)
40
41 /*
42   Format: '2001-07-26 14:00:00+02'
43           '2001-07-26 14:00:00+09:30'
44            0123456789012345678901234
45   
46   Matthew: "07/25/2003 06:00:00 CDT".
47 */
48
49 static Class      NSCalDateClass     = Nil;
50 static NSTimeZone *DefServerTimezone = nil;
51 static NSTimeZone *gmt   = nil;
52 static NSTimeZone *gmt01 = nil;
53 static NSTimeZone *gmt02 = nil;
54
55 - (id)initWithMySQL4Data:(const void *)_value length:(int)_length {
56   static unsigned char buf[28]; // reused buffer, THREAD
57   const char *_cstr = _value;
58   unsigned char  *p;
59   NSTimeZone     *attrTZ;
60   NSCalendarDate *date;
61   int            year, month, day, hour, min, sec, tzOffset;
62   
63   if (_length == 0)
64     return nil;
65   
66   if (_length != 22 && _length != 25) {
67     NSLog(@"ERROR(%s): unexpected date string '%s', returning now"
68           @" (expected format: '2001-07-26 14:00:00+02')", 
69           __PRETTY_FUNCTION__, _cstr);
70     return [NSCalendarDate date];
71   }
72   strncpy(buf, _cstr, 25);
73   buf[25] = '\0';
74   
75   /* perform on reverse, so that we don't overwrite with null-terminators */
76   
77   if (_length == 22) {
78     p = &(buf[19]);
79     tzOffset = atoi(p) * 60;
80   }
81   else if (_length >= 25) {
82     int mins;
83     p = &(buf[23]);
84     mins = atoi(p);
85     buf[22] = '\0'; // the ':'
86     p = &(buf[19]);
87     tzOffset = atoi(p) * 60;
88     tzOffset = tzOffset > 0 ? (tzOffset + mins) : (tzOffset - mins);
89   }
90   
91   p = &(buf[17]); buf[19] = '\0'; sec   = atoi(p);
92   p = &(buf[14]); buf[16] = '\0'; min   = atoi(p);
93   p = &(buf[11]); buf[13] = '\0'; hour  = atoi(p);
94   p = &(buf[8]);  buf[10] = '\0'; day   = atoi(p);
95   p = &(buf[5]);  buf[7]  = '\0'; month = atoi(p);
96   p = &(buf[0]);  buf[4]  = '\0'; year  = atoi(p);
97   
98   /* TODO: cache all timezones (just 26 ;-) */
99   switch (tzOffset) {
100   case 0:
101     if (gmt == nil) {
102       gmt = [[NSTimeZone timeZoneForSecondsFromGMT:0] retain];
103       NSAssert(gmt, @"could not create GMT timezone?!");
104     }
105     attrTZ = gmt;
106     break;
107   case 60:
108     if (gmt01 == nil) {
109       gmt01 = [[NSTimeZone timeZoneForSecondsFromGMT:3600] retain];
110       NSAssert(gmt01, @"could not create GMT+01 timezone?!");
111     }
112     attrTZ = gmt01;
113     break;
114   case 120:
115     if (gmt02 == nil) {
116       gmt02 = [[NSTimeZone timeZoneForSecondsFromGMT:7200] retain];
117       NSAssert(gmt02, @"could not create GMT+02 timezone?!");
118     }
119     attrTZ = gmt02;
120     break;
121     
122   default: {
123     /* cache the first, "alternative" timezone */
124     static int firstTZOffset = 0; // can use 0 since GMT is a separate case
125     static NSTimeZone *firstTZ = nil;
126     if (firstTZOffset == 0) {
127       firstTZOffset = tzOffset;
128       firstTZ = [[NSTimeZone timeZoneForSecondsFromGMT:(tzOffset*60)] retain];
129     }
130     
131     attrTZ = (firstTZOffset == tzOffset)
132       ? firstTZ
133       : [NSTimeZone timeZoneForSecondsFromGMT:(tzOffset * 60)];
134     break;
135   }
136   }
137   
138   if (NSCalDateClass == Nil) NSCalDateClass = [NSCalendarDate class];
139   date = [NSCalDateClass dateWithYear:year month:month day:day
140                          hour:hour minute:min second:sec
141                          timeZone:attrTZ];
142   if (date == nil) {
143     NSLog(@"ERROR(%s): could not construct date from string '%s': "
144           @"year=%i,month=%i,day=%i,hour=%i,minute=%i,second=%i, tz=%@",
145           __PRETTY_FUNCTION__, _cstr,
146           year, month, day, hour, min, sec, attrTZ);
147   }
148   return date;
149 }
150
151 - (id)initWithMySQL4Double:(double)_value {
152   return [self initWithTimeIntervalSince1970:_value];
153 }
154 - (id)initWithMySQL4Int:(int)_value {
155   return [self initWithMySQL4Double:_value];
156 }
157
158 - (id)initWithMySQL4Text:(const unsigned char *)_value {
159   return [self initWithMySQL4Data:_value length:strlen(_value)];
160 }
161
162 /* generating value */
163
164 - (NSString *)stringValueForMySQL4Type:(NSString *)_type
165   attribute:(EOAttribute *)_attribute
166 {
167 #if 0
168   NSString   *format;
169 #endif
170   EOQuotedExpression *expr;
171   NSTimeZone *serverTimeZone;
172   NSString   *format;
173   NSString   *val;
174   unsigned len;
175   unichar  c1;
176   
177   if ((len = [_type length]) == 0)
178     c1 = 0;
179   else
180     c1 = [_type characterAtIndex:0];
181
182   if (c1 == 'i' || c1 == 'I') { // INTEGER
183     char buf[64];
184     sprintf(buf, "%d", ((unsigned int)[self timeIntervalSince1970]));
185     return [NSString stringWithCString:buf];
186   }
187   if (c1 == 'r' || c1 == 'R') { // REAL
188     char buf[64]; // TODO: check format
189     sprintf(buf, "%f", [self timeIntervalSince1970]);
190     return [NSString stringWithCString:buf];
191   }
192
193   if ((serverTimeZone = [_attribute serverTimeZone]) == nil ) {
194     if (DefServerTimezone == nil) {
195       DefServerTimezone = [[NSTimeZone localTimeZone] retain];
196       NSLog(@"Note: MySQL4 adaptor using timezone '%@' as default",
197             DefServerTimezone);
198     }
199     serverTimeZone = DefServerTimezone;
200   }
201   
202 #if 0
203   format = [_attribute calendarFormat];
204 #else /* hm, why is that? */
205   format = @"%Y-%m-%d %H:%M:%S%z";
206 #endif
207   if (format == nil)
208     format = SQLITE3_DATETIME_FORMAT;
209   
210   [self setTimeZone:serverTimeZone];
211   
212   val = [self descriptionWithCalendarFormat:format];
213   expr = [[EOQuotedExpression alloc] initWithExpression:val
214                                      quote:@"\'" escape:@"\\'"];
215   val = [[expr expressionValueForContext:nil] retain];
216   [expr release];
217   
218   return [val autorelease];
219 }
220
221 @end /* NSCalendarDate(MySQL4Values) */