/ CoreFoundation / Locale.subproj / CFDateIntervalFormatter.c
CFDateIntervalFormatter.c
  1  /*	CFDateIntervalFormatter.c
  2  	Copyright (c) 1998-2018, Apple Inc. and the Swift project authors
  3   
  4  	Portions Copyright (c) 2019, Apple Inc. and the Swift project authors
  5  	Licensed under Apache License v2.0 with Runtime Library Exception
  6  	See http://swift.org/LICENSE.txt for license information
  7  	See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  8  */
  9  
 10  #include <CoreFoundation/CFDateIntervalFormatter.h>
 11  #include <CoreFoundation/CFRuntime.h>
 12  #include "CFInternal.h"
 13  #include "CFRuntime_Internal.h"
 14  
 15  #include <CoreFoundation/CFCalendar.h>
 16  #include <CoreFoundation/CFDate.h>
 17  #include <CoreFoundation/CFDateFormatter.h>
 18  #include <CoreFoundation/CFDateInterval.h>
 19  #include <CoreFoundation/CFLocale.h>
 20  #include <CoreFoundation/CFTimeZone.h>
 21  
 22  #include <unicode/udateintervalformat.h>
 23  
 24  #if TARGET_OS_WASI
 25  #define LOCK() do {} while (0)
 26  #define UNLOCK() do {} while (0)
 27  #else
 28  #include <dispatch/dispatch.h>
 29  
 30  #define LOCK() do { dispatch_semaphore_wait(formatter->_lock, DISPATCH_TIME_FOREVER); } while(0)
 31  #define UNLOCK() do { dispatch_semaphore_signal(formatter->_lock); } while(0)
 32  #endif
 33  
 34  CF_INLINE void __CFReleaseIfNotNull(CFTypeRef object) {
 35      if (object) {
 36          CFRelease(object);
 37      }
 38  }
 39  
 40  CF_INLINE CFTypeRef __CFRetainIfNotNull(CFTypeRef object) {
 41      if (object) {
 42          CFRetain(object);
 43      }
 44      
 45      return object;
 46  }
 47  
 48  struct __CFDateIntervalFormatter {
 49      CFRuntimeBase _base;
 50      CFLocaleRef _locale;
 51      CFCalendarRef _calendar;
 52      CFTimeZoneRef _timeZone;
 53      CFStringRef _dateTemplateFromStyles;
 54      CFStringRef _dateTemplate;
 55      void *_formatter;
 56      CFDateIntervalFormatterStyle _dateStyle;
 57      CFDateIntervalFormatterStyle _timeStyle;
 58      _CFDateIntervalFormatterBoundaryStyle _boundaryStyle;
 59  #if !TARGET_OS_WASI
 60      dispatch_semaphore_t _lock;
 61  #endif
 62      bool _modified:1;
 63      bool _useTemplate:1;
 64  };
 65  
 66  static void __CFDateIntervalFormatterDeallocate(CFTypeRef object);
 67  const CFRuntimeClass __CFDateIntervalFormatterClass = {
 68      0,
 69      "CFDateIntervalFormatter",
 70      NULL,    // init
 71      NULL,    // copy
 72      &__CFDateIntervalFormatterDeallocate,    // dealloc
 73      NULL,    // equals
 74      NULL,    // hash
 75      NULL,    // copyFormattingDescription
 76      NULL,    // copyDescription
 77  };
 78  
 79  static CFStringRef createLocaleIDFromLocaleAndCalendar(CFLocaleRef locale, CFCalendarRef calendar) {
 80      CFMutableDictionaryRef dict;
 81      
 82      {
 83          CFDictionaryRef immutableDict = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, CFLocaleGetIdentifier(locale));
 84          dict = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, immutableDict);
 85          CFRelease(immutableDict);
 86      }
 87      
 88      if (calendar) {
 89          CFDictionarySetValue(dict, kCFLocaleCalendar, calendar);
 90      }
 91      CFStringRef localeID = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, dict);
 92      CFRelease(dict);
 93      
 94      return localeID;
 95  }
 96  
 97  static void updateDateTemplate(CFDateIntervalFormatterRef dif, CFDateIntervalFormatterStyle dateStyle, CFDateIntervalFormatterStyle timeStyle);
 98  static void updateDateTemplateFromCurrentSettings(CFDateIntervalFormatterRef dif) {
 99      updateDateTemplate(dif, dif->_dateStyle, dif->_timeStyle);
100  }
101  
102  static void updateDateTemplate(CFDateIntervalFormatterRef dif, CFDateIntervalFormatterStyle dateStyle, CFDateIntervalFormatterStyle timeStyle) {
103      CFDateFormatterRef formatter;
104      {
105          CFLocaleRef locale = dif->_locale ? CFRetain(dif->_locale) : CFLocaleCopyCurrent();
106          CFCalendarRef unretainedCalendar = dif->_calendar ?: (CFCalendarRef)CFLocaleGetValue(locale, kCFLocaleCalendar);
107          formatter = CFDateFormatterCreate(kCFAllocatorSystemDefault, locale, (CFDateFormatterStyle)dateStyle, (CFDateFormatterStyle)timeStyle);
108          CFDateFormatterSetProperty(formatter, kCFDateFormatterCalendar, unretainedCalendar);
109          CFRelease(locale);
110      }
111      
112      CFStringRef template = CFDateFormatterGetFormat(formatter);
113      __CFReleaseIfNotNull(dif->_dateTemplateFromStyles);
114      dif->_dateTemplateFromStyles = CFStringCreateCopy(kCFAllocatorSystemDefault, template);
115      CFRelease(formatter);
116  }
117  
118  static void updateFormatter(CFDateIntervalFormatterRef dif) {
119      if (dif->_modified && dif->_formatter != NULL) {
120          udtitvfmt_close(dif->_formatter);
121          dif->_formatter = NULL;
122          dif->_modified = false;
123      }
124      
125      if (dif->_formatter == NULL) {
126          CFLocaleRef locale = dif->_locale;
127          if (locale) {
128              CFRetain(locale);
129          } else {
130              locale = CFLocaleCopyCurrent();
131          }
132          
133          CFCalendarRef unretainedCalendar = dif->_calendar;
134          if (unretainedCalendar == NULL) {
135              unretainedCalendar = (CFCalendarRef)CFLocaleGetValue(locale, kCFDateFormatterCalendar);
136          }
137          
138          CFStringRef localeID = createLocaleIDFromLocaleAndCalendar(locale, unretainedCalendar);
139          
140          char localeBuffer[100] = {0};
141          CFStringGetCString(localeID, localeBuffer, 100, kCFStringEncodingUTF8);
142  
143          UniChar timeZoneID[100] = {0};
144          CFTimeZoneRef timeZone = dif->_timeZone;
145          if (timeZone) {
146              CFRetain(timeZone);
147          } else {
148              timeZone = CFTimeZoneCopyDefault();
149          }
150          CFStringRef unretainedTimeZoneName = CFTimeZoneGetName(timeZone);
151          CFStringGetCharacters(unretainedTimeZoneName, CFRangeMake(0, __CFMin(CFStringGetLength(unretainedTimeZoneName), 100)), timeZoneID);
152          
153          CFStringRef unretainedTemplate = dif->_dateTemplateFromStyles;
154          if (dif->_useTemplate) {
155              unretainedTemplate = dif->_dateTemplate;
156          }
157          UniChar templateStr[100] = {0};
158          CFStringGetCharacters(unretainedTemplate, CFRangeMake(0, __CFMin(CFStringGetLength(unretainedTemplate), 100)), templateStr);
159          
160          UErrorCode status = U_ZERO_ERROR;
161          dif->_formatter = udtitvfmt_open(localeBuffer, templateStr, CFStringGetLength(unretainedTemplate), timeZoneID, CFStringGetLength(unretainedTimeZoneName), &status);
162          if (U_FAILURE(status)) {
163              CFLog(kCFLogLevelError, CFSTR("udtitvfmt_open failed!  Tried to set template: %@ for locale %s and timezone %@ and got status code: %s"), unretainedTemplate, localeBuffer, unretainedTimeZoneName, u_errorName(status));
164          }
165          if (!(dif->_formatter)) {
166              CFLog(kCFLogLevelError, CFSTR("udtitvfmt_open failed!  Formatter is NULL! -- locale: %s, template: %@, timezone: %@, status: %s"), localeBuffer, unretainedTemplate, unretainedTimeZoneName, u_errorName(status));
167          }
168          
169  #if TARGET_OS_MAC
170          UDateIntervalFormatAttributeValue uDateIntervalMinimizationStyle = UDTITVFMT_MINIMIZE_NONE;
171          const _CFDateIntervalFormatterBoundaryStyle type = dif->_boundaryStyle;
172          switch (type) {
173              case kCFDateIntervalFormatterBoundaryStyleMinimizeAdjacentMonths:
174                  uDateIntervalMinimizationStyle = UDTITVFMT_MINIMIZE_ADJACENT_MONTHS;
175                  
176              default:
177                  break;
178          }
179          
180          if (dif->_formatter) {
181              udtitvfmt_setAttribute(dif->_formatter, UDTITVFMT_MINIMIZE_TYPE, uDateIntervalMinimizationStyle, &status);
182              if (U_FAILURE(status)) {
183                  CFLog(kCFLogLevelError, CFSTR("udtitvfmt_setAttribute failed!  Tried to set minimize type: %d and got status code: %s"), (int)dif->_boundaryStyle, u_errorName(status));
184              }
185          }
186  #endif
187          
188          CFRelease(locale);
189          CFRelease(localeID);
190          CFRelease(timeZone);
191      }
192  }
193  
194  CFDateIntervalFormatterRef CFDateIntervalFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFDateIntervalFormatterStyle dateStyle, CFDateIntervalFormatterStyle timeStyle) {
195      struct __CFDateIntervalFormatter *memory;
196      uint32_t size = sizeof(struct __CFDateIntervalFormatter) - sizeof(CFRuntimeBase);
197      if (!allocator) {
198          allocator = __CFGetDefaultAllocator();
199      }
200      __CFGenericValidateType(allocator, CFAllocatorGetTypeID());
201      memory = (struct __CFDateIntervalFormatter *)_CFRuntimeCreateInstance(allocator, _kCFRuntimeIDCFDateIntervalFormatter, size, NULL);
202      if (!memory) {
203          return (CFDateIntervalFormatterRef _Nonnull)NULL;
204      }
205      
206      switch (dateStyle) {
207          case kCFDateIntervalFormatterNoStyle:
208          case kCFDateIntervalFormatterShortStyle:
209          case kCFDateIntervalFormatterMediumStyle:
210          case kCFDateIntervalFormatterLongStyle:
211          case kCFDateIntervalFormatterFullStyle: break;
212          default:
213              CFAssert2(0, __kCFLogAssertion, "%s(): unknown date style %ld", __PRETTY_FUNCTION__, dateStyle);
214              memory->_dateStyle = kCFDateIntervalFormatterMediumStyle;
215              break;
216      }
217      switch (timeStyle) {
218          case kCFDateIntervalFormatterNoStyle:
219          case kCFDateIntervalFormatterShortStyle:
220          case kCFDateIntervalFormatterMediumStyle:
221          case kCFDateIntervalFormatterLongStyle:
222          case kCFDateIntervalFormatterFullStyle: break;
223          default:
224              CFAssert2(0, __kCFLogAssertion, "%s(): unknown time style %ld", __PRETTY_FUNCTION__, dateStyle);
225              memory->_timeStyle = kCFDateIntervalFormatterMediumStyle;
226              break;
227      }
228      
229      memory->_dateStyle = dateStyle;
230      memory->_timeStyle = timeStyle;
231      
232      memory->_locale = locale ? CFRetain(locale) : NULL;
233      
234      memory->_calendar = NULL;
235      memory->_timeZone = NULL;
236      memory->_dateTemplateFromStyles = NULL;
237      memory->_dateTemplate = CFRetain(CFSTR(""));
238      memory->_formatter = NULL;
239      memory->_boundaryStyle = kCFDateIntervalFormatterBoundaryStyleDefault;
240  #if !TARGET_OS_WASI
241      memory->_lock = dispatch_semaphore_create(1);
242  #endif
243      memory->_modified = false;
244      memory->_useTemplate = false;
245      
246      return (CFDateIntervalFormatterRef)memory;
247  }
248  
249  void _CFDateIntervalFormatterInitializeFromCoderValues(CFDateIntervalFormatterRef formatter,
250                                                         int64_t dateStyle,
251                                                         int64_t timeStyle,
252                                                         CFStringRef _Nullable dateTemplate,
253                                                         CFStringRef _Nullable dateTemplateFromStyles,
254                                                         Boolean modified,
255                                                         Boolean useTemplate,
256                                                         CFLocaleRef _Nullable locale,
257                                                         CFCalendarRef _Nullable calendar,
258                                                         CFTimeZoneRef _Nullable timeZone) {
259      LOCK();
260      formatter->_dateStyle = dateStyle;
261      formatter->_timeStyle = timeStyle;
262      
263  #define __CFSetObjectField(field, value) \
264  { \
265      __auto_type _value = value; \
266      if (field != _value) { \
267          __CFReleaseIfNotNull(field); \
268          field = (__typeof(_value))__CFRetainIfNotNull(_value); \
269      } \
270  }
271      
272      __CFSetObjectField(formatter->_dateTemplate, dateTemplate);
273      __CFSetObjectField(formatter->_dateTemplateFromStyles, dateTemplateFromStyles);
274      
275      formatter->_modified = modified;
276      formatter->_useTemplate = useTemplate;
277      
278      __CFSetObjectField(formatter->_locale, locale);
279      __CFSetObjectField(formatter->_calendar, calendar);
280      __CFSetObjectField(formatter->_timeZone, timeZone);
281      
282      UNLOCK();
283  }
284  
285  void _CFDateIntervalFormatterCopyCoderValues(CFDateIntervalFormatterRef formatter,
286                                               int64_t *dateStyle,
287                                               int64_t *timeStyle,
288                                               CFStringRef _Nullable *dateTemplate,
289                                               CFStringRef _Nullable *dateTemplateFromStyles,
290                                               Boolean *modified,
291                                               Boolean *useTemplate,
292                                               CFLocaleRef _Nullable *locale,
293                                               CFCalendarRef _Nullable *calendar,
294                                               CFTimeZoneRef _Nullable *timeZone) {
295      LOCK();
296      
297      *dateStyle = formatter->_dateStyle;
298      *timeStyle = formatter->_timeStyle;
299      *dateTemplate = __CFRetainIfNotNull(formatter->_dateTemplate);
300      *dateTemplateFromStyles = __CFRetainIfNotNull(formatter->_dateTemplateFromStyles);
301      *modified = formatter->_modified;
302      *useTemplate = formatter->_useTemplate;
303      *locale = __CFRetainIfNotNull(formatter->_locale);
304      *calendar = (CFCalendarRef)__CFRetainIfNotNull(formatter->_calendar);
305      *timeZone = __CFRetainIfNotNull(formatter->_timeZone);
306      
307      UNLOCK();
308  }
309  
310  CFDateIntervalFormatterRef CFDateIntervalFormatterCreateCopy(CFAllocatorRef _Nullable allocator, CFDateIntervalFormatterRef formatter) {
311      LOCK();
312      CFDateIntervalFormatterRef newFormatter = CFDateIntervalFormatterCreate(allocator, formatter->_locale, formatter->_dateStyle, formatter->_timeStyle);
313      
314      if (formatter->_calendar) {
315          newFormatter->_calendar = _CFCalendarCreateCopy(allocator, formatter->_calendar);
316      }
317      if (formatter->_timeZone) {
318          newFormatter->_timeZone = CFRetain(formatter->_timeZone);
319      }
320      if (formatter->_dateTemplateFromStyles) {
321          newFormatter->_dateTemplateFromStyles = CFStringCreateCopy(allocator, formatter->_dateTemplateFromStyles);
322      }
323      if (formatter->_dateTemplate) {
324          newFormatter->_dateTemplate = CFStringCreateCopy(allocator, formatter->_dateTemplate);
325      }
326      
327      newFormatter->_dateStyle = formatter->_dateStyle;
328      newFormatter->_timeStyle = formatter->_timeStyle;
329      newFormatter->_modified = formatter->_modified;
330      newFormatter->_useTemplate = formatter->_useTemplate;
331      UNLOCK();
332      
333      return newFormatter;
334  }
335  
336  static void __CFDateIntervalFormatterDeallocate(CFTypeRef object) {
337      CFDateIntervalFormatterRef formatter = (CFDateIntervalFormatterRef)object;
338      
339      __CFReleaseIfNotNull(formatter->_locale);
340      __CFReleaseIfNotNull(formatter->_calendar);
341      __CFReleaseIfNotNull(formatter->_timeZone);
342      __CFReleaseIfNotNull(formatter->_dateTemplateFromStyles);
343      __CFReleaseIfNotNull(formatter->_dateTemplate);
344      
345      if (formatter->_formatter) {
346          udtitvfmt_close(formatter->_formatter);
347      }
348      
349  #if !TARGET_OS_WASI
350      dispatch_release(formatter->_lock);
351  #endif
352  }
353  
354  CFLocaleRef CFDateIntervalFormatterCopyLocale(CFDateIntervalFormatterRef formatter) {
355      LOCK();
356      CFLocaleRef locale = formatter->_locale;
357      if (locale) {
358          CFRetain(locale);
359      }
360      UNLOCK();
361      
362      if (!locale) {
363          locale = CFLocaleCopyCurrent();
364      }
365      return locale;
366  }
367  
368  void CFDateIntervalFormatterSetLocale(CFDateIntervalFormatterRef formatter, CFLocaleRef locale) {
369      LOCK();
370      if (locale != formatter->_locale) {
371          __CFReleaseIfNotNull(formatter->_locale);
372          formatter->_locale = locale ? CFLocaleCreateCopy(kCFAllocatorSystemDefault, locale) : NULL;
373          formatter->_modified = true;
374          updateDateTemplateFromCurrentSettings(formatter);
375      }
376      UNLOCK();
377  }
378  
379  CFCalendarRef CFDateIntervalFormatterCopyCalendar(CFDateIntervalFormatterRef formatter) {
380      LOCK();
381      CFCalendarRef calendar = (CFCalendarRef)__CFRetainIfNotNull(formatter->_calendar);
382      if (!calendar) {
383          if (formatter->_locale) {
384              calendar = (CFCalendarRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendar);
385              CFRetain(calendar);
386          } else {
387              calendar = CFCalendarCopyCurrent();
388          }
389      }
390      UNLOCK();
391      return calendar;
392  }
393  
394  void CFDateIntervalFormatterSetCalendar(CFDateIntervalFormatterRef formatter, CFCalendarRef calendar) {
395      LOCK();
396      if (calendar != formatter->_calendar) {
397          __CFReleaseIfNotNull(formatter->_calendar);
398          formatter->_calendar = calendar ? _CFCalendarCreateCopy(kCFAllocatorSystemDefault, calendar) : NULL;
399          formatter->_modified = true;
400          updateDateTemplateFromCurrentSettings(formatter);
401      }
402      UNLOCK();
403  }
404  
405  CFTimeZoneRef CFDateIntervalFormatterCopyTimeZone(CFDateIntervalFormatterRef formatter) {
406      LOCK();
407      CFTimeZoneRef timeZone = formatter->_timeZone;
408      if (timeZone) {
409          CFRetain(timeZone);
410      }
411      UNLOCK();
412      
413      if (!timeZone) {
414          timeZone = CFTimeZoneCopyDefault();
415      }
416      return timeZone;
417  }
418  
419  void CFDateIntervalFormatterSetTimeZone(CFDateIntervalFormatterRef formatter, CFTimeZoneRef timeZone) {
420      LOCK();
421      if (timeZone != formatter->_timeZone) {
422          __CFReleaseIfNotNull(formatter->_timeZone);
423          formatter->_timeZone = timeZone ? CFRetain(timeZone) : NULL;
424          formatter->_modified = true;
425          updateDateTemplateFromCurrentSettings(formatter);
426      }
427      UNLOCK();
428  }
429  
430  CFStringRef CFDateIntervalFormatterCopyDateTemplate(CFDateIntervalFormatterRef formatter) {
431      LOCK();
432      CFStringRef dateTemplate = formatter->_dateTemplate;
433      if (dateTemplate) {
434          CFRetain(dateTemplate);
435      } else {
436          dateTemplate = formatter->_dateTemplateFromStyles;
437          if (dateTemplate) {
438              CFRetain(dateTemplate);
439          }
440      }
441      UNLOCK();
442      
443      return dateTemplate;
444  }
445  
446  void CFDateIntervalFormatterSetDateTemplate(CFDateIntervalFormatterRef formatter, CFStringRef dateTemplate) {
447      if (!dateTemplate) {
448          dateTemplate = CFSTR("");
449      }
450      
451      LOCK();
452      if (!CFEqual(dateTemplate, formatter->_dateTemplate)) {
453          __CFReleaseIfNotNull(formatter->_dateTemplate);
454          formatter->_dateTemplate = CFStringCreateCopy(kCFAllocatorSystemDefault, dateTemplate);
455          formatter->_modified = true;
456          formatter->_useTemplate = true;
457      }
458      UNLOCK();
459  }
460  
461  CFDateIntervalFormatterStyle CFDateIntervalFormatterGetDateStyle(CFDateIntervalFormatterRef formatter) {
462      LOCK();
463      CFDateIntervalFormatterStyle result = formatter->_dateStyle;
464      UNLOCK();
465      return result;
466  }
467  
468  void CFDateIntervalFormatterSetDateStyle(CFDateIntervalFormatterRef formatter, CFDateIntervalFormatterStyle dateStyle) {
469      LOCK();
470      formatter->_dateStyle = dateStyle;
471      formatter->_modified = true;
472      formatter->_useTemplate = false;
473      updateDateTemplateFromCurrentSettings(formatter);
474      UNLOCK();
475  }
476  
477  CFDateIntervalFormatterStyle CFDateIntervalFormatterGetTimeStyle(CFDateIntervalFormatterRef formatter) {
478      LOCK();
479      CFDateIntervalFormatterStyle result = formatter->_timeStyle;
480      UNLOCK();
481      return result;
482  }
483  
484  void CFDateIntervalFormatterSetTimeStyle(CFDateIntervalFormatterRef formatter, CFDateIntervalFormatterStyle timeStyle) {
485      LOCK();
486      formatter->_timeStyle = timeStyle;
487      formatter->_modified = true;
488      formatter->_useTemplate = false;
489      updateDateTemplateFromCurrentSettings(formatter);
490      UNLOCK();
491  }
492  
493  _CFDateIntervalFormatterBoundaryStyle _CFDateIntervalFormatterGetBoundaryStyle(CFDateIntervalFormatterRef formatter) {
494      LOCK();
495      _CFDateIntervalFormatterBoundaryStyle result = formatter->_boundaryStyle;
496      UNLOCK();
497      return result;
498  }
499  
500  void _CFDateIntervalFormatterSetBoundaryStyle(CFDateIntervalFormatterRef formatter, _CFDateIntervalFormatterBoundaryStyle boundaryStyle) {
501      LOCK();
502      formatter->_boundaryStyle = boundaryStyle;
503      formatter->_modified = true;
504      UNLOCK();
505  }
506  
507  CFStringRef CFDateIntervalFormatterCreateStringFromDateToDate(CFDateIntervalFormatterRef formatter, CFDateRef fromDate, CFDateRef toDate) {
508      LOCK();
509      
510      CFStringRef resultStr = CFSTR("");
511      updateFormatter(formatter);
512      
513      if (formatter->_formatter) {
514          UDate fromUDate = (CFDateGetAbsoluteTime(fromDate) + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
515          UDate toUDate = (CFDateGetAbsoluteTime(toDate) + kCFAbsoluteTimeIntervalSince1970) * 1000.0;
516          
517  #define BUFFER_LENGTH 1000
518          
519          UChar result[BUFFER_LENGTH];
520          memset(result, '\0', BUFFER_LENGTH * sizeof(UChar));
521          UErrorCode status = U_ZERO_ERROR;
522          int32_t len = udtitvfmt_format(formatter->_formatter, fromUDate, toUDate, result, BUFFER_LENGTH, 0, &status);
523          
524          if (len > BUFFER_LENGTH) {
525              UChar *resultp = (UChar *)calloc(len, sizeof(UChar));
526              status = U_ZERO_ERROR;
527              len = udtitvfmt_format(formatter->_formatter, fromUDate, toUDate, resultp, len, 0, &status);
528              resultStr = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, resultp, len);
529              free(resultp);
530          } else {
531              resultStr = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, result, len);
532          }
533      } else {
534          resultStr = CFSTR("");
535      }
536      UNLOCK();
537      
538      return resultStr;
539  }
540  
541  CFStringRef CFDateIntervalFormatterCreateStringFromDateInterval(CFDateIntervalFormatterRef formatter, CFDateIntervalRef interval) {
542      CFDateRef start = CFDateIntervalCopyStartDate(interval);
543      CFDateRef end = CFDateIntervalCopyEndDate(interval);
544      CFStringRef result = CFDateIntervalFormatterCreateStringFromDateToDate(formatter, start, end);
545      CFRelease(start);
546      CFRelease(end);
547      return result;
548  }