1#include "pyobjc.h" 2#import "OC_PythonDate.h" 3 4static PyObject* datetime_types = NULL; 5 6@implementation OC_PythonDate 7 8+ (instancetype)depythonifyObject:(PyObject*)object 9{ 10 if (datetime_types == NULL) { 11 /* Initialize the mapping table, don't worry about 12 * import errors: if we're running in an Py2app application 13 * that doesn't use datetime we won't be able to import the 14 * module 15 */ 16 datetime_types = PyList_New(0); 17 if (datetime_types == NULL) { 18 return nil; 19 } 20 PyObject* name = PyText_FromString("datetime"); 21 if (name == NULL) { 22 return nil; 23 } 24 PyObject* datetime = PyImport_Import(name); 25 Py_DECREF(name); name = NULL; 26 27 if (datetime == NULL) { 28 PyErr_Clear(); 29 return nil; 30 } 31 32 PyList_Append(datetime_types, 33 PyObject_GetAttrString(datetime, "date")); 34 PyList_Append(datetime_types, 35 PyObject_GetAttrString(datetime, "datetime")); 36 if (PyErr_Occurred()) { 37 Py_DECREF(datetime); 38 return nil; 39 } 40 Py_DECREF(datetime); 41 } 42 43 44 if (PySequence_Contains(datetime_types, (PyObject*)(Py_TYPE(object)))) { 45 return [[[OC_PythonDate alloc] initWithPythonObject:object] autorelease]; 46 } 47 return nil; 48} 49 50+ (instancetype)dateWithPythonObject:(PyObject*)v 51{ 52 OC_PythonDate* res; 53 54 res = [[OC_PythonDate alloc] initWithPythonObject:v]; 55 [res autorelease]; 56 return res; 57} 58 59- (id)initWithPythonObject:(PyObject*)v 60{ 61 self = [super init]; 62 if (unlikely(self == nil)) return nil; 63 64 oc_value = nil; 65 66 Py_INCREF(v); 67 Py_XDECREF(value); 68 value = v; 69 return self; 70} 71 72-(PyObject*)__pyobjc_PythonObject__ 73{ 74 Py_INCREF(value); 75 return value; 76} 77-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie 78{ 79 *cookie = 0; 80 Py_INCREF(value); 81 return value; 82} 83 84-(BOOL)supportsWeakPointers { return YES; } 85 86-(oneway void)release 87{ 88 /* See comment in OC_PythonUnicode */ 89 PyObjC_BEGIN_WITH_GIL 90 [super release]; 91 PyObjC_END_WITH_GIL 92} 93 94-(void)dealloc 95{ 96 [oc_value release]; 97 oc_value = nil; 98 99 PyObjC_BEGIN_WITH_GIL 100 PyObjC_UnregisterObjCProxy(value, self); 101 Py_XDECREF(value); 102 103 PyObjC_END_WITH_GIL 104 105 [super dealloc]; 106} 107 108 109- (void)encodeWithCoder:(NSCoder*)coder 110{ 111 PyObjC_encodeWithCoder(value, coder); 112} 113 114 115/* 116 * Helper method for initWithCoder, needed to deal with 117 * recursive objects (e.g. o.value = o) 118 */ 119-(void)pyobjcSetValue:(NSObject*)other 120{ 121 PyObjC_BEGIN_WITH_GIL 122 PyObject* v = PyObjC_IdToPython(other); 123 Py_XDECREF(value); 124 value = v; 125 PyObjC_END_WITH_GIL 126} 127 128-(id)initWithCoder:(NSCoder*)coder 129{ 130 value = NULL; 131 132 if (PyObjC_Decoder != NULL) { 133 PyObjC_BEGIN_WITH_GIL 134 PyObject* cdr = PyObjC_IdToPython(coder); 135 if (cdr == NULL) { 136 PyObjC_GIL_FORWARD_EXC(); 137 } 138 139 PyObject* setValue; 140 PyObject* selfAsPython = PyObjCObject_New(self, 0, YES); 141 setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_"); 142 143 PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue); 144 Py_DECREF(cdr); 145 Py_DECREF(setValue); 146 Py_DECREF(selfAsPython); 147 148 if (v == NULL) { 149 PyObjC_GIL_FORWARD_EXC(); 150 } 151 152 Py_XDECREF(value); 153 value = v; 154 155 NSObject* proxy = PyObjC_FindObjCProxy(value); 156 if (proxy == NULL) { 157 PyObjC_RegisterObjCProxy(value, self); 158 } else { 159 [self release]; 160 [proxy retain]; 161 self = (OC_PythonDate*)proxy; 162 } 163 164 165 PyObjC_END_WITH_GIL 166 167 return self; 168 169 } else { 170 [NSException raise:NSInvalidArgumentException 171 format:@"decoding Python objects is not supported"]; 172 return nil; 173 174 } 175} 176 177-(NSDate*)_make_oc_value 178{ 179 if (oc_value == nil) { 180 PyObjC_BEGIN_WITH_GIL 181 PyObject* v; 182 183 v = PyObject_CallMethod(value, "strftime", "s", 184 "%Y-%m-%d %H:%M:%S %z"); 185 if (v == NULL) { 186 /* Raise ObjC exception */ 187 PyObjC_GIL_FORWARD_EXC(); 188 } 189 190 191 oc_value = [NSDate dateWithString: PyObjC_PythonToId(v)]; 192 [oc_value retain]; 193 Py_DECREF(v); 194 195 if (oc_value == nil) { 196 /* The first try will fail when the date/datetime object 197 * isn't timezone aware, try again with a default timezone 198 */ 199 char buf[128]; 200 201 NSTimeZone* zone = [NSTimeZone defaultTimeZone]; 202 NSInteger offset = [zone secondsFromGMT]; 203 char posneg; 204 if (offset < 0) { 205 posneg = '-'; 206 offset = -offset; 207 } else { 208 posneg = '+'; 209 } 210 offset = offset / 60; /* Seconds to minutes */ 211 212 int minutes = offset % 60; 213 int hours = offset / 60; 214 215 216 217 snprintf(buf, sizeof(buf), "%%Y-%%m-%%d %%H:%%M:%%S %c%02d%02d", 218 posneg, hours, minutes); 219 v = PyObject_CallMethod(value, "strftime", "s", buf); 220 if (v == NULL) { 221 /* Raise ObjC exception */ 222 } 223 224 oc_value = [NSDate dateWithString: PyObjC_PythonToId(v)]; 225 [oc_value retain]; 226 Py_DECREF(v); 227 } 228 229 230 231 PyObjC_END_WITH_GIL 232 } 233 return oc_value; 234} 235 236-(NSTimeInterval)timeIntervalSinceReferenceDate 237{ 238 return [[self _make_oc_value] timeIntervalSinceReferenceDate]; 239} 240 241 242#pragma clang diagnostic push 243#pragma clang diagnostic ignored "-Wdeprecated-declarations" 244 245- (id)addTimeInterval:(NSTimeInterval)seconds 246{ 247 return [[self _make_oc_value] addTimeInterval:seconds]; 248} 249 250#pragma clang diagnostic pop 251 252- (NSComparisonResult)compare:(NSDate *)anotherDate 253{ 254 return [[self _make_oc_value] compare:anotherDate]; 255} 256 257- (NSCalendarDate *)dateWithCalendarFormat:(NSString *)formatString timeZone:(NSTimeZone *)timeZone 258{ 259 return [[self _make_oc_value] dateWithCalendarFormat:formatString timeZone:timeZone]; 260} 261 262- (NSString*)description 263{ 264 return [[self _make_oc_value] description]; 265} 266 267- (NSString *)descriptionWithCalendarFormat:(NSString *)formatString timeZone:(NSTimeZone *)aTimeZone locale:(id)localeDictionary 268{ 269 return [[self _make_oc_value] descriptionWithCalendarFormat:formatString timeZone:aTimeZone locale:localeDictionary]; 270} 271 272- (NSString *)descriptionWithLocale:(id)localeDictionary 273{ 274 return [[self _make_oc_value] descriptionWithLocale:localeDictionary]; 275} 276 277- (NSDate *)earlierDate:(NSDate *)anotherDate 278{ 279 if ([[self _make_oc_value] earlierDate:anotherDate] == self) { 280 return self; 281 } else { 282 return anotherDate; 283 } 284} 285 286 287- (BOOL)isEqualToDate:(NSDate *)anotherDate 288{ 289 return [[self _make_oc_value] isEqualToDate:anotherDate]; 290} 291 292 293- (NSDate *)laterDate:(NSDate *)anotherDate 294{ 295 if ([[self _make_oc_value] laterDate:anotherDate] == self) { 296 return self; 297 } else { 298 return anotherDate; 299 } 300} 301 302- (NSTimeInterval)timeIntervalSince1970 303{ 304 return [[self _make_oc_value] timeIntervalSince1970]; 305} 306 307- (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate 308{ 309 return [[self _make_oc_value] timeIntervalSinceDate:anotherDate]; 310} 311 312- (NSTimeInterval)timeIntervalSinceNow 313{ 314 return [[self _make_oc_value] timeIntervalSinceNow]; 315} 316 317 318@end /* implementation OC_PythonDate */ 319