2 ********************************************************************************
3 * Copyright (C) 2005-2011, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 ********************************************************************************
9 ********************************************************************************
12 #include "unicode/utypes.h"
14 #if U_PLATFORM_HAS_WIN32_API
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"
34 #include "wintzimpl.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
* Win32DateFormat::getTimeDateFormat(const Calendar
*cal
, const Locale
*locale
, UErrorCode
&status
) const
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 static const 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 int32_t glueIndex
= DateFormat::kDateTime
;
78 int32_t patSize
= ures_getSize(patBundle
);
79 if (patSize
>= (DateFormat::kDateTimeOffset
+ DateFormat::kShort
+ 1)) {
80 // Get proper date time format
81 glueIndex
= (int32_t)(DateFormat::kDateTimeOffset
+ (fDateStyle
- DateFormat::kDateOffset
));
83 const UChar
*resStr
= ures_getStringByIndex(patBundle
, glueIndex
, &resStrLen
, &status
);
85 result
= new UnicodeString(TRUE
, resStr
, resStrLen
);
87 ures_close(patBundle
);
88 ures_close(typBundle
);
89 ures_close(calBundle
);
90 ures_close(topBundle
);
95 // TODO: Range-check timeStyle, dateStyle
96 Win32DateFormat::Win32DateFormat(DateFormat::EStyle timeStyle
, DateFormat::EStyle dateStyle
, const Locale
&locale
, UErrorCode
&status
)
97 : DateFormat(), fDateTimeMsg(NULL
), fTimeStyle(timeStyle
), fDateStyle(dateStyle
), fLocale(&locale
), fZoneID()
99 if (U_SUCCESS(status
)) {
100 fLCID
= locale
.getLCID();
101 fTZI
= NEW_ARRAY(TIME_ZONE_INFORMATION
, 1);
102 uprv_memset(fTZI
, 0, sizeof(TIME_ZONE_INFORMATION
));
103 adoptCalendar(Calendar::createInstance(locale
, status
));
107 Win32DateFormat::Win32DateFormat(const Win32DateFormat
&other
)
113 Win32DateFormat::~Win32DateFormat()
120 Win32DateFormat
&Win32DateFormat::operator=(const Win32DateFormat
&other
)
122 // The following handles fCalendar
123 DateFormat::operator=(other
);
127 this->fDateTimeMsg
= other
.fDateTimeMsg
;
128 this->fTimeStyle
= other
.fTimeStyle
;
129 this->fDateStyle
= other
.fDateStyle
;
130 this->fLCID
= other
.fLCID
;
131 // this->fCalendar = other.fCalendar->clone();
132 this->fZoneID
= other
.fZoneID
;
134 this->fTZI
= NEW_ARRAY(TIME_ZONE_INFORMATION
, 1);
135 *this->fTZI
= *other
.fTZI
;
140 Format
*Win32DateFormat::clone(void) const
142 return new Win32DateFormat(*this);
145 // TODO: Is just ignoring pos the right thing?
146 UnicodeString
&Win32DateFormat::format(Calendar
&cal
, UnicodeString
&appendTo
, FieldPosition
&pos
) const
151 TIME_ZONE_INFORMATION tzi
= *fTZI
;
152 UErrorCode status
= U_ZERO_ERROR
;
153 const TimeZone
&tz
= cal
.getTimeZone();
156 setTimeZoneInfo(&tzi
, tz
);
158 uct
= utmscale_fromInt64((int64_t) cal
.getTime(status
), UDTS_ICU4C_TIME
, &status
);
159 uft
= utmscale_toInt64(uct
, UDTS_WINDOWS_FILE_TIME
, &status
);
161 ft
.dwLowDateTime
= (DWORD
) (uft
& 0xFFFFFFFF);
162 ft
.dwHighDateTime
= (DWORD
) ((uft
>> 32) & 0xFFFFFFFF);
164 FileTimeToSystemTime(&ft
, &st_gmt
);
165 SystemTimeToTzSpecificLocalTime(&tzi
, &st_gmt
, &st_local
);
168 if (fDateStyle
!= DateFormat::kNone
&& fTimeStyle
!= DateFormat::kNone
) {
169 UnicodeString
*date
= new UnicodeString();
170 UnicodeString
*time
= new UnicodeString();
171 UnicodeString
*pattern
= fDateTimeMsg
;
172 Formattable timeDateArray
[2];
174 formatDate(&st_local
, *date
);
175 formatTime(&st_local
, *time
);
177 timeDateArray
[0].adoptString(time
);
178 timeDateArray
[1].adoptString(date
);
180 if (strcmp(fCalendar
->getType(), cal
.getType()) != 0) {
181 pattern
= getTimeDateFormat(&cal
, fLocale
, status
);
184 MessageFormat::format(*pattern
, timeDateArray
, 2, appendTo
, status
);
185 } else if (fDateStyle
!= DateFormat::kNone
) {
186 formatDate(&st_local
, appendTo
);
187 } else if (fTimeStyle
!= DateFormat::kNone
) {
188 formatTime(&st_local
, appendTo
);
194 void Win32DateFormat::parse(const UnicodeString
& text
, Calendar
& cal
, ParsePosition
& pos
) const
196 pos
.setErrorIndex(pos
.getIndex());
199 void Win32DateFormat::adoptCalendar(Calendar
*newCalendar
)
201 if (fCalendar
== NULL
|| strcmp(fCalendar
->getType(), newCalendar
->getType()) != 0) {
202 UErrorCode status
= U_ZERO_ERROR
;
204 if (fDateStyle
!= DateFormat::kNone
&& fTimeStyle
!= DateFormat::kNone
) {
206 fDateTimeMsg
= getTimeDateFormat(newCalendar
, fLocale
, status
);
211 fCalendar
= newCalendar
;
213 fZoneID
= setTimeZoneInfo(fTZI
, fCalendar
->getTimeZone());
216 void Win32DateFormat::setCalendar(const Calendar
&newCalendar
)
218 adoptCalendar(newCalendar
.clone());
221 void Win32DateFormat::adoptTimeZone(TimeZone
*zoneToAdopt
)
223 fZoneID
= setTimeZoneInfo(fTZI
, *zoneToAdopt
);
224 fCalendar
->adoptTimeZone(zoneToAdopt
);
227 void Win32DateFormat::setTimeZone(const TimeZone
& zone
)
229 fZoneID
= setTimeZoneInfo(fTZI
, zone
);
230 fCalendar
->setTimeZone(zone
);
233 static const DWORD dfFlags
[] = {DATE_LONGDATE
, DATE_LONGDATE
, DATE_SHORTDATE
, DATE_SHORTDATE
};
235 void Win32DateFormat::formatDate(const SYSTEMTIME
*st
, UnicodeString
&appendTo
) const
238 UChar stackBuffer
[STACK_BUFFER_SIZE
];
239 UChar
*buffer
= stackBuffer
;
241 result
= GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, buffer
, STACK_BUFFER_SIZE
);
244 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
245 int newLength
= GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, NULL
, 0);
247 buffer
= NEW_ARRAY(UChar
, newLength
);
248 GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, buffer
, newLength
);
252 appendTo
.append(buffer
, (int32_t) wcslen(buffer
));
254 if (buffer
!= stackBuffer
) {
255 DELETE_ARRAY(buffer
);
259 static const DWORD tfFlags
[] = {0, 0, 0, TIME_NOSECONDS
};
261 void Win32DateFormat::formatTime(const SYSTEMTIME
*st
, UnicodeString
&appendTo
) const
264 UChar stackBuffer
[STACK_BUFFER_SIZE
];
265 UChar
*buffer
= stackBuffer
;
267 result
= GetTimeFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, buffer
, STACK_BUFFER_SIZE
);
270 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
271 int newLength
= GetTimeFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, NULL
, 0);
273 buffer
= NEW_ARRAY(UChar
, newLength
);
274 GetDateFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, buffer
, newLength
);
278 appendTo
.append(buffer
, (int32_t) wcslen(buffer
));
280 if (buffer
!= stackBuffer
) {
281 DELETE_ARRAY(buffer
);
285 UnicodeString
Win32DateFormat::setTimeZoneInfo(TIME_ZONE_INFORMATION
*tzi
, const TimeZone
&zone
) const
287 UnicodeString zoneID
;
291 if (zoneID
.compare(fZoneID
) != 0) {
295 if (! uprv_getWindowsTimeZoneInfo(tzi
, icuid
.getBuffer(), icuid
.length())) {
297 int32_t ec
= TimeZone::countEquivalentIDs(icuid
);
299 for (int z
= 0; z
< ec
; z
+= 1) {
300 UnicodeString equiv
= TimeZone::getEquivalentID(icuid
, z
);
302 if (found
= uprv_getWindowsTimeZoneInfo(tzi
, equiv
.getBuffer(), equiv
.length())) {
308 GetTimeZoneInformation(tzi
);
318 #endif /* #if !UCONFIG_NO_FORMATTING */
320 #endif // U_PLATFORM_HAS_WIN32_API