2 ********************************************************************************
3 * Copyright (C) 2005-2014, 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
== NULL
? NULL
: new UnicodeString(*other
.fDateTimeMsg
);
128 this->fTimeStyle
= other
.fTimeStyle
;
129 this->fDateStyle
= other
.fDateStyle
;
130 this->fLocale
= other
.fLocale
;
131 this->fLCID
= other
.fLCID
;
132 // this->fCalendar = other.fCalendar->clone();
133 this->fZoneID
= other
.fZoneID
;
135 this->fTZI
= NEW_ARRAY(TIME_ZONE_INFORMATION
, 1);
136 *this->fTZI
= *other
.fTZI
;
141 Format
*Win32DateFormat::clone(void) const
143 return new Win32DateFormat(*this);
146 // TODO: Is just ignoring pos the right thing?
147 UnicodeString
&Win32DateFormat::format(Calendar
&cal
, UnicodeString
&appendTo
, FieldPosition
&pos
) const
152 TIME_ZONE_INFORMATION tzi
= *fTZI
;
153 UErrorCode status
= U_ZERO_ERROR
;
154 const TimeZone
&tz
= cal
.getTimeZone();
157 setTimeZoneInfo(&tzi
, tz
);
159 uct
= utmscale_fromInt64((int64_t) cal
.getTime(status
), UDTS_ICU4C_TIME
, &status
);
160 uft
= utmscale_toInt64(uct
, UDTS_WINDOWS_FILE_TIME
, &status
);
162 ft
.dwLowDateTime
= (DWORD
) (uft
& 0xFFFFFFFF);
163 ft
.dwHighDateTime
= (DWORD
) ((uft
>> 32) & 0xFFFFFFFF);
165 FileTimeToSystemTime(&ft
, &st_gmt
);
166 SystemTimeToTzSpecificLocalTime(&tzi
, &st_gmt
, &st_local
);
169 if (fDateStyle
!= DateFormat::kNone
&& fTimeStyle
!= DateFormat::kNone
) {
170 UnicodeString
*date
= new UnicodeString();
171 UnicodeString
*time
= new UnicodeString();
172 UnicodeString
*pattern
= fDateTimeMsg
;
173 Formattable timeDateArray
[2];
175 formatDate(&st_local
, *date
);
176 formatTime(&st_local
, *time
);
178 timeDateArray
[0].adoptString(time
);
179 timeDateArray
[1].adoptString(date
);
181 if (strcmp(fCalendar
->getType(), cal
.getType()) != 0) {
182 pattern
= getTimeDateFormat(&cal
, &fLocale
, status
);
185 MessageFormat::format(*pattern
, timeDateArray
, 2, appendTo
, status
);
186 } else if (fDateStyle
!= DateFormat::kNone
) {
187 formatDate(&st_local
, appendTo
);
188 } else if (fTimeStyle
!= DateFormat::kNone
) {
189 formatTime(&st_local
, appendTo
);
195 void Win32DateFormat::parse(const UnicodeString
& text
, Calendar
& cal
, ParsePosition
& pos
) const
197 pos
.setErrorIndex(pos
.getIndex());
200 void Win32DateFormat::adoptCalendar(Calendar
*newCalendar
)
202 if (fCalendar
== NULL
|| strcmp(fCalendar
->getType(), newCalendar
->getType()) != 0) {
203 UErrorCode status
= U_ZERO_ERROR
;
205 if (fDateStyle
!= DateFormat::kNone
&& fTimeStyle
!= DateFormat::kNone
) {
207 fDateTimeMsg
= getTimeDateFormat(newCalendar
, &fLocale
, status
);
212 fCalendar
= newCalendar
;
214 fZoneID
= setTimeZoneInfo(fTZI
, fCalendar
->getTimeZone());
217 void Win32DateFormat::setCalendar(const Calendar
&newCalendar
)
219 adoptCalendar(newCalendar
.clone());
222 void Win32DateFormat::adoptTimeZone(TimeZone
*zoneToAdopt
)
224 fZoneID
= setTimeZoneInfo(fTZI
, *zoneToAdopt
);
225 fCalendar
->adoptTimeZone(zoneToAdopt
);
228 void Win32DateFormat::setTimeZone(const TimeZone
& zone
)
230 fZoneID
= setTimeZoneInfo(fTZI
, zone
);
231 fCalendar
->setTimeZone(zone
);
234 static const DWORD dfFlags
[] = {DATE_LONGDATE
, DATE_LONGDATE
, DATE_SHORTDATE
, DATE_SHORTDATE
};
236 void Win32DateFormat::formatDate(const SYSTEMTIME
*st
, UnicodeString
&appendTo
) const
239 UChar stackBuffer
[STACK_BUFFER_SIZE
];
240 UChar
*buffer
= stackBuffer
;
242 result
= GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, buffer
, STACK_BUFFER_SIZE
);
245 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
246 int newLength
= GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, NULL
, 0);
248 buffer
= NEW_ARRAY(UChar
, newLength
);
249 GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, buffer
, newLength
);
253 appendTo
.append(buffer
, (int32_t) wcslen(buffer
));
255 if (buffer
!= stackBuffer
) {
256 DELETE_ARRAY(buffer
);
260 static const DWORD tfFlags
[] = {0, 0, 0, TIME_NOSECONDS
};
262 void Win32DateFormat::formatTime(const SYSTEMTIME
*st
, UnicodeString
&appendTo
) const
265 UChar stackBuffer
[STACK_BUFFER_SIZE
];
266 UChar
*buffer
= stackBuffer
;
268 result
= GetTimeFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, buffer
, STACK_BUFFER_SIZE
);
271 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
272 int newLength
= GetTimeFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, NULL
, 0);
274 buffer
= NEW_ARRAY(UChar
, newLength
);
275 GetDateFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, buffer
, newLength
);
279 appendTo
.append(buffer
, (int32_t) wcslen(buffer
));
281 if (buffer
!= stackBuffer
) {
282 DELETE_ARRAY(buffer
);
286 UnicodeString
Win32DateFormat::setTimeZoneInfo(TIME_ZONE_INFORMATION
*tzi
, const TimeZone
&zone
) const
288 UnicodeString zoneID
;
292 if (zoneID
.compare(fZoneID
) != 0) {
296 if (! uprv_getWindowsTimeZoneInfo(tzi
, icuid
.getBuffer(), icuid
.length())) {
298 int32_t ec
= TimeZone::countEquivalentIDs(icuid
);
300 for (int z
= 0; z
< ec
; z
+= 1) {
301 UnicodeString equiv
= TimeZone::getEquivalentID(icuid
, z
);
303 if (found
= uprv_getWindowsTimeZoneInfo(tzi
, equiv
.getBuffer(), equiv
.length())) {
309 GetTimeZoneInformation(tzi
);
319 #endif /* #if !UCONFIG_NO_FORMATTING */
321 #endif // U_PLATFORM_HAS_WIN32_API