2 ********************************************************************************
3 * Copyright (C) 2005-2016, 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/simpleformatter.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 NEW_ARRAY(type,count) (type *) uprv_malloc((count) * sizeof(type))
49 #define DELETE_ARRAY(array) uprv_free((void *) (array))
51 #define STACK_BUFFER_SIZE 64
53 UnicodeString
* Win32DateFormat::getTimeDateFormat(const Calendar
*cal
, const Locale
*locale
, UErrorCode
&status
) const
55 UnicodeString
*result
= NULL
;
56 const char *type
= cal
->getType();
57 const char *base
= locale
->getBaseName();
58 UResourceBundle
*topBundle
= ures_open((char *) 0, base
, &status
);
59 UResourceBundle
*calBundle
= ures_getByKey(topBundle
, "calendar", NULL
, &status
);
60 UResourceBundle
*typBundle
= ures_getByKeyWithFallback(calBundle
, type
, NULL
, &status
);
61 UResourceBundle
*patBundle
= ures_getByKeyWithFallback(typBundle
, "DateTimePatterns", NULL
, &status
);
63 if (status
== U_MISSING_RESOURCE_ERROR
) {
64 status
= U_ZERO_ERROR
;
65 typBundle
= ures_getByKeyWithFallback(calBundle
, "gregorian", typBundle
, &status
);
66 patBundle
= ures_getByKeyWithFallback(typBundle
, "DateTimePatterns", patBundle
, &status
);
69 if (U_FAILURE(status
)) {
70 static const UChar defaultPattern
[] = {0x007B, 0x0031, 0x007D, 0x0020, 0x007B, 0x0030, 0x007D, 0x0000}; // "{1} {0}"
71 return new UnicodeString(defaultPattern
, UPRV_LENGTHOF(defaultPattern
));
74 int32_t resStrLen
= 0;
75 int32_t glueIndex
= DateFormat::kDateTime
;
76 int32_t patSize
= ures_getSize(patBundle
);
77 if (patSize
>= (DateFormat::kDateTimeOffset
+ DateFormat::kShort
+ 1)) {
78 // Get proper date time format
79 glueIndex
= (int32_t)(DateFormat::kDateTimeOffset
+ (fDateStyle
- DateFormat::kDateOffset
));
81 const UChar
*resStr
= ures_getStringByIndex(patBundle
, glueIndex
, &resStrLen
, &status
);
83 result
= new UnicodeString(TRUE
, resStr
, resStrLen
);
85 ures_close(patBundle
);
86 ures_close(typBundle
);
87 ures_close(calBundle
);
88 ures_close(topBundle
);
93 // TODO: Range-check timeStyle, dateStyle
94 Win32DateFormat::Win32DateFormat(DateFormat::EStyle timeStyle
, DateFormat::EStyle dateStyle
, const Locale
&locale
, UErrorCode
&status
)
95 : DateFormat(), fDateTimeMsg(NULL
), fTimeStyle(timeStyle
), fDateStyle(dateStyle
), fLocale(locale
), fZoneID()
97 if (U_SUCCESS(status
)) {
98 fLCID
= locale
.getLCID();
99 fTZI
= NEW_ARRAY(TIME_ZONE_INFORMATION
, 1);
100 uprv_memset(fTZI
, 0, sizeof(TIME_ZONE_INFORMATION
));
101 adoptCalendar(Calendar::createInstance(locale
, status
));
105 Win32DateFormat::Win32DateFormat(const Win32DateFormat
&other
)
111 Win32DateFormat::~Win32DateFormat()
118 Win32DateFormat
&Win32DateFormat::operator=(const Win32DateFormat
&other
)
120 // The following handles fCalendar
121 DateFormat::operator=(other
);
125 this->fDateTimeMsg
= other
.fDateTimeMsg
== NULL
? NULL
: new UnicodeString(*other
.fDateTimeMsg
);
126 this->fTimeStyle
= other
.fTimeStyle
;
127 this->fDateStyle
= other
.fDateStyle
;
128 this->fLocale
= other
.fLocale
;
129 this->fLCID
= other
.fLCID
;
130 // this->fCalendar = other.fCalendar->clone();
131 this->fZoneID
= other
.fZoneID
;
133 this->fTZI
= NEW_ARRAY(TIME_ZONE_INFORMATION
, 1);
134 *this->fTZI
= *other
.fTZI
;
139 Format
*Win32DateFormat::clone(void) const
141 return new Win32DateFormat(*this);
144 // TODO: Is just ignoring pos the right thing?
145 UnicodeString
&Win32DateFormat::format(Calendar
&cal
, UnicodeString
&appendTo
, FieldPosition
&pos
) const
150 TIME_ZONE_INFORMATION tzi
= *fTZI
;
151 UErrorCode status
= U_ZERO_ERROR
;
152 const TimeZone
&tz
= cal
.getTimeZone();
155 setTimeZoneInfo(&tzi
, tz
);
157 uct
= utmscale_fromInt64((int64_t) cal
.getTime(status
), UDTS_ICU4C_TIME
, &status
);
158 uft
= utmscale_toInt64(uct
, UDTS_WINDOWS_FILE_TIME
, &status
);
160 ft
.dwLowDateTime
= (DWORD
) (uft
& 0xFFFFFFFF);
161 ft
.dwHighDateTime
= (DWORD
) ((uft
>> 32) & 0xFFFFFFFF);
163 FileTimeToSystemTime(&ft
, &st_gmt
);
164 SystemTimeToTzSpecificLocalTime(&tzi
, &st_gmt
, &st_local
);
167 if (fDateStyle
!= DateFormat::kNone
&& fTimeStyle
!= DateFormat::kNone
) {
170 UnicodeString
*pattern
= fDateTimeMsg
;
172 formatDate(&st_local
, date
);
173 formatTime(&st_local
, time
);
175 if (strcmp(fCalendar
->getType(), cal
.getType()) != 0) {
176 pattern
= getTimeDateFormat(&cal
, &fLocale
, status
);
179 SimpleFormatter(*pattern
, 2, 2, status
).format(time
, date
, appendTo
, status
);
180 } else if (fDateStyle
!= DateFormat::kNone
) {
181 formatDate(&st_local
, appendTo
);
182 } else if (fTimeStyle
!= DateFormat::kNone
) {
183 formatTime(&st_local
, appendTo
);
189 void Win32DateFormat::parse(const UnicodeString
& text
, Calendar
& cal
, ParsePosition
& pos
) const
191 pos
.setErrorIndex(pos
.getIndex());
194 void Win32DateFormat::adoptCalendar(Calendar
*newCalendar
)
196 if (fCalendar
== NULL
|| strcmp(fCalendar
->getType(), newCalendar
->getType()) != 0) {
197 UErrorCode status
= U_ZERO_ERROR
;
199 if (fDateStyle
!= DateFormat::kNone
&& fTimeStyle
!= DateFormat::kNone
) {
201 fDateTimeMsg
= getTimeDateFormat(newCalendar
, &fLocale
, status
);
206 fCalendar
= newCalendar
;
208 fZoneID
= setTimeZoneInfo(fTZI
, fCalendar
->getTimeZone());
211 void Win32DateFormat::setCalendar(const Calendar
&newCalendar
)
213 adoptCalendar(newCalendar
.clone());
216 void Win32DateFormat::adoptTimeZone(TimeZone
*zoneToAdopt
)
218 fZoneID
= setTimeZoneInfo(fTZI
, *zoneToAdopt
);
219 fCalendar
->adoptTimeZone(zoneToAdopt
);
222 void Win32DateFormat::setTimeZone(const TimeZone
& zone
)
224 fZoneID
= setTimeZoneInfo(fTZI
, zone
);
225 fCalendar
->setTimeZone(zone
);
228 static const DWORD dfFlags
[] = {DATE_LONGDATE
, DATE_LONGDATE
, DATE_SHORTDATE
, DATE_SHORTDATE
};
230 void Win32DateFormat::formatDate(const SYSTEMTIME
*st
, UnicodeString
&appendTo
) const
233 UChar stackBuffer
[STACK_BUFFER_SIZE
];
234 UChar
*buffer
= stackBuffer
;
236 result
= GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, buffer
, STACK_BUFFER_SIZE
);
239 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
240 int newLength
= GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, NULL
, 0);
242 buffer
= NEW_ARRAY(UChar
, newLength
);
243 GetDateFormatW(fLCID
, dfFlags
[fDateStyle
- kDateOffset
], st
, NULL
, buffer
, newLength
);
247 appendTo
.append(buffer
, (int32_t) wcslen(buffer
));
249 if (buffer
!= stackBuffer
) {
250 DELETE_ARRAY(buffer
);
254 static const DWORD tfFlags
[] = {0, 0, 0, TIME_NOSECONDS
};
256 void Win32DateFormat::formatTime(const SYSTEMTIME
*st
, UnicodeString
&appendTo
) const
259 UChar stackBuffer
[STACK_BUFFER_SIZE
];
260 UChar
*buffer
= stackBuffer
;
262 result
= GetTimeFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, buffer
, STACK_BUFFER_SIZE
);
265 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
266 int newLength
= GetTimeFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, NULL
, 0);
268 buffer
= NEW_ARRAY(UChar
, newLength
);
269 GetDateFormatW(fLCID
, tfFlags
[fTimeStyle
], st
, NULL
, buffer
, newLength
);
273 appendTo
.append(buffer
, (int32_t) wcslen(buffer
));
275 if (buffer
!= stackBuffer
) {
276 DELETE_ARRAY(buffer
);
280 UnicodeString
Win32DateFormat::setTimeZoneInfo(TIME_ZONE_INFORMATION
*tzi
, const TimeZone
&zone
) const
282 UnicodeString zoneID
;
286 if (zoneID
.compare(fZoneID
) != 0) {
290 if (! uprv_getWindowsTimeZoneInfo(tzi
, icuid
.getBuffer(), icuid
.length())) {
292 int32_t ec
= TimeZone::countEquivalentIDs(icuid
);
294 for (int z
= 0; z
< ec
; z
+= 1) {
295 UnicodeString equiv
= TimeZone::getEquivalentID(icuid
, z
);
297 if (found
= uprv_getWindowsTimeZoneInfo(tzi
, equiv
.getBuffer(), equiv
.length())) {
303 GetTimeZoneInformation(tzi
);
313 #endif /* #if !UCONFIG_NO_FORMATTING */
315 #endif // U_PLATFORM_HAS_WIN32_API