icu 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +21 -0
- data/ext/extconf.rb +31 -0
- data/ext/icu.c +111 -0
- data/ext/icu.h +17 -0
- data/ext/icu_locale.c +313 -0
- data/ext/icu_locale_country.c +82 -0
- data/ext/icu_locale_language.c +82 -0
- data/ext/icu_numeric.c +175 -0
- data/ext/icu_time.c +374 -0
- data/lib/icu.rb +1 -0
- data/test/test_locale.rb +73 -0
- data/test/test_numeric.rb +78 -0
- data/test/test_time.rb +75 -0
- metadata +67 -0
@@ -0,0 +1,82 @@
|
|
1
|
+
#include "icu.h"
|
2
|
+
|
3
|
+
VALUE cCountry;
|
4
|
+
|
5
|
+
/******************* ICU::Locale::Country */
|
6
|
+
|
7
|
+
/**
|
8
|
+
* call-seq:
|
9
|
+
* ICU::Locale.get => locale
|
10
|
+
*/
|
11
|
+
VALUE rb_Country_class_get(VALUE self, VALUE code)
|
12
|
+
{
|
13
|
+
VALUE countries, country;
|
14
|
+
|
15
|
+
code = StringValue(code);
|
16
|
+
countries = rb_cv_get(self, "@@countries");
|
17
|
+
country = rb_hash_aref(countries, code);
|
18
|
+
if (country == Qnil) {
|
19
|
+
VALUE args[1];
|
20
|
+
|
21
|
+
args[0] = code;
|
22
|
+
country = rb_class_new_instance(1, args, self);
|
23
|
+
rb_hash_aset(countries, code, country);
|
24
|
+
return country;
|
25
|
+
} else {
|
26
|
+
return country;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
VALUE rb_Country_initialize(VALUE self, VALUE code)
|
31
|
+
{
|
32
|
+
code = StringValue(code);
|
33
|
+
CheckCountryCode(RSTRING(code)->ptr);
|
34
|
+
rb_iv_set(self, "@code", code);
|
35
|
+
|
36
|
+
return self;
|
37
|
+
}
|
38
|
+
|
39
|
+
VALUE rb_Country_name(int argc, VALUE *argv, VALUE self)
|
40
|
+
{
|
41
|
+
char fakeLocale[4] = "_";
|
42
|
+
VALUE code = rb_iv_get(self, "@code");
|
43
|
+
|
44
|
+
VALUE rb_locale;
|
45
|
+
char * locale = NULL;
|
46
|
+
|
47
|
+
UChar * country = ALLOC_N(UChar, 32);
|
48
|
+
int32_t countryLen = 32;
|
49
|
+
UErrorCode status = U_ZERO_ERROR;
|
50
|
+
|
51
|
+
strcat(fakeLocale, RSTRING(code)->ptr);
|
52
|
+
|
53
|
+
rb_scan_args(argc, argv, "01", &rb_locale);
|
54
|
+
if (rb_locale != Qnil) {
|
55
|
+
locale = StringValuePtr(rb_locale);
|
56
|
+
}
|
57
|
+
|
58
|
+
countryLen = uloc_getDisplayCountry(fakeLocale, locale, country, countryLen, &status);
|
59
|
+
if (status == U_BUFFER_OVERFLOW_ERROR) {
|
60
|
+
status = U_ZERO_ERROR;
|
61
|
+
REALLOC_N(country, UChar, countryLen);
|
62
|
+
uloc_getDisplayCountry(fakeLocale, locale, country, countryLen, &status);
|
63
|
+
}
|
64
|
+
RAISE_ON_ERROR(status);
|
65
|
+
|
66
|
+
return u_strToRString(country, countryLen);
|
67
|
+
}
|
68
|
+
|
69
|
+
void Init_ICU_Locale_Country()
|
70
|
+
{
|
71
|
+
extern VALUE cLocale;
|
72
|
+
|
73
|
+
cCountry = rb_define_class_under(cLocale, "Country", rb_cObject);
|
74
|
+
rb_funcall(cCountry, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("new")));
|
75
|
+
rb_cv_set(cCountry, "@@countries", rb_hash_new());
|
76
|
+
rb_define_singleton_method(cCountry, "get", rb_Country_class_get, 1);
|
77
|
+
rb_define_private_method(cCountry, "initialize", rb_Country_initialize, 1);
|
78
|
+
rb_define_attr(cCountry, "code", 1, 0);
|
79
|
+
rb_define_alias(cCountry, "to_str", "code");
|
80
|
+
rb_define_alias(cCountry, "to_s", "code");
|
81
|
+
rb_define_method(cCountry, "name", rb_Country_name, -1);
|
82
|
+
}
|
@@ -0,0 +1,82 @@
|
|
1
|
+
#include "icu.h"
|
2
|
+
|
3
|
+
VALUE cLanguage;
|
4
|
+
|
5
|
+
/******************* ICU::Locale::Language */
|
6
|
+
|
7
|
+
/**
|
8
|
+
* call-seq:
|
9
|
+
* ICU::Locale.get => locale
|
10
|
+
*/
|
11
|
+
VALUE rb_Language_class_get(VALUE self, VALUE code)
|
12
|
+
{
|
13
|
+
VALUE languages, language;
|
14
|
+
|
15
|
+
code = StringValue(code);
|
16
|
+
languages = rb_cv_get(self, "@@languages");
|
17
|
+
language = rb_hash_aref(languages, code);
|
18
|
+
if (language == Qnil) {
|
19
|
+
VALUE args[1];
|
20
|
+
|
21
|
+
args[0] = code;
|
22
|
+
language = rb_class_new_instance(1, args, self);
|
23
|
+
rb_hash_aset(languages, code, language);
|
24
|
+
return language;
|
25
|
+
} else {
|
26
|
+
return language;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
VALUE rb_Language_initialize(VALUE self, VALUE code)
|
31
|
+
{
|
32
|
+
code = StringValue(code);
|
33
|
+
CheckLanguageCode(RSTRING(code)->ptr);
|
34
|
+
rb_iv_set(self, "@code", code);
|
35
|
+
|
36
|
+
return self;
|
37
|
+
}
|
38
|
+
|
39
|
+
VALUE rb_Language_name(int argc, VALUE *argv, VALUE self)
|
40
|
+
{
|
41
|
+
char *fakeLocale;
|
42
|
+
VALUE code = rb_iv_get(self, "@code");
|
43
|
+
|
44
|
+
VALUE rb_locale;
|
45
|
+
char *locale = NULL;
|
46
|
+
|
47
|
+
UChar *language = ALLOC_N(UChar, 32);
|
48
|
+
int32_t languageLen = 32;
|
49
|
+
UErrorCode status = U_ZERO_ERROR;
|
50
|
+
|
51
|
+
fakeLocale = RSTRING(code)->ptr;
|
52
|
+
|
53
|
+
rb_scan_args(argc, argv, "01", &rb_locale);
|
54
|
+
if (rb_locale != Qnil) {
|
55
|
+
locale = StringValuePtr(rb_locale);
|
56
|
+
}
|
57
|
+
|
58
|
+
languageLen = uloc_getDisplayLanguage(fakeLocale, locale, language, languageLen, &status);
|
59
|
+
if (status == U_BUFFER_OVERFLOW_ERROR) {
|
60
|
+
status = U_ZERO_ERROR;
|
61
|
+
REALLOC_N(language, UChar, languageLen);
|
62
|
+
uloc_getDisplayLanguage(fakeLocale, locale, language, languageLen, &status);
|
63
|
+
}
|
64
|
+
RAISE_ON_ERROR(status);
|
65
|
+
|
66
|
+
return u_strToRString(language, languageLen);
|
67
|
+
}
|
68
|
+
|
69
|
+
void Init_ICU_Locale_Language()
|
70
|
+
{
|
71
|
+
extern VALUE cLocale;
|
72
|
+
|
73
|
+
cLanguage = rb_define_class_under(cLocale, "Language", rb_cObject);
|
74
|
+
rb_funcall(cLanguage, rb_intern("private_class_method"), 1, ID2SYM(rb_intern("new")));
|
75
|
+
rb_cv_set(cLanguage, "@@languages", rb_hash_new());
|
76
|
+
rb_define_singleton_method(cLanguage, "get", rb_Language_class_get, 1);
|
77
|
+
rb_define_private_method(cLanguage, "initialize", rb_Language_initialize, 1);
|
78
|
+
rb_define_attr(cLanguage, "code", 1, 0);
|
79
|
+
rb_define_alias(cLanguage, "to_str", "code");
|
80
|
+
rb_define_alias(cLanguage, "to_s", "code");
|
81
|
+
rb_define_method(cLanguage, "name", rb_Language_name, -1);
|
82
|
+
}
|
data/ext/icu_numeric.c
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
#include "icu.h"
|
2
|
+
|
3
|
+
#include "unicode/unum.h"
|
4
|
+
|
5
|
+
//UNumberFormatRoundingMode parseRoundingModeOption(VALUE rb_options)
|
6
|
+
//{
|
7
|
+
// VALUE rounding_mode;
|
8
|
+
//
|
9
|
+
// rounding_mode = rb_hash_aref(rb_options, ID2SYM(rb_intern("round_mode")));
|
10
|
+
// if (rounding_mode != Qnil) {
|
11
|
+
// ID rounding_mode_ID;
|
12
|
+
//
|
13
|
+
// Check_Type(rounding_mode, T_SYMBOL);
|
14
|
+
// rounding_mode_ID = SYM2ID(rounding_mode);
|
15
|
+
// if (rounding_mode_ID == rb_intern("ceil")) {
|
16
|
+
// return UNUM_ROUND_CEILING;
|
17
|
+
// } else if (rounding_mode_ID == rb_intern("floor")) {
|
18
|
+
// return UNUM_ROUND_FLOOR;
|
19
|
+
// } else if (rounding_mode_ID == rb_intern("down")) {
|
20
|
+
// return UNUM_ROUND_DOWN;
|
21
|
+
// } else if (rounding_mode_ID == rb_intern("up")) {
|
22
|
+
// return UNUM_ROUND_UP;
|
23
|
+
// } else if (rounding_mode_ID == rb_intern("halfeven")) {
|
24
|
+
// return UNUM_FOUND_HALFEVEN;
|
25
|
+
// } else if (rounding_mode_ID == rb_intern("halfdown")) {
|
26
|
+
// return UNUM_ROUND_HALFDOWN;
|
27
|
+
// } else if (rounding_mode_ID == rb_intern("halfup")) {
|
28
|
+
// return UNUM_ROUND_HALFUP;
|
29
|
+
// } else {
|
30
|
+
// rb_raise(rb_eArgError, "unsupported rounding mode '%s'", rb_id2name(rounding_mode_ID));
|
31
|
+
// }
|
32
|
+
// }
|
33
|
+
// return -1;
|
34
|
+
//}
|
35
|
+
|
36
|
+
/******************* Numeric */
|
37
|
+
|
38
|
+
/**
|
39
|
+
* call-seq:
|
40
|
+
* 23874.localize(:decimal, 'es_ES') => 23.874
|
41
|
+
*/
|
42
|
+
VALUE rb_numeric_localize(int argc, VALUE *argv, VALUE self)
|
43
|
+
{
|
44
|
+
VALUE style, options;
|
45
|
+
UNumberFormatStyle formatStyle;
|
46
|
+
char *locale = NULL;
|
47
|
+
|
48
|
+
UNumberFormat *format;
|
49
|
+
UErrorCode status;
|
50
|
+
|
51
|
+
UChar result[256];
|
52
|
+
/* arguments */
|
53
|
+
rb_scan_args(argc, argv, "02", &style, &options);
|
54
|
+
if (style == Qnil) {
|
55
|
+
formatStyle = UNUM_DECIMAL;
|
56
|
+
} else {
|
57
|
+
ID style_ID;
|
58
|
+
|
59
|
+
Check_Type(style, T_SYMBOL);
|
60
|
+
style_ID = SYM2ID(style);
|
61
|
+
if (style_ID == rb_intern("decimal")) {
|
62
|
+
formatStyle = UNUM_DECIMAL;
|
63
|
+
} else if (style_ID == rb_intern("currency")) {
|
64
|
+
formatStyle = UNUM_CURRENCY;
|
65
|
+
} else if (style_ID == rb_intern("percent")) {
|
66
|
+
formatStyle = UNUM_PERCENT;
|
67
|
+
} else if (style_ID == rb_intern("scientific")) {
|
68
|
+
formatStyle = UNUM_SCIENTIFIC;
|
69
|
+
} else if (style_ID == rb_intern("spellout")) {
|
70
|
+
formatStyle = UNUM_SPELLOUT;
|
71
|
+
} else {
|
72
|
+
rb_raise(rb_eArgError, "unsupported format style %s", rb_id2name(style_ID));
|
73
|
+
}
|
74
|
+
}
|
75
|
+
if (options != Qnil) {
|
76
|
+
VALUE rb_locale;
|
77
|
+
|
78
|
+
Check_Type(options, T_HASH);
|
79
|
+
rb_locale = rb_hash_aref(options, ID2SYM(rb_intern("locale")));
|
80
|
+
if (rb_locale != Qnil) {
|
81
|
+
locale = StringValuePtr(rb_locale);
|
82
|
+
}
|
83
|
+
}
|
84
|
+
/* formatter */
|
85
|
+
status = U_ZERO_ERROR;
|
86
|
+
format = unum_open(formatStyle, NULL, 0, locale, NULL, &status);
|
87
|
+
RAISE_ON_ERROR(status);
|
88
|
+
/* set format attributes */
|
89
|
+
if (options != Qnil) {
|
90
|
+
VALUE currency, precision, round_mode, round_increment;
|
91
|
+
|
92
|
+
switch (formatStyle) {
|
93
|
+
case UNUM_CURRENCY:
|
94
|
+
currency = rb_hash_aref(options, ID2SYM(rb_intern("currency")));
|
95
|
+
if (currency != Qnil) {
|
96
|
+
UChar *uStr;
|
97
|
+
int32_t uStrLen;
|
98
|
+
|
99
|
+
uStr = u_strFromRString(currency, &uStrLen);
|
100
|
+
status = U_ZERO_ERROR;
|
101
|
+
unum_setTextAttribute(format, UNUM_CURRENCY_CODE, uStr, uStrLen, &status);
|
102
|
+
RAISE_ON_ERROR(status);
|
103
|
+
}
|
104
|
+
case UNUM_DECIMAL:
|
105
|
+
/* precision */
|
106
|
+
precision = rb_hash_aref(options, ID2SYM(rb_intern("precision")));
|
107
|
+
if (precision != Qnil) {
|
108
|
+
Check_Type(precision, T_FIXNUM);
|
109
|
+
status = U_ZERO_ERROR;
|
110
|
+
unum_setAttribute(format, UNUM_FRACTION_DIGITS, NUM2INT(precision));
|
111
|
+
RAISE_ON_ERROR(status);
|
112
|
+
}
|
113
|
+
|
114
|
+
round_mode = rb_hash_aref(options, ID2SYM(rb_intern("round_mode")));
|
115
|
+
if (round_mode != Qnil) {
|
116
|
+
ID round_mode_ID;
|
117
|
+
UNumberFormatRoundingMode rounding_mode;
|
118
|
+
|
119
|
+
Check_Type(round_mode, T_SYMBOL);
|
120
|
+
round_mode_ID = SYM2ID(round_mode);
|
121
|
+
if (round_mode_ID == rb_intern("ceil")) {
|
122
|
+
rounding_mode = UNUM_ROUND_CEILING;
|
123
|
+
} else if (round_mode_ID == rb_intern("floor")) {
|
124
|
+
rounding_mode = UNUM_ROUND_FLOOR;
|
125
|
+
} else if (round_mode_ID == rb_intern("down")) {
|
126
|
+
rounding_mode = UNUM_ROUND_DOWN;
|
127
|
+
} else if (round_mode_ID == rb_intern("up")) {
|
128
|
+
rounding_mode = UNUM_ROUND_UP;
|
129
|
+
} else if (round_mode_ID == rb_intern("halfeven")) {
|
130
|
+
rounding_mode = UNUM_FOUND_HALFEVEN;
|
131
|
+
} else if (round_mode_ID == rb_intern("halfdown")) {
|
132
|
+
rounding_mode = UNUM_ROUND_HALFDOWN;
|
133
|
+
} else if (round_mode_ID == rb_intern("halfup")) {
|
134
|
+
rounding_mode = UNUM_ROUND_HALFUP;
|
135
|
+
} else {
|
136
|
+
rb_raise(rb_eArgError, "unsupported rounding mode '%s'", rb_id2name(round_mode_ID));
|
137
|
+
}
|
138
|
+
status = U_ZERO_ERROR;
|
139
|
+
unum_setAttribute(format, UNUM_ROUNDING_MODE, rounding_mode);
|
140
|
+
RAISE_ON_ERROR(status);
|
141
|
+
}
|
142
|
+
round_increment = rb_hash_aref(options, ID2SYM(rb_intern("round_increment")));
|
143
|
+
if (round_increment != Qnil) {
|
144
|
+
Check_Type(round_increment, T_FLOAT);
|
145
|
+
status = U_ZERO_ERROR;
|
146
|
+
unum_setDoubleAttribute(format, UNUM_ROUNDING_INCREMENT, NUM2DBL(round_increment));
|
147
|
+
RAISE_ON_ERROR(status);
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
/* format */
|
152
|
+
status = U_ZERO_ERROR;
|
153
|
+
switch (TYPE(self)) {
|
154
|
+
case T_FIXNUM:
|
155
|
+
unum_format(format, NUM2INT(self), result, 256, NULL, &status);
|
156
|
+
break;
|
157
|
+
case T_FLOAT:
|
158
|
+
unum_formatDouble(format, NUM2DBL(self), result, 256, NULL, &status);
|
159
|
+
break;
|
160
|
+
case T_BIGNUM:
|
161
|
+
unum_formatInt64(format, rb_big2ll(self), result, 256, NULL, &status);
|
162
|
+
break;
|
163
|
+
|
164
|
+
}
|
165
|
+
RAISE_ON_ERROR(status);
|
166
|
+
/* free resources */
|
167
|
+
unum_close(format);
|
168
|
+
|
169
|
+
return u_strToRString(result, -1);
|
170
|
+
}
|
171
|
+
|
172
|
+
void Init_ICU_Numeric(void)
|
173
|
+
{
|
174
|
+
rb_define_method(rb_cNumeric, "localize", rb_numeric_localize, -1);
|
175
|
+
}
|
data/ext/icu_time.c
ADDED
@@ -0,0 +1,374 @@
|
|
1
|
+
#include "icu.h"
|
2
|
+
|
3
|
+
#include "unicode/ucal.h"
|
4
|
+
#include "unicode/udat.h"
|
5
|
+
|
6
|
+
/******************* Time */
|
7
|
+
|
8
|
+
/**
|
9
|
+
* call-seq:
|
10
|
+
* 23874.localize(:date => :short) => 23.874
|
11
|
+
*/
|
12
|
+
VALUE rb_Time_localize(int argc, VALUE *argv, VALUE self)
|
13
|
+
{
|
14
|
+
VALUE options;
|
15
|
+
UDateFormatStyle dateStyle = UDAT_DEFAULT, timeStyle = UDAT_DEFAULT;
|
16
|
+
char *locale = NULL;
|
17
|
+
const UChar *timeZone = 0;
|
18
|
+
int32_t timeZoneLen = -1;
|
19
|
+
|
20
|
+
UDateFormat *format;
|
21
|
+
UErrorCode status;
|
22
|
+
UChar result[256];
|
23
|
+
/* arguments */
|
24
|
+
rb_scan_args(argc, argv, "01", &options);
|
25
|
+
if (options != Qnil) {
|
26
|
+
VALUE rb_locale, rb_timeZone;
|
27
|
+
|
28
|
+
Check_Type(options, T_HASH);
|
29
|
+
/* date and time style */
|
30
|
+
dateStyle = getStyle(options, "date");
|
31
|
+
timeStyle = getStyle(options, "time");
|
32
|
+
/* locale */
|
33
|
+
rb_locale = rb_hash_aref(options, ID2SYM(rb_intern("locale")));
|
34
|
+
if (rb_locale != Qnil) {
|
35
|
+
locale = StringValuePtr(rb_locale);
|
36
|
+
}
|
37
|
+
/* time zone */
|
38
|
+
rb_timeZone = rb_hash_aref(options, ID2SYM(rb_intern("zone")));
|
39
|
+
if (rb_timeZone != Qnil) {
|
40
|
+
Check_Type(rb_timeZone, T_STRING);
|
41
|
+
timeZone = u_strFromRString(rb_timeZone, &timeZoneLen);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
/* formatter */
|
46
|
+
status = U_ZERO_ERROR;
|
47
|
+
format = udat_open(timeStyle, dateStyle, locale, timeZone, timeZoneLen, NULL, -1, &status);
|
48
|
+
RAISE_ON_ERROR(status);
|
49
|
+
/* format */
|
50
|
+
status = U_ZERO_ERROR;
|
51
|
+
{
|
52
|
+
extern struct timeval rb_time_timeval(VALUE time);
|
53
|
+
struct timeval tv;
|
54
|
+
UDate dateToFormat;
|
55
|
+
UChar result[256];
|
56
|
+
|
57
|
+
tv = rb_time_timeval(self);
|
58
|
+
dateToFormat = ((double)tv.tv_sec + (double)tv.tv_usec / 1e6) * 1e3;
|
59
|
+
udat_format(format, dateToFormat, result, 256, NULL, &status);
|
60
|
+
RAISE_ON_ERROR(status);
|
61
|
+
/* free resources */
|
62
|
+
unum_close(format);
|
63
|
+
|
64
|
+
return u_strToRString(result, -1);
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
UDateFormatStyle getStyle(VALUE options, const char * key)
|
69
|
+
{
|
70
|
+
UDateFormatStyle formatStyle = UDAT_DEFAULT;
|
71
|
+
VALUE style;
|
72
|
+
|
73
|
+
style = rb_hash_aref(options, ID2SYM(rb_intern(key)));
|
74
|
+
if (style != Qnil) {
|
75
|
+
if (style == Qfalse) {
|
76
|
+
formatStyle = UDAT_NONE;
|
77
|
+
} else {
|
78
|
+
ID style_ID;
|
79
|
+
|
80
|
+
Check_Type(style, T_SYMBOL);
|
81
|
+
style_ID = SYM2ID(style);
|
82
|
+
if (style_ID == rb_intern("full")) {
|
83
|
+
formatStyle = UDAT_FULL;
|
84
|
+
} else if (style_ID == rb_intern("long")) {
|
85
|
+
formatStyle = UDAT_LONG;
|
86
|
+
} else if (style_ID == rb_intern("medium")) {
|
87
|
+
formatStyle = UDAT_MEDIUM;
|
88
|
+
} else if (style_ID == rb_intern("short")) {
|
89
|
+
formatStyle = UDAT_SHORT;
|
90
|
+
} else {
|
91
|
+
rb_raise(rb_eArgError, "unsupported format style %s", rb_id2name(style_ID));
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
return formatStyle;
|
97
|
+
}
|
98
|
+
|
99
|
+
VALUE enumToOptions(UEnumeration *enumeration, VALUE options, UCalendar *calendar, UCalendarDisplayNameType type, char *locale)
|
100
|
+
{
|
101
|
+
const UChar *zoneID;
|
102
|
+
int32_t zoneIDLen;
|
103
|
+
UErrorCode status = U_ZERO_ERROR;
|
104
|
+
|
105
|
+
while (zoneID = uenum_unext(enumeration, &zoneIDLen, &status)) {
|
106
|
+
RAISE_ON_ERROR(status);
|
107
|
+
if (type == -1) {
|
108
|
+
rb_ary_push(options, u_strToRString(zoneID, zoneIDLen));
|
109
|
+
} else {
|
110
|
+
VALUE option = rb_ary_new2(2);
|
111
|
+
UChar *zoneName = ALLOC_N(UChar, 64);
|
112
|
+
int32_t zoneNameLen = 64;
|
113
|
+
|
114
|
+
ucal_setTimeZone(calendar, zoneID, zoneIDLen, &status);
|
115
|
+
RAISE_ON_ERROR(status);
|
116
|
+
zoneNameLen = ucal_getTimeZoneDisplayName(calendar, UCAL_STANDARD, locale, zoneName, zoneNameLen, &status);
|
117
|
+
if (status == U_BUFFER_OVERFLOW_ERROR) {
|
118
|
+
status = U_ZERO_ERROR;
|
119
|
+
REALLOC_N(zoneName, UChar, zoneNameLen);
|
120
|
+
ucal_getTimeZoneDisplayName(calendar, UCAL_STANDARD, locale, zoneName, zoneNameLen, &status);
|
121
|
+
}
|
122
|
+
RAISE_ON_ERROR(status);
|
123
|
+
rb_ary_push(option, u_strToRString(zoneName, zoneNameLen));
|
124
|
+
rb_ary_push(option, u_strToRString(zoneID, zoneIDLen));
|
125
|
+
rb_ary_push(options, option);
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
return options;
|
130
|
+
}
|
131
|
+
|
132
|
+
/**
|
133
|
+
* call-seq:
|
134
|
+
* Time.zones(:countries => ['US'], :locale => 'es_ES', :type => :short) => 23.874
|
135
|
+
* Time.zones(:countries => :all, :group => true) => 23.874
|
136
|
+
*/
|
137
|
+
VALUE rb_Time_singleton_zones(int argc, VALUE *argv, VALUE self)
|
138
|
+
{
|
139
|
+
VALUE options, countries = Qfalse, group = Qfalse;
|
140
|
+
char *locale = NULL;
|
141
|
+
UCalendarDisplayNameType type = -1;
|
142
|
+
|
143
|
+
UCalendar *calendar;
|
144
|
+
UErrorCode status = U_ZERO_ERROR;
|
145
|
+
UEnumeration *enumeration;
|
146
|
+
VALUE select = rb_ary_new();
|
147
|
+
UCollator *collator;
|
148
|
+
|
149
|
+
//arguments
|
150
|
+
rb_scan_args(argc, argv, "01", &options);
|
151
|
+
if (options != Qnil) {
|
152
|
+
VALUE rb_locale, rb_type;
|
153
|
+
|
154
|
+
Check_Type(options, T_HASH);
|
155
|
+
//locale
|
156
|
+
rb_locale = rb_hash_aref(options, ID2SYM(rb_intern("locale")));
|
157
|
+
if (rb_locale != Qnil) {
|
158
|
+
locale = StringValuePtr(rb_locale);
|
159
|
+
}
|
160
|
+
//countries
|
161
|
+
countries = rb_hash_aref(options, ID2SYM(rb_intern("countries")));
|
162
|
+
if (countries == Qnil) {
|
163
|
+
countries = Qfalse;
|
164
|
+
} else {
|
165
|
+
|
166
|
+
}
|
167
|
+
//group
|
168
|
+
group = rb_hash_aref(options, ID2SYM(rb_intern("group")));
|
169
|
+
group = group && group != Qnil ? Qtrue : Qfalse;
|
170
|
+
//type
|
171
|
+
rb_type = rb_hash_aref(options, ID2SYM(rb_intern("type")));
|
172
|
+
if (rb_type != Qnil) {
|
173
|
+
ID rb_type_ID;
|
174
|
+
|
175
|
+
Check_Type(rb_type, T_SYMBOL);
|
176
|
+
rb_type_ID = SYM2ID(rb_type);
|
177
|
+
if (rb_type_ID == rb_intern("standard")) {
|
178
|
+
type = UCAL_STANDARD;
|
179
|
+
} else if (rb_type_ID == rb_intern("short_standard")) {
|
180
|
+
type = UCAL_SHORT_STANDARD;
|
181
|
+
} else if (rb_type_ID == rb_intern("dst")) {
|
182
|
+
type = UCAL_DST;
|
183
|
+
} else if (rb_type_ID == rb_intern("short_dst")) {
|
184
|
+
type = UCAL_SHORT_DST;
|
185
|
+
} else {
|
186
|
+
rb_raise(rb_eArgError, "unsupported time zone type %s", rb_id2name(rb_type_ID));
|
187
|
+
}
|
188
|
+
}
|
189
|
+
}
|
190
|
+
//calendar
|
191
|
+
calendar = ucal_open(NULL, -1, locale, UCAL_GREGORIAN, &status);
|
192
|
+
RAISE_ON_ERROR(status);
|
193
|
+
|
194
|
+
collator = ucol_open(locale, &status);
|
195
|
+
RAISE_ON_ERROR(status);
|
196
|
+
|
197
|
+
if (countries) {
|
198
|
+
const char* const* isoCountries = uloc_getISOCountries();
|
199
|
+
|
200
|
+
while (*isoCountries != NULL) {
|
201
|
+
if (TYPE(countries) == T_SYMBOL || (TYPE(countries) == T_ARRAY && rb_ary_includes(countries, rb_str_new2(*isoCountries)))) {
|
202
|
+
if (group) {
|
203
|
+
char fakeLocale[4] = "_";
|
204
|
+
UChar *country = ALLOC_N(UChar, 32);
|
205
|
+
int32_t countryLen = 32;
|
206
|
+
VALUE optgroup = rb_ary_new2(2);
|
207
|
+
|
208
|
+
strcat(fakeLocale, *isoCountries);
|
209
|
+
countryLen = uloc_getDisplayCountry(fakeLocale, locale, country, countryLen, &status);
|
210
|
+
if (status == U_BUFFER_OVERFLOW_ERROR) {
|
211
|
+
status = U_ZERO_ERROR;
|
212
|
+
REALLOC_N(country, UChar, countryLen);
|
213
|
+
uloc_getDisplayCountry(fakeLocale, locale, country, countryLen, &status);
|
214
|
+
}
|
215
|
+
rb_ary_push(optgroup, u_strToRString(country, countryLen));
|
216
|
+
enumeration = ucal_openCountryTimeZones(*isoCountries, &status);
|
217
|
+
RAISE_ON_ERROR(status);
|
218
|
+
rb_ary_push(optgroup, enumToOptions(enumeration, rb_ary_new(), calendar, type, locale));
|
219
|
+
uenum_close(enumeration);
|
220
|
+
if (RARRAY(RARRAY(optgroup)->ptr[1])->len) {
|
221
|
+
ruby_qsort(RARRAY(RARRAY(optgroup)->ptr[1])->ptr, RARRAY(RARRAY(optgroup)->ptr[1])->len, sizeof(VALUE), collateByDisplayName, collator);
|
222
|
+
rb_ary_push(select, optgroup);
|
223
|
+
}
|
224
|
+
} else {
|
225
|
+
enumeration = ucal_openCountryTimeZones(*isoCountries, &status);
|
226
|
+
RAISE_ON_ERROR(status);
|
227
|
+
enumToOptions(enumeration, select, calendar, type, locale);
|
228
|
+
uenum_close(enumeration);
|
229
|
+
}
|
230
|
+
}
|
231
|
+
*isoCountries++;
|
232
|
+
}
|
233
|
+
} else {
|
234
|
+
enumeration = ucal_openTimeZones(&status);
|
235
|
+
RAISE_ON_ERROR(status);
|
236
|
+
enumToOptions(enumeration, select, calendar, type, locale);
|
237
|
+
uenum_close(enumeration);
|
238
|
+
}
|
239
|
+
//sort
|
240
|
+
ruby_qsort(RARRAY(select)->ptr, RARRAY(select)->len, sizeof(VALUE), collateByDisplayName, collator);
|
241
|
+
//free
|
242
|
+
ucal_close(calendar);
|
243
|
+
ucol_close(collator);
|
244
|
+
|
245
|
+
return select;
|
246
|
+
}
|
247
|
+
|
248
|
+
/**
|
249
|
+
* call-seq:
|
250
|
+
* Time.default_zone = 'GMT'
|
251
|
+
*/
|
252
|
+
VALUE rb_Time_singleton_set_default_zone(VALUE self, VALUE zone)
|
253
|
+
{
|
254
|
+
UErrorCode status = U_ZERO_ERROR;
|
255
|
+
|
256
|
+
ucal_setDefaultTimeZone((const UChar *)u_strFromRString(zone, NULL), &status);
|
257
|
+
RAISE_ON_ERROR(status);
|
258
|
+
|
259
|
+
return zone;
|
260
|
+
}
|
261
|
+
|
262
|
+
/**
|
263
|
+
* call-seq:
|
264
|
+
* Time.default_zone -> 'GMT'
|
265
|
+
*/
|
266
|
+
VALUE rb_Time_singleton_get_default_zone(VALUE self)
|
267
|
+
{
|
268
|
+
UChar * timeZone = ALLOC_N(UChar, 64);
|
269
|
+
int32_t timeZoneLen;
|
270
|
+
UErrorCode status = U_ZERO_ERROR;
|
271
|
+
|
272
|
+
timeZoneLen = ucal_getDefaultTimeZone(timeZone, 2, &status);
|
273
|
+
if (status == U_BUFFER_OVERFLOW_ERROR) {
|
274
|
+
status = U_ZERO_ERROR;
|
275
|
+
REALLOC_N(timeZone, UChar, timeZoneLen);
|
276
|
+
ucal_getDefaultTimeZone(timeZone, timeZoneLen, &status);
|
277
|
+
}
|
278
|
+
RAISE_ON_ERROR(status);
|
279
|
+
|
280
|
+
return u_strToRString(timeZone, timeZoneLen);
|
281
|
+
}
|
282
|
+
|
283
|
+
/**
|
284
|
+
* call-seq:
|
285
|
+
* 23874.localize(:date => :short) => 23.874
|
286
|
+
*/
|
287
|
+
VALUE rb_Time_singleton_pattern(int argc, VALUE *argv, VALUE self)
|
288
|
+
{
|
289
|
+
VALUE options;
|
290
|
+
UDateFormatStyle dateStyle = UDAT_DEFAULT, timeStyle = UDAT_DEFAULT;
|
291
|
+
char *locale = NULL;
|
292
|
+
|
293
|
+
UDateFormat *format;
|
294
|
+
UErrorCode status = U_ZERO_ERROR;
|
295
|
+
|
296
|
+
UChar * pattern = ALLOC_N(UChar, 64);
|
297
|
+
int32_t patternLen;
|
298
|
+
|
299
|
+
/* arguments */
|
300
|
+
rb_scan_args(argc, argv, "01", &options);
|
301
|
+
if (options != Qnil) {
|
302
|
+
VALUE rb_locale;
|
303
|
+
|
304
|
+
Check_Type(options, T_HASH);
|
305
|
+
/* date and time style */
|
306
|
+
dateStyle = getStyle(options, "date");
|
307
|
+
timeStyle = getStyle(options, "time");
|
308
|
+
/* locale */
|
309
|
+
rb_locale = rb_hash_aref(options, ID2SYM(rb_intern("locale")));
|
310
|
+
if (rb_locale != Qnil) {
|
311
|
+
locale = StringValuePtr(rb_locale);
|
312
|
+
}
|
313
|
+
}
|
314
|
+
/* formatter */
|
315
|
+
status = U_ZERO_ERROR;
|
316
|
+
format = udat_open(timeStyle, dateStyle, locale, NULL, 0, NULL, 0, &status);
|
317
|
+
RAISE_ON_ERROR(status);
|
318
|
+
/* pattern */
|
319
|
+
patternLen = udat_toPattern(format, 0, pattern, 64, &status);
|
320
|
+
if (status == U_BUFFER_OVERFLOW_ERROR) {
|
321
|
+
status = U_ZERO_ERROR;
|
322
|
+
REALLOC_N(pattern, UChar, patternLen);
|
323
|
+
udat_toPattern(format, 0, pattern, 64, &status);
|
324
|
+
}
|
325
|
+
RAISE_ON_ERROR(status);
|
326
|
+
/* free */
|
327
|
+
udat_close(format);
|
328
|
+
|
329
|
+
return u_strToRString(pattern, patternLen);
|
330
|
+
}
|
331
|
+
|
332
|
+
/**
|
333
|
+
* call-seq:
|
334
|
+
* 23874.localize(:date => :short) => 23.874
|
335
|
+
*/
|
336
|
+
VALUE rb_Time_singleton_week_start(int argc, VALUE *argv, VALUE self)
|
337
|
+
{
|
338
|
+
VALUE options;
|
339
|
+
char * locale = NULL;
|
340
|
+
UErrorCode status = U_ZERO_ERROR;
|
341
|
+
UCalendar * calendar;
|
342
|
+
int32_t result;
|
343
|
+
|
344
|
+
/* arguments */
|
345
|
+
rb_scan_args(argc, argv, "01", &options);
|
346
|
+
if (options != Qnil) {
|
347
|
+
VALUE rb_locale;
|
348
|
+
|
349
|
+
Check_Type(options, T_HASH);
|
350
|
+
/* locale */
|
351
|
+
rb_locale = rb_hash_aref(options, ID2SYM(rb_intern("locale")));
|
352
|
+
if (rb_locale != Qnil) {
|
353
|
+
locale = StringValuePtr(rb_locale);
|
354
|
+
}
|
355
|
+
}
|
356
|
+
/* calendar */
|
357
|
+
calendar = ucal_open(NULL, 0, locale, UCAL_GREGORIAN, &status);
|
358
|
+
RAISE_ON_ERROR(status);
|
359
|
+
/* attribute */
|
360
|
+
result = ucal_getAttribute(calendar, UCAL_FIRST_DAY_OF_WEEK);
|
361
|
+
ucal_close(calendar);
|
362
|
+
|
363
|
+
return INT2NUM(result);
|
364
|
+
}
|
365
|
+
|
366
|
+
void Init_ICU_Time(void)
|
367
|
+
{
|
368
|
+
rb_define_method(rb_cTime, "localize", rb_Time_localize, -1);
|
369
|
+
rb_define_singleton_method(rb_cTime, "zones", rb_Time_singleton_zones, -1);
|
370
|
+
rb_define_singleton_method(rb_cTime, "default_zone=", rb_Time_singleton_set_default_zone, 1);
|
371
|
+
rb_define_singleton_method(rb_cTime, "default_zone", rb_Time_singleton_get_default_zone, 0);
|
372
|
+
rb_define_singleton_method(rb_cTime, "pattern", rb_Time_singleton_pattern, -1);
|
373
|
+
rb_define_singleton_method(rb_cTime, "week_start", rb_Time_singleton_week_start, -1);
|
374
|
+
}
|