2 ********************************************************************************
3 * Copyright (C) 2005-2006, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 ********************************************************************************
9 ********************************************************************************
12 #include "unicode/utypes.h"
16 #if !UCONFIG_NO_FORMATTING
18 #include "unicode/ures.h"
19 #include "unicode/format.h"
20 #include "unicode/fmtable.h"
21 #include "unicode/datefmt.h"
22 #include "unicode/msgfmt.h"
23 #include "unicode/calendar.h"
24 #include "unicode/gregocal.h"
25 #include "unicode/locid.h"
26 #include "unicode/unistr.h"
27 #include "unicode/ustring.h"
28 #include "unicode/timezone.h"
29 #include "unicode/utmscale.h"
36 # define WIN32_LEAN_AND_MEAN
46 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Win32DateFormat
)
48 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
50 #define NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
51 #define DELETE_ARRAY(array) uprv_free((void *) (array))
53 #define STACK_BUFFER_SIZE 64
55 UnicodeString
*getTimeDateFormat(const Calendar
*cal
, const Locale
*locale
, UErrorCode
&status
)
57 UnicodeString
*result
= NULL
;
58 const char *type
= cal
->getType();
59 const char *base
= locale
->getBaseName();
60 UResourceBundle
*topBundle
= ures_open((char *) 0, base
, &status
);
61 UResourceBundle
*calBundle
= ures_getByKey(topBundle
, "calendar", NULL
, &status
);
62 UResourceBundle
*typBundle
= ures_getByKeyWithFallback(calBundle
, type
, NULL
, &status
);
63 UResourceBundle
*patBundle
= ures_getByKeyWithFallback(typBundle
, "DateTimePatterns", NULL
, &status
);
65 if (status
== U_MISSING_RESOURCE_ERROR
) {
66 status
= U_ZERO_ERROR
;
67 typBundle
= ures_getByKeyWithFallback(calBundle
, "gregorian", typBundle
, &status
);
68 patBundle
= ures_getByKeyWithFallback(typBundle
, "DateTimePatterns", patBundle
, &status
);
71 if (U_FAILURE(status
)) {
72 UChar defaultPattern
[] = {0x007B, 0x0031, 0x007D, 0x0020, 0x007B, 0x0030, 0x007D, 0x0000}; // "{1} {0}"
73 return new UnicodeString(defaultPattern
, ARRAY_SIZE(defaultPattern
));
76 int32_t resStrLen
= 0;
77 const UChar
*resStr
= ures_getStringByIndex(patBundle
, (int32_t)DateFormat::kDateTime
, &resStrLen
, &status
);
79 result
= new UnicodeString(TRUE
, resStr
, resStrLen
);
81 ures_close(patBundle
);
82 ures_close(typBundle
);
83 ures_close(calBundle
);
84 ures_close(topBundle
);
89 // TODO: Range-check timeStyle, dateStyle
90 Win32DateFormat::Win32DateFormat(DateFormat::EStyle timeStyle
, DateFormat::EStyle dateStyle
, const Locale
&locale
, UErrorCode
&status
)
91 : DateFormat(), fDateTimeMsg(NULL
), fTimeStyle(timeStyle
), fDateStyle(dateStyle
), fLocale(&locale
), fZoneID()
93 if (U_SUCCESS(status
)) {
94 fLCID
= locale
.getLCID();
95 fTZI
= NEW_ARRAY(TIME_ZONE_INFORMATION
, 1);
96 uprv_memset(fTZI
, 0, sizeof(TIME_ZONE_INFORMATION
));
97 adoptCalendar(Calendar::createInstance(locale
, status
));
101 Win32DateFormat::Win32DateFormat(const Win32DateFormat
&other
)
107 Win32DateFormat::~Win32DateFormat()
114 Win32DateFormat
&Win32DateFormat::operator=(const Win32DateFormat
&other
)
116 // The following handles fCalendar
117 DateFormat::operator=(other
);
121 this->fDateTimeMsg
= other
.fDateTimeMsg
;
122 this->fTimeStyle
= other
.fTimeStyle
;
123 this->fDateStyle
= other
.fDateStyle
;
124 this->fLCID
= other
.fLCID
;
125 // this->fCalendar = other.fCalendar->clone();
126 this->fZoneID
= other
.fZoneID
;
128 this->fTZI
= NEW_ARRAY(TIME_ZONE_INFORMATION
, 1);
129 *this->fTZI
= *other
.fTZI
;
134 Format
*Win32DateFormat::clone(void) const
136 return new Win32DateFormat(*this);
139 // TODO: Is just ignoring pos the right thing?
140 UnicodeString
&Win32DateFormat::format(Calendar
&cal
, UnicodeString
&appendTo
, FieldPosition
&pos
) const
145 TIME_ZONE_INFORMATION tzi
= *fTZI
;
146 UErrorCode status
= U_ZERO_ERROR
;
147 const TimeZone
&tz
= cal
.getTimeZone();
150 setTimeZoneInfo(&tzi
, tz
);
152 uct
= utmscale_fromInt64((int64_t) cal
.getTime(status
), UDTS_ICU4C_TIME
, &status
);
153 uft
= utmscale_toInt64(uct
, UDTS_WINDOWS_FILE_TIME
, &status
);
155 ft
.dwLowDateTime
= (DWORD
) (uft
& 0xFFFFFFFF);
156 ft
.dwHighDateTime
= (DWORD
) ((uft
>> 32) & 0xFFFFFFFF);
158 FileTimeToSystemTime(&ft
, &st_gmt
);
159 SystemTimeToTzSpecificLocalTime(&tzi
, &st_gmt
, &st_local
);
162 if (fDateStyle
!= DateFormat::kNone
&& fTimeStyle
!= DateFormat::kNone
) {
163 UnicodeString
*date
= new UnicodeString();
164 UnicodeString
*time
= new UnicodeString();
165 UnicodeString
*pattern
= fDateTimeMsg
;
166 Formattable timeDateArray
[2];
168 formatDate(&st_local
, *date
);
169 formatTime(&st_local
, *time
);
171 timeDateArray
[0].adoptString(time
);
172 timeDateArray
[1].adoptString(date
);
174 if (strcmp(fCalendar
->getType(), cal
.getType()) != 0) {
175 pattern
= getTimeDateFormat(&cal
, fLocale
, status
);
178 MessageFormat::format(*pattern
, timeDateArray
, 2, appendTo
, status
);
179 } else if (fDateStyle
!= DateFormat::kNone
) {
180 formatDate(&st_local
, appendTo
);
181 } else if (fTimeStyle
!= DateFormat::kNone
) {
182 formatTime(&st_local
, appendTo
);
188 void Win32DateFormat::parse(const UnicodeString
& text
, Calendar
& cal
, ParsePosition
& pos
) const
190 pos
.setErrorIndex(pos
.getIndex());
193 void Win32DateFormat::adoptCalendar(Calendar
*newCalendar
)
195 if (fCalendar
== NULL
|| strcmp(fCalendar
->getType(), newCalendar
->getType()) != 0) {
196 UErrorCode status
= U_ZERO_ERROR
;
198 if (fDateStyle
!= DateFormat::kNone
&& fTimeStyle
!= DateFormat::kNone
) {
200 fDateTimeMsg
= getTimeDateFormat(newCalendar
, fLocale
, status
);
205 fCalendar
= newCalendar
;
207 fZoneID
= setTimeZoneInfo(fTZI
, fCalendar
->getTimeZone());
210 void Win32DateFormat::setCalendar(const Calendar
&newCalendar
)
212 adoptCalendar(newCalendar
.clone());
215 void Win32DateFormat::adoptTimeZone(TimeZone
*zoneToAdopt
)
217 fZoneID
= setTimeZoneInfo(fTZI
, *zoneToAdopt
);
218 fCalendar
->adoptTimeZone(zoneToAdopt
);
221 void Win32DateFormat::setTimeZone(const TimeZone
& zone
)
223 fZoneID
= setTimeZoneInfo(fTZI
, zone
);
224 fCalendar
->setTimeZone(zone
);
227 static const DWORD dfFlags
[] = {DATE_LONGDATE
, DATE_LONGDATE
, DATE_SHORTDATE
, DATE_SHORTDATE
};
229 void Win32DateFormat::formatDate(const SYSTEMTIME
*st
, UnicodeString
&appendTo
) const
232 UChar stackBuffer
[STACK_BUFFER_SIZE
];
233 UChar
*buffer
= stackBuffer
;
235 result
= GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, buffer
, STACK_BUFFER_SIZE
);
238 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
239 int newLength
= GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, NULL
, 0);
241 buffer
= NEW_ARRAY(UChar
, newLength
);
242 GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, buffer
, newLength
);
246 appendTo
.append(buffer
, (int32_t) wcslen(buffer
));
248 if (buffer
!= stackBuffer
) {
249 DELETE_ARRAY(buffer
);
253 static const DWORD tfFlags
[] = {0, 0, 0, TIME_NOSECONDS
};
255 void Win32DateFormat::formatTime(const SYSTEMTIME
*st
, UnicodeString
&appendTo
) const
258 UChar stackBuffer
[STACK_BUFFER_SIZE
];
259 UChar
*buffer
= stackBuffer
;
261 result
= GetTimeFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, buffer
, STACK_BUFFER_SIZE
);
264 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
265 int newLength
= GetTimeFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, NULL
, 0);
267 buffer
= NEW_ARRAY(UChar
, newLength
);
268 GetDateFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, buffer
, newLength
);
272 appendTo
.append(buffer
, (int32_t) wcslen(buffer
));
274 if (buffer
!= stackBuffer
) {
275 DELETE_ARRAY(buffer
);
279 UnicodeString
Win32DateFormat::setTimeZoneInfo(TIME_ZONE_INFORMATION
*tzi
, const TimeZone
&zone
) const
281 UnicodeString zoneID
;
285 if (zoneID
.compare(fZoneID
) != 0) {
289 if (! uprv_getWindowsTimeZoneInfo(tzi
, icuid
.getBuffer(), icuid
.length())) {
291 int32_t ec
= TimeZone::countEquivalentIDs(icuid
);
293 for (int z
= 0; z
< ec
; z
+= 1) {
294 UnicodeString equiv
= TimeZone::getEquivalentID(icuid
, z
);
296 if (found
= uprv_getWindowsTimeZoneInfo(tzi
, equiv
.getBuffer(), equiv
.length())) {
302 GetTimeZoneInformation(tzi
);
312 #endif /* #if !UCONFIG_NO_FORMATTING */
314 #endif // #ifdef U_WINDOWS