ICU-5990 Merging time zone formatting/parsing changes from yoshito's working branch to the trunk.

X-SVN-Rev: 22978
This commit is contained in:
Yoshito Umaoka 2007-11-28 20:49:58 +00:00
parent d1599f4771
commit 7e51ed7330
72 changed files with 9602 additions and 2278 deletions

1
.gitattributes vendored
View file

@ -48,6 +48,7 @@ README text !eol
*.spp -text
*.tri2 -text
icu4c/source/data/misc/metazoneInfo.txt -text
icu4c/source/data/xml/collation/as.xml -text
icu4c/source/data/xml/collation/bn.xml -text
icu4c/source/data/xml/collation/cy.xml -text

View file

@ -170,7 +170,7 @@ static const char * const LANGUAGES[] = {
"ty", "tyv", "udm", "ug", "uga", "uk", "umb", "und", "ur",
"uz", "vai", "ve", "vi", "vo", "vot", "wa", "wak",
"wal", "war", "was", "wen", "wo", "xal", "xh", "yao", "yap",
"yi", "yo", "ypk", "za", "zap", "zen", "zh", "znd",
"yi", "yo", "ypk", "za", "zap", "zbl", "zen", "zh", "znd",
"zu", "zun", "zxx", "zza",
NULL,
"in", "iw", "ji", "jw", "sh", /* obsolete language codes */
@ -310,8 +310,8 @@ static const char * const LANGUAGES_3[] = {
"uzb", "vai", "ven", "vie", "vol", "vot", "wln", "wak",
/* "wal", "war", "was", "wen", "wo", "xal", "xh", "yao", "yap", */
"wal", "war", "was", "wen", "wol", "xal", "xho", "yao", "yap",
/* "yi", "yo", "ypk", "za", "zap", "zen", "zh", "znd", */
"yid", "yor", "ypk", "zha", "zap", "zen", "zho", "znd",
/* "yi", "yo", "ypk", "za", "zap", "zbl", "zen", "zh", "znd", */
"yid", "yor", "ypk", "zha", "zap", "zbl", "zen", "zho", "znd",
/* "zu", "zun", "zxx", "zza", */
"zul", "zun", "zxx", "zza",
NULL,

View file

@ -70,7 +70,7 @@
</taskdef>
</target>
<!-- target for generating ICU data -->
<target name="all" depends="locales, resfiles, collation, colfiles, supplementalData, brkitr, brkfiles" />
<target name="all" depends="locales, resfiles, collation, colfiles, supplementalData, metazoneInfo, brkitr, brkfiles" />
<!-- parallel target -->
<target name="pall" depends="init">
@ -237,6 +237,20 @@
</run>
</cldr-build>
</target>
<target name="metazoneInfo" depends="init,setup" description="builds metazoneInfo.txt from metazoneInfo.xml">
<cldr-build toolName="org.unicode.cldr.icu.LDML2ICUConverter" destFile="metazoneInfo.txt" noArgs="true">
<!-- launch the tool and generate the data after reading the config file -->
<run>
<args>
<arg name="-s" value="${env.CLDR_DIR}/common/supplemental" />
<arg name="-d" value="${env.ICU4C_DIR}/source/data/misc"/>
<arg name="-z"/>
<arg name="-f"/>
<arg name="-m" value="${env.CLDR_DIR}/common/supplemental" />
</args>
</run>
</cldr-build>
</target>
<target name="brkitr" depends="init,setup" description="builds break iterator files in ICU text format">
<cldr-build toolName="org.unicode.cldr.icu.LDML2ICUConverter" srcFile=".*xml" destFile=".*txt">
<run>
@ -316,6 +330,9 @@
<fileset id="locales" dir="${env.ICU4C_DIR}/source/data/misc">
<include name="supplementalData.txt" />
</fileset>
<fileset id="locales" dir="${env.ICU4C_DIR}/source/data/misc">
<include name="metazoneInfo.txt" />
</fileset>
</delete>
</target>
</project>

View file

@ -1413,7 +1413,7 @@ bg{
traditional{"Традиционно"}
}
}
Version{"1.89"}
Version{"1.90"}
calendar{
gregorian{
AmPmMarkers{
@ -2197,12 +2197,6 @@ bg{
"meta:GMT"{
ls{"Часова зона Гринуич"}
}
"meta:Hawaii"{
ld{"Лятна часова зона Хавай"}
ls{"Часова зона Хавай"}
sd{"HDT"}
ss{"HST"}
}
"meta:Israel"{
ld{"Лятна часова зона Израел"}
ls{"Часова зона Израел"}

View file

@ -1441,7 +1441,7 @@ cs{
japanese{"Japonský kalendář"}
}
}
Version{"1.103"}
Version{"1.104"}
calendar{
gregorian{
AmPmMarkers{
@ -1723,12 +1723,6 @@ cs{
ls{"Greenwichský střední čas"}
ss{"GMT"}
}
"meta:Hawaii"{
ld{"Havajský letní čas"}
ls{"Havajský standardní čas"}
sd{"HDT"}
ss{"HST"}
}
"meta:Israel"{
ld{"Izraelský letní čas"}
ls{"Izraelský standardní čas"}

View file

@ -1918,7 +1918,7 @@ da{
traditional{"traditionel sorteringsrækkefølge"}
}
}
Version{"1.89"}
Version{"1.90"}
calendar{
gregorian{
AmPmMarkers{
@ -2270,7 +2270,6 @@ da{
lg{"mellemeuropæisk tid"}
ls{"mellemeuropæisk normaltid"}
sd{"CEST"}
sg{"CET"}
ss{"CET"}
}
"meta:Europe_Eastern"{
@ -2279,7 +2278,6 @@ da{
lg{"østeuropæisk tid"}
ls{"østeuropæisk normaltid"}
sd{"EEST"}
sg{"EET"}
ss{"EET"}
}
"meta:Europe_Western"{
@ -2287,23 +2285,14 @@ da{
ld{"vesteuropæisk sommertid"}
lg{"vesteuropæisk tid"}
ls{"vesteuropæisk normaltid"}
sg{"WET"}
sd{"WEST"}
ss{"WET"}
}
"meta:GMT"{
cu:int{1}
ld{"GMT-sommertid"}
lg{"verdenstid"}
ls{"Verdenstid"}
sd{"GMT"}
sg{"GMT"}
ss{"GMT"}
}
"meta:Hawaii"{
ld{"Hawaii-sommertid"}
ls{"Hawaii-normaltid"}
sd{"HDT"}
ss{"HST"}
}
"meta:Israel"{
ld{"Israelsk sommertid"}
ls{"Israelsk normaltid"}

View file

@ -75,6 +75,7 @@ en{
BH{"Bahrain"}
BI{"Burundi"}
BJ{"Benin"}
BL{"Saint Barthélemy"}
BM{"Bermuda"}
BN{"Brunei"}
BO{"Bolivia"}
@ -188,6 +189,7 @@ en{
MC{"Monaco"}
MD{"Moldova"}
ME{"Montenegro"}
MF{"Saint Martin"}
MG{"Madagascar"}
MH{"Marshall Islands"}
MK{"Macedonia"}
@ -1882,6 +1884,7 @@ en{
ypk{"Yupik Language"}
za{"Zhuang"}
zap{"Zapotec"}
zbl{"Blissymbols"}
zen{"Zenaga"}
zh{"Chinese"}
zh_Hans{"Simplified Chinese"}
@ -1918,6 +1921,7 @@ en{
Scripts{
Arab{"Arabic"}
Armn{"Armenian"}
Avst{"Avestan"}
Bali{"Balinese"}
Batk{"Batak"}
Beng{"Bengali"}
@ -1981,6 +1985,7 @@ en{
Lyci{"Lycian"}
Lydi{"Lydian"}
Mand{"Mandaean"}
Mani{"Manichaean"}
Maya{"Mayan hieroglyphs"}
Mero{"Meroitic"}
Mlym{"Malayalam"}
@ -1996,12 +2001,14 @@ en{
Osma{"Osmanya"}
Perm{"Old Permic"}
Phag{"Phags-pa"}
Phlv{"Book Pahlavi"}
Phnx{"Phoenician"}
Plrd{"Pollard Phonetic"}
Qaai{"Inherited"}
Rjng{"Rejang"}
Roro{"Rongorongo"}
Runr{"Runic"}
Samr{"Samaritan"}
Sara{"Sarati"}
Saur{"Saurashtra"}
Sgnw{"SignWriting"}
@ -2057,6 +2064,7 @@ en{
Variants{
1606NICT{"Late Middle French to 1606"}
1901{"Traditional German orthography"}
1994{"Standardized Resian orthography"}
1996{"German orthography of 1996"}
AREVELA{"Eastern Armenian"}
BAKU1926{"Unified Turkic Latin Alphabet"}
@ -2067,6 +2075,7 @@ en{
GAULISH{"Gaulish"}
GUOYU{"Mandarin or Standard Chinese"}
HAKKA{"Hakka"}
LIPAW{"The Lipovaz dialect of Resian"}
LOJBAN{"Lojban"}
MONOTON{"Monotonic"}
NEDIS{"Natisone dialect"}
@ -2077,12 +2086,13 @@ en{
REVISED{"Revised Orthography"}
ROZAJ{"Resian"}
SAAHO{"Saho"}
SCOTLAND{"Scottish Standard English"}
SCOUSE{"Scouse"}
SOLBA{"Stolvizza/Solbica dialect"}
TARASK{"Taraskievica orthography"}
XIANG{"Xiang or Hunanese"}
}
Version{"1.158"}
Version{"1.161"}
calendar{
gregorian{
AmPmMarkers{
@ -2253,8 +2263,8 @@ en{
"meta:Acre"{
ld{"Acre Summer Time"}
ls{"Acre Time"}
sd{"ACST"}
ss{"ACT"}
sd{"ACST (Acre)"}
ss{"ACT (Acre)"}
}
"meta:Afghanistan"{
ls{"Afghanistan Time"}

View file

@ -23,7 +23,7 @@ en_AU{
"#,##0%",
"#E0",
}
Version{"1.45"}
Version{"1.46"}
calendar{
gregorian{
DateTimeElements:intvector{

View file

@ -17,7 +17,7 @@ en_CA{
"US Dollar",
}
}
Version{"1.53"}
Version{"1.54"}
calendar{
gregorian{
DateTimeElements:intvector{

View file

@ -13,7 +13,7 @@ en_GB{
"#,##0%",
"#E0",
}
Version{"1.54"}
Version{"1.55"}
calendar{
gregorian{
DateTimePatterns{

View file

@ -23,7 +23,7 @@ en_NZ{
"#,##0%",
"#E0",
}
Version{"1.48"}
Version{"1.49"}
calendar{
gregorian{
DateTimeElements:intvector{

View file

@ -13,7 +13,7 @@ en_ZA{
"#,##0%",
"#E0",
}
Version{"1.49"}
Version{"1.50"}
calendar{
gregorian{
DateTimeElements:intvector{

View file

@ -19,7 +19,7 @@ en_ZW{
"#,##0%",
"#E0",
}
Version{"1.42"}
Version{"1.43"}
calendar{
gregorian{
DateTimeElements:intvector{

View file

@ -1953,7 +1953,7 @@ es{
Variants{
REVISED{"Ortografía revisada"}
}
Version{"1.98"}
Version{"1.99"}
calendar{
gregorian{
AmPmMarkers{
@ -2496,7 +2496,7 @@ es{
"meta:China"{
ld{"Hora de verano de China"}
ls{"Hora estándar de China"}
ss{"CTT"}
ss{"CST (China)"}
}
"meta:Europe_Central"{
ld{"Hora de verano de Europa Central"}
@ -2514,11 +2514,8 @@ es{
ls{"Hora media de Greenwich"}
ss{"GMT"}
}
"meta:Hawaii"{
"meta:Hawaii_Aleutian"{
cu:int{1}
ld{"Hora de verano de Hawai"}
ls{"Hora estándar de Hawai"}
sd{"HDT"}
ss{"HST"}
}
"meta:Israel"{
@ -2536,7 +2533,7 @@ es{
"meta:Newfoundland"{
ld{"Hora de verano de Newfoundland"}
ls{"Hora estándar de Newfoundland"}
ss{"CNT"}
ss{"NST"}
}
}
}

View file

@ -1056,7 +1056,7 @@ fa{
1996{"رسم‌الخط آلمانی ۱۹۹۶ میلادی"}
REVISED{"رسم‌الخط تجدیدنظرشده"}
}
Version{"1.78"}
Version{"1.79"}
calendar{
gregorian{
AmPmMarkers{
@ -1615,8 +1615,8 @@ fa{
ec{"تاهیتی"}
}
"meta:Afghanistan"{
lg{"وقت افغانستان"}
sg{"AFT"}
ls{"وقت افغانستان"}
ss{"AFT"}
}
"meta:Iran"{
ld{"وقت تابستانی ایران"}

View file

@ -2069,7 +2069,7 @@ fi{
SCOUSE{"englannin scouse-murre"}
VALENCIA{"katalaanin valencia-murre"}
}
Version{"1.95"}
Version{"1.96"}
calendar{
gregorian{
AmPmMarkers{
@ -2756,13 +2756,6 @@ fi{
"meta:Guyana"{
cu:int{0}
}
"meta:Hawaii"{
cu:int{0}
ld{"Havaijin kesäaika"}
ls{"Havaijin normaaliaika"}
sd{"HDT"}
ss{"HST"}
}
"meta:Hawaii_Aleutian"{
cu:int{0}
}

View file

@ -2023,7 +2023,7 @@ fr{
SCOUSE{"dialecte scouse"}
VALENCIA{"valencien"}
}
Version{"1.106"}
Version{"1.107"}
calendar{
chinese{
monthNames{
@ -2639,13 +2639,6 @@ fr{
sd{"HAEE"}
ss{"HEE"}
}
"meta:Hawaii"{
ld{"Heure avancée dHawaï"}
lg{"Heure dHawaï"}
ls{"Heure normale dHawaï"}
sd{"HDT"}
ss{"HST"}
}
"meta:Israel"{
ld{"Heure avancée dIsraël"}
ls{"Heure normale dIsraël"}

View file

@ -23,7 +23,7 @@ fr_CA{
"#,##0 %",
"#E0",
}
Version{"1.49"}
Version{"1.50"}
calendar{
gregorian{
DateTimeElements:intvector{

View file

@ -1748,7 +1748,7 @@ hu{
NEDIS{"Natisone dialektus"}
REVISED{"Átdolgozott helyesírás"}
}
Version{"1.88"}
Version{"1.89"}
calendar{
buddhist{
eras{

View file

@ -1404,7 +1404,7 @@ is{
traditional{"Hefðbundin"}
}
}
Version{"1.76"}
Version{"1.77"}
calendar{
gregorian{
DateTimePatterns{

View file

@ -1956,7 +1956,7 @@ it{
ROZAJ{"resiano"}
SAAHO{"saho"}
}
Version{"1.92"}
Version{"1.93"}
calendar{
gregorian{
AmPmMarkers{
@ -2325,7 +2325,7 @@ it{
ls{"Ora Standard Alaska"}
}
"meta:China"{
ld{"Ora Standard Cina"}
ld{"Ora Legale Cina"}
ls{"Ora Standard Cina"}
sd{"CDT (Cina)"}
ss{"CST (Cina)"}

View file

@ -1975,7 +1975,7 @@ ja{
POSIX{"コンピュータ"}
REVISED{"改訂版"}
}
Version{"1.114"}
Version{"1.115"}
calendar{
gregorian{
AmPmMarkers{
@ -3044,12 +3044,6 @@ ja{
ls{"グリニッジ標準時"}
ss{"GMT"}
}
"meta:Hawaii"{
ld{"ハワイ夏時間"}
ls{"ハワイ標準時"}
sd{"HDT"}
ss{"HST"}
}
"meta:Israel"{
ld{"イスラエル夏時間"}
ls{"イスラエル標準時"}

View file

@ -1906,7 +1906,7 @@ ko{
Variants{
REVISED{"개정"}
}
Version{"1.95"}
Version{"1.96"}
calendar{
buddhist{
eras{
@ -2951,12 +2951,6 @@ ko{
ls{"그리니치 표준시"}
ss{"GMT"}
}
"meta:Hawaii"{
ld{"하와이 하계 표준시"}
ls{"하와이 표준시"}
sd{"HDT"}
ss{"HST"}
}
"meta:Israel"{
ld{"이스라엘 하계 표준시"}
ls{"이스라엘 표준시"}

View file

@ -1996,7 +1996,7 @@ nl{
SAAHO{"Saho"}
SCOUSE{"Liverpools (Scouse)"}
}
Version{"1.93"}
Version{"1.94"}
calendar{
gregorian{
DateTimePatterns{
@ -2516,12 +2516,6 @@ nl{
ls{"Greenwich Mean Time"}
ss{"GMT"}
}
"meta:Hawaii"{
ld{"Hawaï-zomertijd"}
ls{"Hawaï-standaardtijd"}
sd{"HDT"}
ss{"HST"}
}
"meta:Israel"{
ld{"Israëlische zomertijd"}
ls{"Israëlische standaardtijd"}

View file

@ -1991,7 +1991,7 @@ pt{
SAAHO{"saho"}
SCOUSE{"scouse"}
}
Version{"1.89"}
Version{"1.90"}
calendar{
buddhist{
DateTimePatterns{
@ -2443,7 +2443,7 @@ pt{
lg{"Horário da Austrália Central"}
ls{"Horário Padrão da Austrália Central"}
sd{"ACDT"}
ss{"ACST"}
ss{"ACST (Austrália)"}
}
"meta:Australia_Eastern"{
ld{"Horário de Verão da Austrália Oriental"}
@ -2611,21 +2611,9 @@ pt{
ls{"Horário Padrão de Gulf"}
ss{"GST"}
}
"meta:Hawaii"{
ld{"Horário de Verão do Havaí"}
lg{"Horário do Havaí"}
ls{"Horário Padrão do Havaí"}
sd{"HDT"}
sg{"HT"}
ss{"HST"}
}
"meta:Hawaii_Aleutian"{
ld{"Horário de Verão do Havaí-Aleuta"}
lg{"Horário do Havaí-Aleuta"}
ls{"Horário Padrão do Havaí-Aleuta"}
sd{"HADT"}
sg{"HAT"}
ss{"HAST"}
ss{"HST"}
}
"meta:India"{
ls{"Horário Padrão da Índia"}
@ -2647,7 +2635,7 @@ pt{
ld{"Horário de Verão de Israel"}
ls{"Horário Padrão de Israel"}
sd{"IDT"}
ss{"IST"}
ss{"IST (Israel)"}
}
"meta:Japan"{
ld{"Horário de Verão do Japão"}

View file

@ -199,7 +199,7 @@ pt_PT{
phonebook{"Ordem da Lista Telefónica"}
}
}
Version{"1.63"}
Version{"1.64"}
calendar{
buddhist{
DateTimePatterns{
@ -400,10 +400,6 @@ pt_PT{
"meta:Europe_Central"{
ls{"Horário Padrão da Europa Central"}
}
"meta:Hawaii"{
ld{"Horário de Verão do Havai"}
ls{"Horário Padrão do Havai"}
}
"meta:Newfoundland"{
ld{"Horário de Verão da Terra Nova"}
ls{"Horário Padrão da Terra Nova"}

View file

@ -16,13 +16,11 @@ GENRB_CLDR_VERSION = 1.5
# * To add an additional locale to the list:
# _____________________________________________________
# | GENRB_SOURCE_LOCAL = myLocale.txt ...
# | GENRB_ALIAS_SOURCE_LOCAL = myAliasLocale.txt ...
#
# * To REPLACE the default list and only build with a few
# locale:
# _____________________________________________________
# | GENRB_SOURCE = ar.txt ar_AE.txt en.txt de.txt zh.txt
# | GENRB_ALIAS_SOURCE = az_AZ.txt zh_CN.txt ...
#
#
# Generated by LDML2ICUConverter, from LDML source files.

View file

@ -70,7 +70,7 @@ root{
297,
210,
}
Version{"1.121"}
Version{"1.123"}
calendar{
buddhist{
AmPmMarkers{
@ -5075,7 +5075,7 @@ root{
"1994-04-30 21:00",
}
mz3{
"Moscow",
"Europe_Eastern",
"1997-03-30 01:00",
"9999-12-31 23:59",
}

View file

@ -2048,7 +2048,7 @@ sv{
SCOUSE{"scouse"}
VALENCIA{"valensisk dialekt"}
}
Version{"1.108"}
Version{"1.109"}
calendar{
gregorian{
AmPmMarkers{
@ -2497,29 +2497,25 @@ sv{
lg{"västbrasiliansk tid"}
}
"meta:Africa_Central"{
lg{"centralafrikansk tid"}
ls{"centralafrikansk tid"}
sg{"CAT"}
ss{"CAT"}
}
"meta:Africa_Eastern"{
lg{"östafrikansk tid"}
ls{"östafrikansk normaltid"}
sg{"EAT"}
ss{"EAT"}
}
"meta:Africa_Southern"{
lg{"sydafrikansk tid"}
ls{"sydafrikansk normaltid"}
sd{"sydafrikansk sommartid"}
ss{"SAT"}
sg{"SAT"}
ss{"SAST"}
}
"meta:Africa_Western"{
ld{"västafrikansk sommartid"}
lg{"västafrikansk tid"}
ls{"västafrikansk normaltid"}
sd{"VAST"}
sg{"WAT"}
ss{"WAT"}
}
"meta:Alaska"{
@ -2568,8 +2564,8 @@ sv{
ld{"saudiarabisk sommartid"}
lg{"saudiarabisk tid"}
ls{"saudiarabisk normaltid"}
sg{"AT"}
ss{"AST"}
sg{"AT (saudiarabisk)"}
ss{"AST (saudiarabisk)"}
}
"meta:Argentina"{
lg{"östargentinsk tid"}
@ -2660,7 +2656,6 @@ sv{
lg{"centraleuropeisk tid"}
ls{"Centraleuropa, normaltid"}
sd{"CEST"}
sg{"CET"}
ss{"CET"}
}
"meta:Europe_Eastern"{
@ -2669,7 +2664,6 @@ sv{
lg{"östeuropeisk tid"}
ls{"Östeuropa, normaltid"}
sd{"EEST"}
sg{"EET"}
ss{"EET"}
}
"meta:Europe_Western"{
@ -2678,16 +2672,11 @@ sv{
lg{"västeuropeisk tid"}
ls{"västeuropeisk normaltid"}
sd{"WEST"}
sg{"WET"}
ss{"WET"}
}
"meta:GMT"{
cu:int{1}
ld{"greenwichtid"}
lg{"greenwichtid"}
ls{"Greenwichtid"}
sd{"GMT"}
sg{"GMT"}
ss{"GMT"}
}
"meta:Galapagos"{
@ -2714,13 +2703,6 @@ sv{
"meta:Guam"{
lg{"Guamtid"}
}
"meta:Hawaii"{
ld{"Hawaii, sommartid"}
lg{"hawaiiansk tid"}
ls{"Hawaii, normaltid"}
sd{"HDT"}
ss{"HST"}
}
"meta:India"{
lg{"indisk tid"}
}
@ -2741,7 +2723,7 @@ sv{
lg{"israelisk tid"}
ls{"Israel, normaltid"}
sd{"IDT"}
ss{"IST"}
ss{"IST (Israel)"}
}
"meta:Japan"{
ld{"Japan, sommartid"}
@ -2776,8 +2758,8 @@ sv{
ld{"Newfoundland, sommartid"}
lg{"New Foundland-tid"}
ls{"Newfoundland, normaltid"}
sd{"CDT"}
ss{"CNT"}
sd{"NDT"}
ss{"NST"}
}
"meta:Pakistan"{
lg{"pakistansk tid"}

View file

@ -1964,7 +1964,7 @@ th{
ROZAJ{"เรเซียน"}
SAAHO{"ซาโฮ"}
}
Version{"1.94"}
Version{"1.95"}
calendar{
buddhist{
DateTimePatterns{

View file

@ -2041,7 +2041,7 @@ tr{
SAAHO{"Saho"}
SCOUSE{"Scouse"}
}
Version{"1.91"}
Version{"1.92"}
calendar{
coptic{
monthNames{
@ -2435,8 +2435,8 @@ tr{
"meta:Acre"{
ld{"Acre Yaz Saati"}
ls{"Acre Saati"}
sd{"ACST"}
ss{"ACT"}
sd{"ACST (Acre)"}
ss{"ACT (Acre)"}
}
"meta:Afghanistan"{
ls{"Afganistan Saati"}
@ -2842,21 +2842,9 @@ tr{
ls{"Guyana Saati"}
ss{"GYT"}
}
"meta:Hawaii"{
ld{"Hawaii Yaz Saati"}
lg{"Hawaii Saati"}
ls{"Hawaii Standart Saati"}
sd{"HDT"}
sg{"HT"}
ss{"HST"}
}
"meta:Hawaii_Aleutian"{
ld{"Hawaii-Aleutian Yaz Saati"}
lg{"Hawaii-Aleutian Saati"}
ls{"Hawaii-Aleutian Standart Saati"}
sd{"HADT"}
sg{"HAT"}
ss{"HAST"}
ss{"HST"}
}
"meta:Hong_Kong"{
ld{"Hong Kong Yaz Saati"}
@ -3207,7 +3195,7 @@ tr{
}
"meta:South_Georgia"{
ls{"Güney Georgia Saati"}
ss{"GST (S. Georgia)"}
ss{"GST (Güney Georgia)"}
}
"meta:Suriname"{
ls{"Surinam Saati"}

View file

@ -2026,7 +2026,7 @@ zh{
REVISED{"已修订的拼字学"}
SAAHO{"萨霍"}
}
Version{"1.104"}
Version{"1.105"}
calendar{
gregorian{
AmPmMarkers{
@ -3278,17 +3278,14 @@ zh{
ls{"Acre 标准时间"}
}
"meta:Africa_Central"{
ld{"非洲中部夏令时间"}
lg{"非洲中部时间"}
ls{"中部非洲标准时间"}
}
"meta:Africa_Eastern"{
ld{"非洲东部夏令时间"}
lg{"非洲东部时间"}
ls{"东部非洲标准时间"}
}
"meta:Africa_Southern"{
ld{"非洲南部夏令时间"}
lg{"非洲南部时间"}
ls{"南部非洲标准时间"}
}
@ -3375,17 +3372,11 @@ zh{
ls{"格林尼治标准时间"}
ss{"GMT"}
}
"meta:Hawaii"{
ld{"夏威夷夏令时间"}
ls{"夏威夷标准时间"}
sd{"HDT"}
ss{"HST"}
}
"meta:Israel"{
ld{"以色列夏令时间"}
ls{"以色列标准时间"}
sd{"IDT"}
ss{"IST"}
ss{"IST (Israel)"}
}
"meta:Japan"{
ld{"日本夏令时间"}

View file

@ -1662,7 +1662,7 @@ zh_Hant{
REVISED{"已修訂"}
SAAHO{"SAAHO"}
}
Version{"1.89"}
Version{"1.90"}
calendar{
gregorian{
DateTimePatterns{
@ -2511,9 +2511,6 @@ zh_Hant{
"meta:GMT"{
ls{"格林威治標準時間"}
}
"meta:Hawaii"{
ls{"夏威夷標準時間"}
}
"meta:Israel"{
ls{"以色列標準時間"}
}

File diff suppressed because it is too large Load diff

View file

@ -23,4 +23,4 @@
#
MISC_SOURCE = \
zoneinfo.txt supplementalData.txt
zoneinfo.txt supplementalData.txt metazoneInfo.txt

View file

@ -516,6 +516,26 @@ supplementalData:table(nofallback){
}
}
}
BL{
{
id{"EUR"}
from:intvector{ /** 1999-01-01 */
213,
320825952,
}
}
{
id{"FRF"}
from:intvector{ /** 1960-01-01 */
-74,
-2086527392,
}
to:intvector{ /** 2002-02-17 */
235,
1908405440,
}
}
}
BM{
{
id{"BMD"}
@ -654,6 +674,19 @@ supplementalData:table(nofallback){
}
}
}
BU{
{
id{"BUK"}
from:intvector{ /** 1952-07-01 */
-133,
-1143896928,
}
to:intvector{ /** 1989-06-18 */
139,
-210261440,
}
}
}
BV{
{
id{"NOK"}
@ -875,10 +908,10 @@ supplementalData:table(nofallback){
}
CS{
{
id{"EUR"}
from:intvector{ /** 2003-02-04 */
242,
-2038532928,
id{"CSD"}
from:intvector{ /** 2002-05-15 */
235,
1735785440,
}
to:intvector{ /** 2006-06-03 */
264,
@ -886,10 +919,10 @@ supplementalData:table(nofallback){
}
}
{
id{"CSD"}
from:intvector{ /** 2002-05-15 */
235,
1735785440,
id{"EUR"}
from:intvector{ /** 2003-02-04 */
242,
-2038532928,
}
to:intvector{ /** 2006-06-03 */
264,
@ -997,6 +1030,19 @@ supplementalData:table(nofallback){
}
}
}
DD{
{
id{"DDM"}
from:intvector{ /** 1948-07-20 */
-162,
-1178645344,
}
to:intvector{ /** 1990-10-02 */
146,
-121192512,
}
}
}
DE{
{
id{"EUR"}
@ -1424,9 +1470,9 @@ supplementalData:table(nofallback){
GP{
{
id{"EUR"}
from:intvector{ /** 1999 */
from:intvector{ /** 1999-01-01 */
213,
320765952,
320825952,
}
}
{
@ -2210,6 +2256,26 @@ supplementalData:table(nofallback){
}
}
}
MF{
{
id{"EUR"}
from:intvector{ /** 1999-01-01 */
213,
320825952,
}
}
{
id{"FRF"}
from:intvector{ /** 1960-01-01 */
-74,
-2086527392,
}
to:intvector{ /** 2002-02-17 */
235,
1908405440,
}
}
}
MG{
{
id{"MGA"}
@ -2920,6 +2986,15 @@ supplementalData:table(nofallback){
}
}
}
QU{
{
id{"EUR"}
from:intvector{ /** 1999-01-01 */
213,
320825952,
}
}
}
RE{
{
id{"EUR"}
@ -3296,6 +3371,19 @@ supplementalData:table(nofallback){
}
}
}
SU{
{
id{"SUR"}
from:intvector{ /** 1961-01-01 */
-67,
-528898464,
}
to:intvector{ /** 1991-12-25 */
154,
-957610880,
}
}
}
SV{
{
id{"SVC"}
@ -3495,6 +3583,30 @@ supplementalData:table(nofallback){
}
}
}
TP{
{
id{"TPE"}
from:intvector{ /** 1959-01-02 */
-81,
823610976,
}
to:intvector{ /** 2002-05-20 */
235,
-2127181856,
}
}
{
id{"IDR"}
from:intvector{ /** 1975-12-07 */
36,
-628269952,
}
to:intvector{ /** 2002-05-20 */
235,
-2127181856,
}
}
}
TR{
{
id{"TRY"}
@ -3814,6 +3926,41 @@ supplementalData:table(nofallback){
}
}
}
YU{
{
id{"YUM"}
from:intvector{ /** 1994-01-24 */
176,
-839551392,
}
to:intvector{ /** 2002-05-15 */
235,
1735785440,
}
}
{
id{"YUN"}
from:intvector{ /** 1990-01-01 */
146,
-208132512,
}
to:intvector{ /** 1992-07-24 */
162,
426918048,
}
}
{
id{"YUD"}
from:intvector{ /** 1966-01-01 */
-30,
-1676288416,
}
to:intvector{ /** 1990-01-01 */
146,
-208132512,
}
}
}
ZA{
{
id{"ZAR"}
@ -3832,6 +3979,30 @@ supplementalData:table(nofallback){
}
}
}
ZR{
{
id{"ZRN"}
from:intvector{ /** 1993-11-01 */
168,
-2413024,
}
to:intvector{ /** 1998-07 */
205,
-1150042976,
}
}
{
id{"ZRZ"}
from:intvector{ /** 1971-10-27 */
7,
-576738368,
}
to:intvector{ /** 1993-11-01 */
168,
-2413024,
}
}
}
ZW{
{
id{"ZWD"}
@ -4258,13 +4429,6 @@ supplementalData:table(nofallback){
}
}
}
auv{
secondary{
territories{
"FR",
}
}
}
av{
primary{
scripts{
@ -5361,6 +5525,7 @@ supplementalData:table(nofallback){
"BF",
"BI",
"BJ",
"BL",
"CA",
"CD",
"CF",
@ -5381,6 +5546,7 @@ supplementalData:table(nofallback){
"LU",
"MA",
"MC",
"MF",
"MG",
"ML",
"MQ",
@ -6136,6 +6302,13 @@ supplementalData:table(nofallback){
}
}
}
kg{
secondary{
territories{
"CD",
}
}
}
kha{
primary{
scripts{
@ -6312,13 +6485,6 @@ supplementalData:table(nofallback){
}
}
}
kon{
secondary{
territories{
"CD",
}
}
}
kos{
primary{
scripts{
@ -7307,6 +7473,11 @@ supplementalData:table(nofallback){
"Latn",
}
}
secondary{
territories{
"FR",
}
}
}
om{
primary{
@ -9097,7 +9268,6 @@ supplementalData:table(nofallback){
"meta:Europe_Western_EH"{"Africa/El_Aaiun"}
"meta:Europe_Western_FO"{"Atlantic/Faeroe"}
"meta:Europe_Western_MA"{"Africa/Casablanca"}
"meta:Europe_Western_PT"{"Europe/Lisbon"}
"meta:Falkland_001"{"Atlantic/Stanley"}
"meta:Fiji_001"{"Pacific/Fiji"}
"meta:French_Guiana_001"{"America/Cayenne"}
@ -9257,7 +9427,7 @@ supplementalData:table(nofallback){
"America:Buenos_Aires"{"SA Eastern"}
"America:Caracas"{"SA Western"}
"America:Chicago"{"Central"}
"America:Chihuahua"{"Mountain Standard Time (Mexico)"}
"America:Chihuahua"{"Mexico Standard Time 2"}
"America:Denver"{"Mountain"}
"America:Godthab"{"Greenland"}
"America:Guatemala"{"Central America"}
@ -9265,7 +9435,7 @@ supplementalData:table(nofallback){
"America:Indianapolis"{"US Eastern"}
"America:Los_Angeles"{"Pacific"}
"America:Manaus"{"Central Brazilian"}
"America:Mexico_City"{"Central Standard Time (Mexico)"}
"America:Mexico_City"{"Mexico"}
"America:Montevideo"{"Montevideo"}
"America:New_York"{"Eastern"}
"America:Noronha"{"Mid-Atlantic"}
@ -9473,6 +9643,7 @@ supplementalData:table(nofallback){
"AN",
"AW",
"BB",
"BL",
"BS",
"CU",
"DM",
@ -9484,6 +9655,7 @@ supplementalData:table(nofallback){
"KN",
"KY",
"LC",
"MF",
"MQ",
"MS",
"PR",
@ -10466,9 +10638,6 @@ supplementalData:table(nofallback){
}
"Antarctica:McMurdo"{
territory{"AQ"}
aliases{
"Antarctica/South_Pole",
}
}
"Antarctica:Palmer"{
territory{"AQ"}
@ -10476,6 +10645,9 @@ supplementalData:table(nofallback){
"Antarctica:Rothera"{
territory{"AQ"}
}
"Antarctica:South_Pole"{
territory{"AQ"}
}
"Antarctica:Syowa"{
territory{"AQ"}
}

View file

@ -78,7 +78,7 @@ name2uni.o uni2name.o nortrans.o quant.o transreg.o \
regexcmp.o rematch.o repattrn.o regexst.o udatpg.o uregex.o uregexc.o \
ulocdata.o measfmt.o currfmt.o curramt.o currunit.o measure.o utmscale.o \
csdetect.o csmatch.o csr2022.o csrecog.o csrmbcs.o csrsbcs.o csrucode.o csrutf8.o inputext.o \
windtfmt.o winnmfmt.o basictz.o dtrule.o rbtz.o tzrule.o tztrans.o vtzone.o
windtfmt.o winnmfmt.o basictz.o dtrule.o rbtz.o tzrule.o tztrans.o vtzone.o zonemeta.o zstrfmt.o
## Header files to install
HEADERS = $(srcdir)/unicode/*.h

View file

@ -512,6 +512,15 @@ error:
transitionRules = NULL;
}
void
BasicTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/ {
if (U_FAILURE(status)) {
return;
}
status = U_UNSUPPORTED_ERROR;
}
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -1094,7 +1094,7 @@ void Calendar::computeFields(UErrorCode &ec)
double localMillis = internalGetTime();
int32_t rawOffset, dstOffset;
getTimeZone().getOffset(localMillis, FALSE, rawOffset, dstOffset, ec);
localMillis += rawOffset;
localMillis += (rawOffset + dstOffset);
// Mark fields as set. Do this before calling handleComputeFields().
uint32_t mask = //fInternalSetMask;
@ -1134,33 +1134,8 @@ void Calendar::computeFields(UErrorCode &ec)
//__FILE__, __LINE__, fFields[UCAL_JULIAN_DAY], localMillis);
#endif
// In some cases we will have to call this method again below to
// adjust for DST pushing us into the next Julian day.
computeGregorianAndDOWFields(fFields[UCAL_JULIAN_DAY], ec);
int32_t millisInDay = (int32_t) (localMillis - (days * kOneDay));
if (millisInDay < 0) millisInDay += (int32_t)kOneDay;
// Adjust our millisInDay for DST. dstOffset will be zero if DST
// is not in effect at this time of year, or if our zone does not
// use DST.
millisInDay += dstOffset;
// If DST has pushed us into the next day, we must call
// computeGregorianAndDOWFields() again. This happens in DST between
// 12:00 am and 1:00 am every day. The first call to
// computeGregorianAndDOWFields() will give the wrong day, since the
// Standard time is in the previous day.
if (millisInDay >= (int32_t)kOneDay) {
millisInDay -= (int32_t)kOneDay; // ASSUME dstOffset < 24:00
// We don't worry about overflow of JULIAN_DAY because the
// allowable range of JULIAN_DAY has slop at the ends (that is,
// the max is less that 0x7FFFFFFF and the min is greater than
// -0x80000000).
computeGregorianAndDOWFields(++fFields[UCAL_JULIAN_DAY], ec);
}
// Call framework method to have subclass compute its fields.
// These must include, at a minimum, MONTH, DAY_OF_MONTH,
// EXTENDED_YEAR, YEAR, DAY_OF_YEAR. This method will call internalSet(),
@ -1174,6 +1149,7 @@ void Calendar::computeFields(UErrorCode &ec)
// Compute time-related fields. These are indepent of the date and
// of the subclass algorithm. They depend only on the local zone
// wall milliseconds in day.
int32_t millisInDay = (int32_t) (localMillis - (days * kOneDay));
fFields[UCAL_MILLISECONDS_IN_DAY] = millisInDay;
fFields[UCAL_MILLISECOND] = millisInDay % 1000;
millisInDay /= 1000;
@ -2348,11 +2324,11 @@ void Calendar::computeTime(UErrorCode& status) {
// 1. The transition into DST. Here, a designated time of 2:00 am - 2:59 am
// can be in standard or in DST depending. However, 2:00 am is an invalid
// representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
// We assume standard time.
// We assume standard time, that is, 2:30 am is interpreted as 3:30 am DST.
// 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
// can be in standard or DST. Both are valid representations (the rep
// jumps from 1:59:59 DST to 1:00:00 Std).
// Again, we assume standard time.
// Again, we assume standard time, that is, 1:30 am is interpreted as 1:30 am Std.
// We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
// or DST_OFFSET fields; then we use those fields.
if (fStamp[UCAL_ZONE_OFFSET] >= ((int32_t)kMinimumUserStamp) ||

View file

@ -170,24 +170,32 @@ UDate
DateFormat::parse(const UnicodeString& text,
ParsePosition& pos) const
{
UDate d = 0; // Error return UDate is 0 (the epoch)
if (fCalendar != NULL) {
int32_t start = pos.getIndex();
// Parse may update TimeZone used by the calendar.
TimeZone *tzsav = (TimeZone*)fCalendar->getTimeZone().clone();
fCalendar->clear();
parse(text, *fCalendar, pos);
if (pos.getIndex() != start) {
UErrorCode ec = U_ZERO_ERROR;
UDate d = fCalendar->getTime(ec);
if (U_SUCCESS(ec)) {
return d; // Successful function exit
d = fCalendar->getTime(ec);
if (U_FAILURE(ec)) {
// We arrive here if fCalendar is non-lenient and there
// is an out-of-range field. We don't know which field
// was illegal so we set the error index to the start.
pos.setIndex(start);
pos.setErrorIndex(start);
d = 0;
}
// We arrive here if fCalendar is non-lenient and there
// is an out-of-range field. We don't know which field
// was illegal so we set the error index to the start.
pos.setIndex(start);
pos.setErrorIndex(start);
}
// Restore TimeZone
fCalendar->adoptTimeZone(tzsav);
}
return 0; // Error return UDate is 0 (the epoch)
return d;
}
//----------------------------------------------------------------------

File diff suppressed because it is too large Load diff

View file

@ -1646,6 +1646,22 @@
RelativePath=".\winnmfmt.h"
>
</File>
<File
RelativePath=".\zonemeta.cpp"
>
</File>
<File
RelativePath=".\zonemeta.h"
>
</File>
<File
RelativePath=".\zstrfmt.cpp"
>
</File>
<File
RelativePath=".\zstrfmt.h"
>
</File>
</Filter>
<Filter
Name="misc"

View file

@ -317,11 +317,11 @@ int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month,
millis, monthLength, ec);
}
// Compute local epoch seconds from input fields
double time = Grego::fieldsToDay(year, month, dom) * SECONDS_PER_DAY +
uprv_floor(millis / (double) U_MILLIS_PER_SECOND);
return zoneOffset(findTransition(time, TRUE)) * U_MILLIS_PER_SECOND;
// Compute local epoch millis from input fields
UDate date = (UDate)(Grego::fieldsToDay(year, month, dom) * U_MILLIS_PER_DAY + millis);
int32_t rawoff, dstoff;
getHistoricalOffset(date, TRUE, kDaylight, kStandard, rawoff, dstoff);
return rawoff + dstoff;
}
/**
@ -332,40 +332,30 @@ void OlsonTimeZone::getOffset(UDate date, UBool local, int32_t& rawoff,
if (U_FAILURE(ec)) {
return;
}
// The check against finalMillis will suffice most of the time, except
// for the case in which finalMillis == DBL_MAX, date == DBL_MAX,
// and finalZone == 0. For this case we add "&& finalZone != 0".
if (date >= finalMillis && finalZone != 0) {
int32_t year, month, dom, dow;
double millis;
double days = Math::floorDivide(date, (double)U_MILLIS_PER_DAY, millis);
Grego::dayToFields(days, year, month, dom, dow);
finalZone->getOffset(date, local, rawoff, dstoff, ec);
} else {
getHistoricalOffset(date, local, kFormer, kLatter, rawoff, dstoff);
}
}
rawoff = finalZone->getRawOffset();
if (!local) {
// Adjust from GMT to local
date += rawoff;
double days2 = Math::floorDivide(date, (double)U_MILLIS_PER_DAY, millis);
if (days2 != days) {
Grego::dayToFields(days2, year, month, dom, dow);
}
}
dstoff = finalZone->getOffset(
GregorianCalendar::AD, year, month,
dom, (uint8_t) dow, (int32_t) millis, ec) - rawoff;
void
OlsonTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) /*const*/ {
if (U_FAILURE(ec)) {
return;
}
double secs = uprv_floor(date / U_MILLIS_PER_SECOND);
int16_t i = findTransition(secs, local);
rawoff = rawOffset(i) * U_MILLIS_PER_SECOND;
dstoff = dstOffset(i) * U_MILLIS_PER_SECOND;
if (date >= finalMillis && finalZone != 0) {
finalZone->getOffsetFromLocal(date, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff, ec);
} else {
getHistoricalOffset(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff);
}
}
/**
* TimeZone API.
*/
@ -394,69 +384,84 @@ void printTime(double ms) {
double days = Math::floorDivide(((double)ms), (double)U_MILLIS_PER_DAY, millis);
Grego::dayToFields(days, year, month, dom, dow);
U_DEBUG_TZ_MSG((" findTransition: time %.1f (%04d.%02d.%02d+%.1fh)\n", ms,
U_DEBUG_TZ_MSG((" getHistoricalOffset: time %.1f (%04d.%02d.%02d+%.1fh)\n", ms,
year, month+1, dom, (millis/kOneHour)));
}
#endif
/**
* Find the smallest i (in 0..transitionCount-1) such that time >=
* transition(i), where transition(i) is either the GMT or the local
* transition time, as specified by `local'.
* @param time epoch seconds, either GMT or local wall
* @param local if TRUE, `time' is in local wall units, otherwise it
* is GMT
* @return an index i, where 0 <= i < transitionCount, and
* transition(i) <= time < transition(i+1), or i == 0 if
* transitionCount == 0 or time < transition(0).
*/
int16_t OlsonTimeZone::findTransition(double time, UBool local) const {
int16_t i = 0;
U_DEBUG_TZ_MSG(("findTransition(%.1f, %s)\n", time, local?"T":"F"));
void
OlsonTimeZone::getHistoricalOffset(UDate date, UBool local,
int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
int32_t& rawoff, int32_t& dstoff) const {
U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst)\n",
date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt));
#if defined U_DEBUG_TZ
printTime(time*1000.0);
printTime(date*1000.0);
#endif
if (transitionCount != 0) {
double sec = uprv_floor(date / U_MILLIS_PER_SECOND);
// Linear search from the end is the fastest approach, since
// most lookups will happen at/near the end.
int16_t i;
for (i = transitionCount - 1; i > 0; --i) {
int32_t transition = transitionTimes[i];
if (local) {
int32_t zoneOffsetPrev = zoneOffset(typeData[i-1]);
int32_t zoneOffsetCurr = zoneOffset(typeData[i]);
// use the lowest offset ( == standard time ). as per tzregts.cpp which says:
/**
* @bug 4084933
* The expected behavior of TimeZone around the boundaries is:
* (Assume transition time of 2:00 AM)
* day of onset 1:59 AM STD = display name 1:59 AM ST
* 2:00 AM STD = display name 3:00 AM DT
* day of end 0:59 AM STD = display name 1:59 AM DT
* 1:00 AM STD = display name 1:00 AM ST
*/
if(zoneOffsetPrev<zoneOffsetCurr) {
transition += zoneOffsetPrev;
if (local) {
int32_t offsetBefore = zoneOffset(typeData[i-1]);
UBool dstBefore = dstOffset(typeData[i-1]) != 0;
int32_t offsetAfter = zoneOffset(typeData[i]);
UBool dstAfter = dstOffset(typeData[i]) != 0;
UBool dstToStd = dstBefore && !dstAfter;
UBool stdToDst = !dstBefore && dstAfter;
if (offsetAfter - offsetBefore >= 0) {
// Positive transition, which makes a non-existing local time range
if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
|| ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
transition += offsetBefore;
} else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
|| ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
transition += offsetAfter;
} else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
transition += offsetBefore;
} else {
// Interprets the time with rule before the transition,
// default for non-existing time range
transition += offsetAfter;
}
} else {
transition += zoneOffsetCurr;
// Negative transition, which makes a duplicated local time range
if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
|| ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
transition += offsetAfter;
} else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
|| ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
transition += offsetBefore;
} else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
transition += offsetBefore;
} else {
// Interprets the time with rule after the transition,
// default for duplicated local time range
transition += offsetAfter;
}
}
}
if (time >= transition) {
U_DEBUG_TZ_MSG(("Found@%d: time=%.1f, localtransition=%d (orig %d) dz %d\n", i, time, transition, transitionTimes[i],
if (sec >= transition) {
U_DEBUG_TZ_MSG(("Found@%d: time=%.1f, localtransition=%d (orig %d) dz %d\n", i, sec, transition, transitionTimes[i],
zoneOffset(typeData[i-1])));
#if defined U_DEBUG_TZ
printTime(transition*1000.0);
printTime(transitionTimes[i]*1000.0);
printTime(transition*1000.0);
printTime(transitionTimes[i]*1000.0);
#endif
break;
} else {
U_DEBUG_TZ_MSG(("miss@%d: time=%.1f, localtransition=%d (orig %d) dz %d\n", i, time, transition, transitionTimes[i],
U_DEBUG_TZ_MSG(("miss@%d: time=%.1f, localtransition=%d (orig %d) dz %d\n", i, sec, transition, transitionTimes[i],
zoneOffset(typeData[i-1])));
#if defined U_DEBUG_TZ
printTime(transition*1000.0);
printTime(transitionTimes[i]*1000.0);
printTime(transition*1000.0);
printTime(transitionTimes[i]*1000.0);
#endif
}
}
@ -465,17 +470,25 @@ int16_t OlsonTimeZone::findTransition(double time, UBool local) const {
// Check invariants for GMT times; if these pass for GMT times
// the local logic should be working too.
U_ASSERT(local || time < transitionTimes[0] || time >= transitionTimes[i]);
U_ASSERT(local || i == transitionCount-1 || time < transitionTimes[i+1]);
U_ASSERT(local || sec < transitionTimes[0] || sec >= transitionTimes[i]);
U_ASSERT(local || i == transitionCount-1 || sec < transitionTimes[i+1]);
U_DEBUG_TZ_MSG(("findTransition(%.1f, %s)= trans %d\n", time, local?"T":"F", i));
i = typeData[i];
U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst) - trans %d\n",
date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt, i));
// Since ICU tzdata 2007c, the first transition data is actually not a
// transition, but used for representing the initial offset. So the code
// below works even if i == 0.
int16_t index = typeData[i];
rawoff = rawOffset(index) * U_MILLIS_PER_SECOND;
dstoff = dstOffset(index) * U_MILLIS_PER_SECOND;
} else {
// No transitions, single pair of offsets only
rawoff = rawOffset(0) * U_MILLIS_PER_SECOND;
dstoff = dstOffset(0) * U_MILLIS_PER_SECOND;
}
U_ASSERT(i>=0 && i<typeCount);
U_DEBUG_TZ_MSG(("findTransition(%.1f, %s)=%d, offset %d\n", time, local?"T":"F", i, zoneOffset(i)));
return i;
U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst) - raw=%d, dst=%d\n",
date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt, rawoff, dstoff));
}
/**

View file

@ -181,6 +181,12 @@ class OlsonTimeZone: public BasicTimeZone {
virtual void getOffset(UDate date, UBool local, int32_t& rawOffset,
int32_t& dstOffset, UErrorCode& ec) const;
/**
* BasicTimeZone API.
*/
virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
int32_t& rawoff, int32_t& dstoff, UErrorCode& ec) /*const*/;
/**
* TimeZone API. This method has no effect since objects of this
* class are quasi-immutable (the base class allows the ID to be
@ -279,7 +285,9 @@ private:
void constructEmpty();
int16_t findTransition(double time, UBool local) const;
void getHistoricalOffset(UDate date, UBool local,
int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
int32_t& rawoff, int32_t& dstoff) const;
int32_t zoneOffset(int16_t index) const;
int32_t rawOffset(int16_t index) const;

View file

@ -46,14 +46,6 @@ static UBool compareRules(UVector* rules1, UVector* rules2) {
return TRUE;
}
static UDate getTransitionTime(Transition* transition, UBool local) {
UDate time = transition->time;
if (local) {
time += transition->from->getRawOffset() + transition->from->getDSTSavings();
}
return time;
}
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedTimeZone)
RuleBasedTimeZone::RuleBasedTimeZone(const UnicodeString& id, InitialTimeZoneRule* initialRule)
@ -183,7 +175,7 @@ RuleBasedTimeZone::complete(UErrorCode& status) {
for (i = 0; i < historicCount; i++) {
done[i] = FALSE;
}
while (true) {
while (TRUE) {
int32_t curStdOffset = curRule->getRawOffset();
int32_t curDstSavings = curRule->getDSTSavings();
UDate nextTransitionTime = MAX_MILLIS;
@ -377,7 +369,7 @@ RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t d
}
int32_t rawOffset, dstOffset;
UDate time = (UDate)Grego::fieldsToDay(year, month, day) * U_MILLIS_PER_DAY + millis;
getOffset(time, true, rawOffset, dstOffset, status);
getOffsetInternal(time, TRUE, kDaylight, kStandard, rawOffset, dstOffset, status);
if (U_FAILURE(status)) {
return 0;
}
@ -387,6 +379,24 @@ RuleBasedTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t d
void
RuleBasedTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
int32_t& dstOffset, UErrorCode& status) const {
getOffsetInternal(date, local, kFormer, kLatter, rawOffset, dstOffset, status);
}
void
RuleBasedTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/ {
getOffsetInternal(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawOffset, dstOffset, status);
}
/*
* The internal getOffset implementation
*/
void
RuleBasedTimeZone::getOffsetInternal(UDate date, UBool local,
int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
int32_t& rawOffset, int32_t& dstOffset,
UErrorCode& status) const {
rawOffset = 0;
dstOffset = 0;
@ -404,15 +414,17 @@ RuleBasedTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
if (fHistoricTransitions == NULL) {
rule = fInitialRule;
} else {
UDate tstart = getTransitionTime((Transition*)fHistoricTransitions->elementAt(0), local);
UDate tstart = getTransitionTime((Transition*)fHistoricTransitions->elementAt(0),
local, NonExistingTimeOpt, DuplicatedTimeOpt);
if (date < tstart) {
rule = fInitialRule;
} else {
int32_t idx = fHistoricTransitions->size() - 1;
UDate tend = getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx), local);
UDate tend = getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx),
local, NonExistingTimeOpt, DuplicatedTimeOpt);
if (date > tend) {
if (fFinalRules != NULL) {
rule = findRuleInFinal(date, local);
rule = findRuleInFinal(date, local, NonExistingTimeOpt, DuplicatedTimeOpt);
} else {
// no final rule, use the last rule
rule = ((Transition*)fHistoricTransitions->elementAt(idx))->to;
@ -420,7 +432,8 @@ RuleBasedTimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
} else {
// Find a historical transition
while (idx >= 0) {
if (date >= getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx), local)) {
if (date >= getTransitionTime((Transition*)fHistoricTransitions->elementAt(idx),
local, NonExistingTimeOpt, DuplicatedTimeOpt)) {
break;
}
idx--;
@ -651,7 +664,8 @@ RuleBasedTimeZone::copyRules(UVector* source) {
}
TimeZoneRule*
RuleBasedTimeZone::findRuleInFinal(UDate date, UBool local) const {
RuleBasedTimeZone::findRuleInFinal(UDate date, UBool local,
int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
if (fFinalRules == NULL) {
return NULL;
}
@ -664,12 +678,25 @@ RuleBasedTimeZone::findRuleInFinal(UDate date, UBool local) const {
UDate start0, start1;
UDate base;
int32_t localDelta;
base = local ? date - fr1->getRawOffset() - fr1->getDSTSavings() : date;
UBool avail0 = fr0->getPreviousStart(base, fr1->getRawOffset(), fr1->getDSTSavings(), true, start0);
base = date;
if (local) {
localDelta = getLocalDelta(fr1->getRawOffset(), fr1->getDSTSavings(),
fr0->getRawOffset(), fr0->getDSTSavings(),
NonExistingTimeOpt, DuplicatedTimeOpt);
base -= localDelta;
}
UBool avail0 = fr0->getPreviousStart(base, fr1->getRawOffset(), fr1->getDSTSavings(), TRUE, start0);
base = local ? date - fr0->getRawOffset() - fr0->getDSTSavings() : date;
UBool avail1 = fr1->getPreviousStart(base, fr0->getRawOffset(), fr0->getDSTSavings(), true, start1);
base = date;
if (local) {
localDelta = getLocalDelta(fr0->getRawOffset(), fr0->getDSTSavings(),
fr1->getRawOffset(), fr1->getDSTSavings(),
NonExistingTimeOpt, DuplicatedTimeOpt);
base -= localDelta;
}
UBool avail1 = fr1->getPreviousStart(base, fr0->getRawOffset(), fr0->getDSTSavings(), TRUE, start1);
if (avail0 && (!avail1 || start0 > start1)) {
return fr0;
@ -689,14 +716,14 @@ RuleBasedTimeZone::findNext(UDate base, UBool inclusive, UDate& transitionTime,
UBool found = FALSE;
Transition result;
Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0);
UDate tt = getTransitionTime(tzt, FALSE);
UDate tt = tzt->time;
if (tt > base || (inclusive && tt == base)) {
result = *tzt;
found = TRUE;
} else {
int32_t idx = fHistoricTransitions->size() - 1;
tzt = (Transition*)fHistoricTransitions->elementAt(idx);
tt = getTransitionTime(tzt, FALSE);
tt = tzt->time;
if (inclusive && tt == base) {
result = *tzt;
found = TRUE;
@ -730,7 +757,7 @@ RuleBasedTimeZone::findNext(UDate base, UBool inclusive, UDate& transitionTime,
Transition *prev = tzt;
while (idx > 0) {
tzt = (Transition*)fHistoricTransitions->elementAt(idx);
tt = getTransitionTime(tzt, FALSE);
tt = tzt->time;
if (tt < base || (!inclusive && tt == base)) {
break;
}
@ -772,14 +799,14 @@ RuleBasedTimeZone::findPrev(UDate base, UBool inclusive, UDate& transitionTime,
UBool found = FALSE;
Transition result;
Transition *tzt = (Transition*)fHistoricTransitions->elementAt(0);
UDate tt = getTransitionTime(tzt, FALSE);
UDate tt = tzt->time;
if (inclusive && tt == base) {
result = *tzt;
found = TRUE;
} else if (tt < base) {
int32_t idx = fHistoricTransitions->size() - 1;
tzt = (Transition*)fHistoricTransitions->elementAt(idx);
tt = getTransitionTime(tzt, FALSE);
tt = tzt->time;
if (inclusive && tt == base) {
result = *tzt;
found = TRUE;
@ -813,7 +840,7 @@ RuleBasedTimeZone::findPrev(UDate base, UBool inclusive, UDate& transitionTime,
idx--;
while (idx >= 0) {
tzt = (Transition*)fHistoricTransitions->elementAt(idx);
tt = getTransitionTime(tzt, FALSE);
tt = tzt->time;
if (tt < base || (inclusive && tt == base)) {
break;
}
@ -839,6 +866,63 @@ RuleBasedTimeZone::findPrev(UDate base, UBool inclusive, UDate& transitionTime,
return FALSE;
}
UDate
RuleBasedTimeZone::getTransitionTime(Transition* transition, UBool local,
int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
UDate time = transition->time;
if (local) {
time += getLocalDelta(transition->from->getRawOffset(), transition->from->getDSTSavings(),
transition->to->getRawOffset(), transition->to->getDSTSavings(),
NonExistingTimeOpt, DuplicatedTimeOpt);
}
return time;
}
int32_t
RuleBasedTimeZone::getLocalDelta(int32_t rawBefore, int32_t dstBefore, int32_t rawAfter, int32_t dstAfter,
int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const {
int32_t delta = 0;
int32_t offsetBefore = rawBefore + dstBefore;
int32_t offsetAfter = rawAfter + dstAfter;
UBool dstToStd = (dstBefore != 0) && (dstAfter == 0);
UBool stdToDst = (dstBefore == 0) && (dstAfter != 0);
if (offsetAfter - offsetBefore >= 0) {
// Positive transition, which makes a non-existing local time range
if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
|| ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
delta = offsetBefore;
} else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
|| ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
delta = offsetAfter;
} else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
delta = offsetBefore;
} else {
// Interprets the time with rule before the transition,
// default for non-existing time range
delta = offsetAfter;
}
} else {
// Negative transition, which makes a duplicated local time range
if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
|| ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
delta = offsetAfter;
} else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
|| ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
delta = offsetBefore;
} else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
delta = offsetBefore;
} else {
// Interprets the time with rule after the transition,
// default for duplicated local time range
delta = offsetAfter;
}
}
return delta;
}
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -502,6 +502,55 @@ SimpleTimeZone::getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
return result;
}
void
SimpleTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
int32_t& rawOffsetGMT, int32_t& savingsDST, UErrorCode& status) /*const*/ {
if (U_FAILURE(status)) {
return;
}
rawOffsetGMT = getRawOffset();
int32_t year, month, dom, dow;
double day = uprv_floor(date / U_MILLIS_PER_DAY);
int32_t millis = (int32_t) (date - day * U_MILLIS_PER_DAY);
Grego::dayToFields(day, year, month, dom, dow);
savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
(uint8_t) dow, millis,
Grego::monthLength(year, month),
status) - rawOffsetGMT;
if (U_FAILURE(status)) {
return;
}
UBool recalc = FALSE;
// Now we need some adjustment
if (savingsDST > 0) {
if ((nonExistingTimeOpt & kStdDstMask) == kStandard
|| (nonExistingTimeOpt & kStdDstMask) != kDaylight && (nonExistingTimeOpt & kFormerLatterMask) != kLatter) {
date -= getDSTSavings();
recalc = TRUE;
}
} else {
if ((duplicatedTimeOpt & kStdDstMask) == kDaylight
|| (duplicatedTimeOpt & kStdDstMask) != kStandard && (duplicatedTimeOpt & kFormerLatterMask) == kFormer) {
date -= getDSTSavings();
recalc = TRUE;
}
}
if (recalc) {
day = uprv_floor(date / U_MILLIS_PER_DAY);
millis = (int32_t) (date - day * U_MILLIS_PER_DAY);
Grego::dayToFields(day, year, month, dom, dow);
savingsDST = getOffset(GregorianCalendar::AD, year, month, dom,
(uint8_t) dow, millis,
Grego::monthLength(year, month),
status) - rawOffsetGMT;
}
}
// -------------------------------------
/**
@ -966,8 +1015,8 @@ SimpleTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTrans
return FALSE;
}
UDate stdDate, dstDate;
UBool stdAvail = stdRule->getPreviousStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), false, stdDate);
UBool dstAvail = dstRule->getPreviousStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), false, dstDate);
UBool stdAvail = stdRule->getPreviousStart(base, dstRule->getRawOffset(), dstRule->getDSTSavings(), inclusive, stdDate);
UBool dstAvail = dstRule->getPreviousStart(base, stdRule->getRawOffset(), stdRule->getDSTSavings(), inclusive, dstDate);
if (stdAvail && (!dstAvail || stdDate > dstDate)) {
result.setTime(stdDate);
result.setFrom((const TimeZoneRule&)*dstRule);

File diff suppressed because it is too large Load diff

View file

@ -88,6 +88,7 @@ static char gStrBuf[256];
#define kDEFAULT "Default"
#define kMAX_CUSTOM_HOUR 23
#define kMAX_CUSTOM_MIN 59
#define kMAX_CUSTOM_SEC 59
#define MINUS 0x002D
#define PLUS 0x002B
#define ZERO_DIGIT 0x0030
@ -687,36 +688,40 @@ void TimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
}
rawOffset = getRawOffset();
// Convert to local wall millis if necessary
if (!local) {
date += rawOffset; // now in local standard millis
}
// When local==FALSE, we might have to recompute. This loop is
// executed once, unless a recomputation is required; then it is
// executed twice.
// When local == TRUE, date might not be in local standard
// millis. getOffset taking 7 parameters used here assume
// the given time in day is local standard time.
// At STD->DST transition, there is a range of time which
// does not exist. When 'date' is in this time range
// (and local == TRUE), this method interprets the specified
// local time as DST. At DST->STD transition, there is a
// range of time which occurs twice. In this case, this
// method interprets the specified local time as STD.
// To support the behavior above, we need to call getOffset
// (with 7 args) twice when local == true and DST is
// detected in the initial call.
for (int32_t pass=0; ; ++pass) {
int32_t year, month, dom, dow;
double day = uprv_floor(date / U_MILLIS_PER_DAY);
int32_t millis = (int32_t) (date - day * U_MILLIS_PER_DAY);
Grego::dayToFields(day, year, month, dom, dow);
dstOffset = getOffset(GregorianCalendar::AD, year, month, dom,
(uint8_t) dow, millis,
Grego::monthLength(year, month),
ec) - rawOffset;
// Recompute if local==FALSE, dstOffset!=0, and addition of
// the dstOffset puts us in a different day.
if (pass!=0 || local || dstOffset==0) {
break;
}
date += dstOffset;
if (uprv_floor(date / U_MILLIS_PER_DAY) == day) {
// Recompute if local==TRUE, dstOffset!=0.
if (pass!=0 || !local || dstOffset == 0) {
break;
}
// adjust to local standard millis
date -= dstOffset;
}
}
@ -1093,6 +1098,33 @@ TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) {
// ---------------------------------------
UnicodeString&
TimeZone::getOlsonCanonicalID(const UnicodeString &id, UnicodeString &canonical) {
UErrorCode ec = U_ZERO_ERROR;
canonical.remove();
UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
UResourceBundle *res = getZoneByName(top, id, NULL, ec);
if (U_SUCCESS(ec)) {
if (ures_getSize(res) == 1) {
int32_t deref = ures_getInt(res, &ec);
UResourceBundle *nres = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Names section
int32_t len;
const UChar* tmp = ures_getStringByIndex(nres, deref, &len, &ec);
if (U_SUCCESS(ec)) {
canonical.setTo(tmp, len);
}
ures_close(nres);
} else {
canonical.setTo(id);
}
}
ures_close(res);
ures_close(top);
return canonical;
}
// ---------------------------------------
UnicodeString&
TimeZone::getDisplayName(UnicodeString& result) const
@ -1192,11 +1224,12 @@ TimeZone::createCustomTimeZone(const UnicodeString& id)
UBool negative = FALSE;
int32_t hour = 0;
int32_t min = 0;
int32_t sec = 0;
if (id[pos.getIndex()] == MINUS /*'-'*/)
negative = TRUE;
else if (id[pos.getIndex()] != PLUS /*'+'*/)
return 0;
return NULL;
pos.setIndex(pos.getIndex() + 1);
UErrorCode success = U_ZERO_ERROR;
@ -1215,75 +1248,125 @@ TimeZone::createCustomTimeZone(const UnicodeString& id)
numberFormat->parse(id, n, pos);
if (pos.getIndex() == start) {
delete numberFormat;
return 0;
return NULL;
}
hour = n.getLong();
if (pos.getIndex() < id.length() &&
id[pos.getIndex()] == 0x003A /*':'*/)
{
if (pos.getIndex() < id.length()) {
if (pos.getIndex() - start > 2
|| id[pos.getIndex()] != 0x003A /*':'*/) {
delete numberFormat;
return NULL;
}
// hh:mm
pos.setIndex(pos.getIndex() + 1);
int32_t oldPos = pos.getIndex();
n.setLong(kParseFailed);
numberFormat->parse(id, n, pos);
if (pos.getIndex() == oldPos) {
if ((pos.getIndex() - oldPos) != 2) {
// must be 2 digits
delete numberFormat;
return 0;
return NULL;
}
min = n.getLong();
}
else
{
// hhmm or hh
if (pos.getIndex() < id.length()) {
if (id[pos.getIndex()] != 0x003A /*':'*/) {
delete numberFormat;
return NULL;
}
// [:ss]
pos.setIndex(pos.getIndex() + 1);
oldPos = pos.getIndex();
n.setLong(kParseFailed);
numberFormat->parse(id, n, pos);
if (pos.getIndex() != id.length()
|| (pos.getIndex() - oldPos) != 2) {
delete numberFormat;
return NULL;
}
sec = n.getLong();
}
} else {
// Supported formats are below -
//
// HHmmss
// Hmmss
// HHmm
// Hmm
// HH
// H
// Be strict about interpreting something as hh; it must be
// an offset < 23, and it must be one or two digits. Thus
// 0010 is interpreted as 00:10, but 10 is interpreted as
// 10:00.
if (hour > kMAX_CUSTOM_HOUR || (pos.getIndex() - start) > 2) {
min = hour % 100;
hour /= 100;
int32_t length = pos.getIndex() - start;
if (length <= 0 || 6 < length) {
// invalid length
delete numberFormat;
return NULL;
}
switch (length) {
case 1:
case 2:
// already set to hour
break;
case 3:
case 4:
min = hour % 100;
hour /= 100;
break;
case 5:
case 6:
sec = hour % 100;
min = (hour/100) % 100;
hour /= 10000;
break;
}
}
delete numberFormat;
if (hour > kMAX_CUSTOM_HOUR || min > kMAX_CUSTOM_MIN) {
if (hour > kMAX_CUSTOM_HOUR || min > kMAX_CUSTOM_MIN || sec > kMAX_CUSTOM_SEC) {
return 0;
}
// Create time zone ID in RFC822 format - GMT[+|-]hhmm
UnicodeString tzRFC(GMT_ID);
if (hour|min) {
// Create time zone ID - GMT[+|-]hhmm[ss]
UnicodeString tzID(GMT_ID);
if (hour | min | sec) {
if (negative) {
tzRFC += (UChar)MINUS;
tzID += (UChar)MINUS;
} else {
tzRFC += (UChar)PLUS;
tzID += (UChar)PLUS;
}
if (hour < 10) {
tzRFC += (UChar)ZERO_DIGIT;
tzID += (UChar)ZERO_DIGIT;
} else {
tzRFC += (UChar)(ZERO_DIGIT + hour/10);
tzID += (UChar)(ZERO_DIGIT + hour/10);
}
tzRFC += (UChar)(ZERO_DIGIT + hour%10);
tzID += (UChar)(ZERO_DIGIT + hour%10);
if (min < 10) {
tzRFC += (UChar)ZERO_DIGIT;
tzID += (UChar)ZERO_DIGIT;
} else {
tzRFC += (UChar)(ZERO_DIGIT + min/10);
tzID += (UChar)(ZERO_DIGIT + min/10);
}
tzID += (UChar)(ZERO_DIGIT + min%10);
if (sec) {
if (sec < 10) {
tzID += (UChar)ZERO_DIGIT;
} else {
tzID += (UChar)(ZERO_DIGIT + sec/10);
}
tzID += (UChar)(ZERO_DIGIT + sec%10);
}
tzRFC += (UChar)(ZERO_DIGIT + min%10);
}
int32_t offset = (hour * 60 + min) * 60 * 1000;
if(negative) {
int32_t offset = ((hour * 60 + min) * 60 + sec) * 1000;
if (negative) {
offset = -offset;
}
return new SimpleTimeZone(offset, tzRFC);
return new SimpleTimeZone(offset, tzID);
}
return 0;
return NULL;
}

View file

@ -40,6 +40,8 @@ typedef enum ECleanupI18NType {
UCLN_I18N_UCOL,
UCLN_I18N_UCOL_BLD,
UCLN_I18N_CSDET,
UCLN_I18N_ZONEMETA,
UCLN_I18N_ZSFORMAT,
UCLN_I18N_COUNT /* This must be last */
} ECleanupI18NType;

View file

@ -140,7 +140,36 @@ public:
virtual void getSimpleRulesNear(UDate date, InitialTimeZoneRule*& initial,
AnnualTimeZoneRule*& std, AnnualTimeZoneRule*& dst, UErrorCode& status) /*const*/;
/**
* The time type option bit flags used by getOffsetFromLocal
* @internal
*/
enum {
kStandard = 0x01,
kDaylight = 0x03,
kFormer = 0x04,
kLatter = 0x0C
};
/**
* Get time zone offsets from local wall time.
* @internal
*/
virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/;
protected:
/**
* The time type option bit masks used by getOffsetFromLocal
* @internal
*/
enum {
kStdDstMask = kDaylight,
kFormerLatterMask = kLatter
};
/**
* Default constructor.
* @draft ICU 3.8

View file

@ -37,6 +37,8 @@ U_NAMESPACE_BEGIN
/* forward declaration */
class SimpleDateFormat;
class Hashtable;
class ZoneStringFormat;
class SafeZoneStringFormatPtr;
/**
* DateFormatSymbols is a public class for encapsulating localizable date-time
@ -445,100 +447,6 @@ public:
*/
static UClassID U_EXPORT2 getStaticClassID();
/**
* The translation type of the translated zone strings
* @internal ICU 3.6
*/
enum TimeZoneTranslationType {
TIMEZONE_SHORT_GENERIC,
TIMEZONE_SHORT_STANDARD,
TIMEZONE_SHORT_DAYLIGHT,
TIMEZONE_LONG_GENERIC,
TIMEZONE_LONG_STANDARD,
TIMEZONE_LONG_DAYLIGHT,
TIMEZONE_EXEMPLAR_CITY,
TIMEZONE_COUNT
};
/**
* Creates an enumeration of time zone IDs. The object is owned by the caller and should delete it after use.
* The time zone IDs are just for programmatic lookup. NOT LOCALIZED!!!
* @param status Input/output parameter, set to success or
* failure code upon return.
* @return A new StringEnumeration object
* @internal ICU 3.6
*/
virtual StringEnumeration* createZoneStringIDs(UErrorCode &status);
/**
* Gets timezone string give the key and translation type
* @param ID The ID of zone strings, e.g: "America/Los_Angeles".
* The time zone ID is for programmatic lookup.
* @param type The translation type requested
* @param result Output parameter to recieve the translation string
* @param status Input/output parameter, set to success or
* failure code upon return.
* @return the input UnicodeString parameter for chaining
* @internal ICU 3.8
*/
UnicodeString& getZoneString(const UnicodeString &ID, const TimeZoneTranslationType type, UnicodeString &result, UErrorCode &status);
/**
* Gets metazone string given the key and translation type and calendar
* @param ID The ID of zone strings, e.g: "America/Los_Angeles".
* The time zone ID is for programmatic lookup.
* @param type The translation type requested
* @param cal The calendar
* @param result Output parameter to recieve the translation string
* @param status Input/output parameter, set to success or
* failure code upon return.
* @return the input UnicodeString parameter for chaining
* @internal ICU 3.8
*/
UnicodeString getMetazoneString(const UnicodeString &ID, const TimeZoneTranslationType type, Calendar &cal, UnicodeString &result, UErrorCode &status);
/**
* Gets fallback string given the key
* @param ID The ID of zone strings, e.g: "America/Los_Angeles".
* The time zone ID is for programmatic lookup.
* @param result Output parameter to recieve the translation string
* @param status Input/output parameter, set to success or
* failure code upon return.
* @return the input UnicodeString parameter for chaining
* @internal ICU 3.8
*/
UnicodeString& getFallbackString(const UnicodeString &ID, UnicodeString &result, UErrorCode &status);
/**
* Sets timezone string for the given the ID and translation type
* @param ID The ID of zone strings, e.g: "America/Los_Angeles".
* The time zone ID is for programmatic lookup.
* @param type The translation type to set the value for
* @param value The string with which current translation needs to be replaced
* @param status Input/output parameter, set to success or
* @internal ICU 3.6
*/
/**
* Determines if the Commonly Used flag is set for this zone
* @param zid The ID of zone strings, e.g: "America/Los_Angeles".
* The time zone ID is for programmatic lookup.
* @return A boolean value indicating if the zone is commonlyUsed or not.
* @internal ICU 3.8
*/
UBool isCommonlyUsed(const UnicodeString &zid);
/**
* Sets timezone string for the given the ID and translation type
* @param ID The ID of zone strings, e.g: "America/Los_Angeles".
* The time zone ID is for programmatic lookup.
* @param type The translation type to set the value for
* @param value The string with which current translation needs to be replaced
* @param status Input/output parameter, set to success or
* @internal ICU 3.6
*/
void setZoneString(const UnicodeString &ID, const TimeZoneTranslationType type, const UnicodeString &value, UErrorCode &status);
private:
friend class SimpleDateFormat;
@ -661,13 +569,34 @@ private:
/**
* The format data of all the timezones in this locale.
*/
UnicodeString** fZoneStrings;
UnicodeString **fZoneStrings; // Zone string array set by setZoneStrings
UnicodeString **fLocaleZoneStrings; // Zone string array created by the locale
int32_t fZoneStringsRowCount;
int32_t fZoneStringsColCount;
StringEnumeration* fZoneIDEnumeration;
Hashtable* fZoneStringsHash;
UResourceBundle* fResourceBundle;
const char* fCountry;
const ZoneStringFormat *fZoneStringFormat;
ZoneStringFormat *fZSFLocal; // Local ZoneStringFormat instance
SafeZoneStringFormatPtr *fZSFCachePtr; // Cached ZoneStringFormat
Locale fZSFLocale; // Locale used for getting ZoneStringFormat
/**
* Pattern string used for localized time zone GMT format. For example, "GMT{0}"
*/
UnicodeString fGmtFormat;
/**
* Pattern strings used for formatting zone offset in a localized time zone GMT string.
*/
UnicodeString *fGmtHourFormats;
int32_t fGmtHourFormatsCount;
enum GMTHourType {
GMT_NEGATIVE_HMS = 0,
GMT_NEGATIVE_HM,
GMT_POSITIVE_HMS,
GMT_POSITIVE_HM,
GMT_HOUR_COUNT
};
/**
* Localized date-time pattern characters. For example: use 'u' as 'y'.
@ -728,21 +657,6 @@ private:
*/
void createZoneStrings(const UnicodeString *const * otherStrings);
/**
* Package private: used by SimpleDateFormat
* Gets the index for the given time zone ID to obtain the timezone
* strings for formatting. The time zone ID is just for programmatic
* lookup. NOT LOCALIZED!!!
* @param ID the given time zone ID.
* @return the index of the given time zone ID. Returns -1 if
* the given time zone ID can't be located in the DateFormatSymbols object.
* @see java.util.SimpleTimeZone
*/
int32_t getZoneIndex(const UnicodeString& ID) const;
// Internal method; see source for documentation
int32_t _getZoneIndex(const UnicodeString& id) const;
/**
* Delete all the storage owned by this object.
*/
@ -754,67 +668,26 @@ private:
*/
void copyData(const DateFormatSymbols& other);
/**
* Returns a ZoneStringFormat, used only by SimpleDateFormat for now.
*/
const ZoneStringFormat* getZoneStringFormat(void) const;
/**
* Create a ZoneStringFormat by locale if not yet availble
*/
void initZoneStringFormat(void);
/**
* Create zone strings array by locale if not yet available
*/
void initZoneStringsArray(void);
/**
* Delete just the zone strings.
*/
void disposeZoneStrings(void);
/**
* Initializes the zoneStrings hash and keys StringEnumeration after reading the zoneStrings resource
*/
void initZoneStrings(UErrorCode &status);
/**
* initialzes the zoneStrings has and keys enumeration after reading the strings[][]. Required for backwards
* compatibility of setZoneStrings method
*/
void initZoneStrings(const UnicodeString** strings, int32_t rowCount, int32_t collumnCount, UErrorCode& status);
/**
* initialization of the fZoneStrings data member
*/
void initZoneStringsArray(UErrorCode& status);
/**
* Creates a deep clone of the Hashtable
*/
Hashtable* createZoneStringsHash(const Hashtable* otherHash);
/**
* Fetches the key from the hashtable for a given ID.
* e.g: for a given ID such as PST returns "Americal/Los_Angeles"
* Used by SimpleDateFormat class.
* @param ID The id of the time zone for which the key needs to be fetched
* @param result Output parameter to recieve the key.
* @return the input UnicodeString object for chaining
*/
UnicodeString& getZoneID(const UnicodeString& zid, UnicodeString& result, UErrorCode& status);
/**
* Fetches the zone type and zone string from the hashtable for a given key.
* e.g: for key: "Americal/Los_Angeles", text: "2004/1/1 PT 1:00" and start:9
* returns TIMEZONE_SHORT_GENERIC and "PT".
* Used by SimpleDateFormat class.
* @param ID the name of the timezone
* @param text the string containing the time zone translation
* @param start The position in string where time zone string starts
* @param type output parameter to recieve the type of time zone string
* @param value output parameter to recieve the the acutal time zone string
*/
void getZoneType(const UnicodeString& zid, const UnicodeString& text, int32_t start, TimeZoneTranslationType& type, UnicodeString& value, UErrorCode& status);
/**
* Fetches the zone type and zone string from the hashtable by cycling through all elements in the hashtable.
* e.g: text: "2004/1/1 PT 1:00" and start:9
* returns "Americal/Los_Angeles", TIMEZONE_SHORT_GENERIC and "PT". Used by SimpleDateFormat class.
* Used by SimpleDateFormat class.
* @param ID output parameter to recieve the key name of the time zone
* @param text the string containing the time zone translation
* @param start The position in string where time zone string starts
* @param type output parameter to recieve the type of time zone string
* @param value output parameter to recieve the the acutal time zone string
* @param status output parameter to recive the error information
*/
void findZoneIDTypeValue(UnicodeString& zid, const UnicodeString& text, int32_t start, TimeZoneTranslationType& type, UnicodeString& value, UErrorCode& status);
UnicodeString resolveParsedMetazone(const UnicodeString& zid);
};
U_NAMESPACE_END

View file

@ -23,6 +23,7 @@ U_NAMESPACE_BEGIN
// forward declaration
class UVector;
struct Transition;
class U_I18N_API RuleBasedTimeZone : public BasicTimeZone {
public:
@ -289,13 +290,27 @@ public:
virtual void getTimeZoneRules(const InitialTimeZoneRule*& initial,
const TimeZoneRule* trsrules[], int32_t& trscount, UErrorCode& status) /*const*/;
/**
* Get time zone offsets from local wall time.
* @internal
*/
virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/;
private:
void deleteRules(void);
void deleteTransitions(void);
UVector* copyRules(UVector* source);
TimeZoneRule* findRuleInFinal(UDate date, UBool local) const;
TimeZoneRule* findRuleInFinal(UDate date, UBool local,
int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const;
UBool findNext(UDate base, UBool inclusive, UDate& time, TimeZoneRule*& from, TimeZoneRule*& to) const;
UBool findPrev(UDate base, UBool inclusive, UDate& time, TimeZoneRule*& from, TimeZoneRule*& to) const;
int32_t getLocalDelta(int32_t rawBefore, int32_t dstBefore, int32_t rawAfter, int32_t dstAfter,
int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const;
UDate getTransitionTime(Transition* transition, UBool local,
int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt) const;
void getOffsetInternal(UDate date, UBool local, int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
int32_t& rawOffset, int32_t& dstOffset, UErrorCode& ec) const;
InitialTimeZoneRule *fInitialRule;
UVector *fHistoricRules;

View file

@ -616,6 +616,13 @@ public:
virtual void getOffset(UDate date, UBool local, int32_t& rawOffset,
int32_t& dstOffset, UErrorCode& ec) const;
/**
* Get time zone offsets from local wall time.
* @internal
*/
virtual void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) /*const*/;
/**
* Returns the TimeZone's raw GMT offset (i.e., the number of milliseconds to add
* to GMT to get local time, before taking daylight savings time into account).

View file

@ -38,6 +38,7 @@ U_NAMESPACE_BEGIN
class DateFormatSymbols;
class DateFormat;
class MessageFormat;
/**
*
@ -649,13 +650,6 @@ private:
Calendar& cal,
UErrorCode& status) const; // in case of illegal argument
/**
* Used to resolve Time Zone aliases
*
* @param zid Time Zone ID to Canonicalize ( resolve aliases )
*/
void zoneIDCanonicalize( UnicodeString & ) const;
/**
* Used by subFormat() to format a numeric value.
* Appends to toAppendTo a string representation of "value"
@ -767,6 +761,12 @@ private:
ParsePosition& pos,
UBool allowNegative) const;
void parseInt(const UnicodeString& text,
Formattable& number,
int32_t maxDigits,
ParsePosition& pos,
UBool allowNegative) const;
/**
* Translate a pattern, mapping each character in the from string to the
* corresponding character in the to string. Return an error if the original
@ -793,25 +793,22 @@ private:
* if the operation succeeds.
*/
void parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status);
/**
* Given text, a start in the text, and a row index, return the column index that
* of the zone name that matches (case insensitive) at start, or 0 if none matches.
*
int32_t matchZoneString(const UnicodeString& text, int32_t start, int32_t zi) const;
*/
/**
* Given text, a start in the text, and a calendar, return the next offset in the text
* after matching the zone string. If we fail to match, return 0. Update the calendar
* as appropriate.
*/
int32_t subParseZoneString(const UnicodeString& text, int32_t start, Calendar& cal, UErrorCode& status) const;
/**
* append the gmt string
* Private methods for formatting/parsing GMT string
*/
inline void appendGMT(UnicodeString &appendTo, Calendar& cal, UErrorCode& status) const;
void appendGMT(UnicodeString &appendTo, Calendar& cal, UErrorCode& status) const;
void formatGMTDefault(UnicodeString &appendTo, int32_t offset) const;
int32_t parseGMT(const UnicodeString &text, ParsePosition &pos) const;
int32_t parseGMTDefault(const UnicodeString &text, ParsePosition &pos) const;
UBool isDefaultGMTFormat() const;
void formatRFC822TZ(UnicodeString &appendTo, int32_t offset) const;
/**
* Initialize MessageFormat instances used for GMT formatting/parsing
*/
void initGMTFormatters(UErrorCode &status);
/**
* Used to map pattern characters to Calendar field identifiers.
@ -854,7 +851,18 @@ private:
*/
/*transient*/ int32_t fDefaultCenturyStartYear;
/*transient*/ TimeZone* parsedTimeZone; // here to avoid api change
enum ParsedTZType {
TZTYPE_UNK,
TZTYPE_STD,
TZTYPE_DST
};
ParsedTZType tztype; // here to avoid api change
/*
* MessageFormat instances used for localized GMT format
*/
MessageFormat **fGMTFormatters;
UBool fHaveDefaultCentury;
};

View file

@ -670,6 +670,15 @@ protected:
static UResourceBundle* loadRule(const UResourceBundle* top, const UnicodeString& ruleid, UResourceBundle* oldbundle, UErrorCode&status);
private:
friend class ZoneMeta;
/**
* Get a canonical Olson zone ID for the given ID. If the given ID is not valid,
* this method returns empty string as the result. If the given ID is a link, then the
* referenced ID (canonical ID) is returned.
*/
static UnicodeString& getOlsonCanonicalID(const UnicodeString &id, UnicodeString &canonical);
static TimeZone* createCustomTimeZone(const UnicodeString&); // Creates a time zone based on the string.
/**

View file

@ -0,0 +1,930 @@
/*
*******************************************************************************
* Copyright (C) 2007, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "zonemeta.h"
#include "unicode/timezone.h"
#include "unicode/ustring.h"
#include "unicode/putil.h"
#include "umutex.h"
#include "uvector.h"
#include "cmemory.h"
#include "gregoimp.h"
#include "cstring.h"
#include "ucln_in.h"
static UBool gZoneMetaInitialized = FALSE;
// Metazone mapping tables
static UMTX gZoneMetaLock = NULL;
static U_NAMESPACE_QUALIFIER Hashtable *gCanonicalMap = NULL;
static U_NAMESPACE_QUALIFIER Hashtable *gOlsonToMeta = NULL;
static U_NAMESPACE_QUALIFIER Hashtable *gMetaToOlson = NULL;
U_CDECL_BEGIN
/**
* Cleanup callback func
*/
static UBool U_CALLCONV zoneMeta_cleanup(void)
{
umtx_destroy(&gZoneMetaLock);
if (gCanonicalMap != NULL) {
delete (U_NAMESPACE_QUALIFIER Hashtable*) gCanonicalMap;
gCanonicalMap = NULL;
}
if (gOlsonToMeta != NULL) {
delete (U_NAMESPACE_QUALIFIER Hashtable*) gOlsonToMeta;
gOlsonToMeta = NULL;
}
if (gMetaToOlson != NULL) {
delete (U_NAMESPACE_QUALIFIER Hashtable*) gMetaToOlson;
gMetaToOlson = NULL;
}
gZoneMetaInitialized = FALSE;
return TRUE;
}
/**
* Deleter for UVector
*/
static void U_CALLCONV
deleteUVector(void *obj) {
delete (U_NAMESPACE_QUALIFIER UVector*) obj;
}
/**
* Deleter for CanonicalMapEntry
*/
static void U_CALLCONV
deleteCanonicalMapEntry(void *obj) {
U_NAMESPACE_QUALIFIER CanonicalMapEntry *entry = (U_NAMESPACE_QUALIFIER CanonicalMapEntry*)obj;
uprv_free(entry->id);
if (entry->country != NULL) {
uprv_free(entry->country);
}
uprv_free(entry);
}
/**
* Deleter for OlsonToMetaMappingEntry
*/
static void U_CALLCONV
deleteOlsonToMetaMappingEntry(void *obj) {
U_NAMESPACE_QUALIFIER OlsonToMetaMappingEntry *entry = (U_NAMESPACE_QUALIFIER OlsonToMetaMappingEntry*)obj;
uprv_free(entry->mzid);
uprv_free(entry);
}
/**
* Deleter for MetaToOlsonMappingEntry
*/
static void U_CALLCONV
deleteMetaToOlsonMappingEntry(void *obj) {
U_NAMESPACE_QUALIFIER MetaToOlsonMappingEntry *entry = (U_NAMESPACE_QUALIFIER MetaToOlsonMappingEntry*)obj;
uprv_free(entry->id);
uprv_free(entry->territory);
uprv_free(entry);
}
U_CDECL_END
U_NAMESPACE_BEGIN
#define ZID_KEY_MAX 128
static const char gZoneStringsTag[] = "zoneStrings";
static const char gUseMetazoneTag[] = "um";
static const char gSupplementalData[] = "supplementalData";
static const char gMapTimezonesTag[] = "mapTimezones";
static const char gMetazonesTag[] = "metazones";
static const char gZoneFormattingTag[] = "zoneFormatting";
static const char gTerritoryTag[] = "territory";
static const char gAliasesTag[] = "aliases";
static const char gMultizoneTag[] = "multizone";
static const char gMetazoneInfo[] = "metazoneInfo";
static const char gMetazoneMappings[] = "metazoneMappings";
#define MZID_PREFIX_LEN 5
static const char gMetazoneIdPrefix[] = "meta:";
static const UChar gWorld[] = {0x30, 0x30, 0x31, 0x00}; // "001"
#define ASCII_DIGIT(c) (((c)>=0x30 && (c)<=0x39) ? (c)-0x30 : -1)
/*
* Convert a date string used by metazone mappings to UDate.
* The format used by CLDR metazone mapping is "yyyy-MM-dd HH:mm".
*/
static UDate parseDate (const UChar *text, UErrorCode &status) {
if (U_FAILURE(status)) {
return 0;
}
int32_t year = 0, month = 0, day = 0, hour = 0, min = 0, n;
int32_t idx;
// "yyyy" (0 - 3)
for (idx = 0; idx <= 3 && U_SUCCESS(status); idx++) {
n = ASCII_DIGIT(text[idx]);
if (n >= 0) {
year = 10*year + n;
} else {
status = U_INVALID_FORMAT_ERROR;
}
}
// "MM" (5 - 6)
for (idx = 5; idx <= 6 && U_SUCCESS(status); idx++) {
n = ASCII_DIGIT(text[idx]);
if (n >= 0) {
month = 10*month + n;
} else {
status = U_INVALID_FORMAT_ERROR;
}
}
// "dd" (8 - 9)
for (idx = 8; idx <= 9 && U_SUCCESS(status); idx++) {
n = ASCII_DIGIT(text[idx]);
if (n >= 0) {
day = 10*day + n;
} else {
status = U_INVALID_FORMAT_ERROR;
}
}
// "HH" (11 - 12)
for (idx = 11; idx <= 12 && U_SUCCESS(status); idx++) {
n = ASCII_DIGIT(text[idx]);
if (n >= 0) {
hour = 10*hour + n;
} else {
status = U_INVALID_FORMAT_ERROR;
}
}
// "mm" (14 - 15)
for (idx = 14; idx <= 15 && U_SUCCESS(status); idx++) {
n = ASCII_DIGIT(text[idx]);
if (n >= 0) {
min = 10*min + n;
} else {
status = U_INVALID_FORMAT_ERROR;
}
}
if (U_SUCCESS(status)) {
UDate date = Grego::fieldsToDay(year, month - 1, day) * U_MILLIS_PER_DAY
+ hour * U_MILLIS_PER_HOUR + min * U_MILLIS_PER_MINUTE;
return date;
}
return 0;
}
/*
* Initialize global objects
*/
void
ZoneMeta::initialize(void) {
UBool initialized;
UMTX_CHECK(&gZoneMetaLock, gZoneMetaInitialized, initialized);
if (initialized) {
return;
}
UErrorCode status = U_ZERO_ERROR;
// Initialize hash tables
Hashtable *tmpCanonicalMap = createCanonicalMap();
Hashtable *tmpOlsonToMeta = createOlsonToMetaMap();
if (tmpOlsonToMeta == NULL) {
// With ICU 3.8 data
createOlsonToMetaMapOld();
}
Hashtable *tmpMetaToOlson = createMetaToOlsonMap();
umtx_lock(&gZoneMetaLock);
if (gZoneMetaInitialized) {
// Another thread already created mappings
delete tmpCanonicalMap;
delete tmpOlsonToMeta;
delete tmpMetaToOlson;
} else {
gZoneMetaInitialized = TRUE;
gCanonicalMap = tmpCanonicalMap;
gOlsonToMeta = tmpOlsonToMeta;
gMetaToOlson = tmpMetaToOlson;
ucln_i18n_registerCleanup(UCLN_I18N_ZONEMETA, zoneMeta_cleanup);
}
umtx_unlock(&gZoneMetaLock);
}
Hashtable*
ZoneMeta::createCanonicalMap(void) {
UErrorCode status = U_ZERO_ERROR;
Hashtable *canonicalMap = NULL;
UResourceBundle *supplementalDataBundle = NULL;
UResourceBundle *zoneFormatting = NULL;
UResourceBundle *tzitem = NULL;
UResourceBundle *aliases = NULL;
canonicalMap = new Hashtable(uhash_compareUnicodeString, NULL, status);
if (U_FAILURE(status)) {
return NULL;
}
canonicalMap->setValueDeleter(deleteCanonicalMapEntry);
supplementalDataBundle = ures_openDirect(NULL, gSupplementalData, &status);
zoneFormatting = ures_getByKey(supplementalDataBundle, gZoneFormattingTag, NULL, &status);
if (U_FAILURE(status)) {
goto error_cleanup;
}
while (ures_hasNext(zoneFormatting)) {
tzitem = ures_getNextResource(zoneFormatting, NULL, &status);
if (U_FAILURE(status)) {
ures_close(tzitem);
tzitem = NULL;
status = U_ZERO_ERROR;
continue;
}
if (ures_getType(tzitem) != URES_TABLE) {
ures_close(tzitem);
tzitem = NULL;
continue;
}
int32_t territoryLen;
const UChar *territory = ures_getStringByKey(tzitem, gTerritoryTag, &territoryLen, &status);
if (U_FAILURE(status)) {
territory = NULL;
status = U_ZERO_ERROR;
}
int32_t tzidLen = 0;
char tzid[ZID_KEY_MAX];
const char *tzkey = ures_getKey(tzitem);
uprv_strcpy(tzid, tzkey);
// Replace ':' with '/'
char *p = tzid;
while (*p) {
if (*p == ':') {
*p = '/';
}
p++;
tzidLen++;
}
// Create canonical map entry
CanonicalMapEntry *entry = (CanonicalMapEntry*)uprv_malloc(sizeof(CanonicalMapEntry));
if (entry == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
goto error_cleanup;
}
entry->id = (UChar*)uprv_malloc((tzidLen + 1) * sizeof(UChar));
if (entry->id == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
uprv_free(entry);
goto error_cleanup;
}
u_charsToUChars(tzid, entry->id, tzidLen + 1);
if (territory == NULL || u_strcmp(territory, gWorld) == 0) {
entry->country = NULL;
} else {
entry->country = (UChar*)uprv_malloc((territoryLen + 1) * sizeof(UChar));
if (entry->country == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteCanonicalMapEntry(entry);
goto error_cleanup;
}
u_strcpy(entry->country, territory);
}
// Put this entry to the table
canonicalMap->put(UnicodeString(tzid), entry, status);
if (U_FAILURE(status)) {
deleteCanonicalMapEntry(entry);
goto error_cleanup;
}
// Get aliases
aliases = ures_getByKey(tzitem, gAliasesTag, NULL, &status);
if (U_FAILURE(status)) {
// No aliases
status = U_ZERO_ERROR;
ures_close(tzitem);
continue;
}
while (ures_hasNext(aliases)) {
int32_t aliasLen;
const UChar* alias = ures_getNextString(aliases, &aliasLen, NULL, &status);
if (U_FAILURE(status)) {
status = U_ZERO_ERROR;
continue;
}
// Create canonical map entry for this alias
entry = (CanonicalMapEntry*)uprv_malloc(sizeof(CanonicalMapEntry));
if (entry == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
goto error_cleanup;
}
entry->id = (UChar*)uprv_malloc((tzidLen + 1) * sizeof(UChar));
if (entry->id == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
uprv_free(entry);
goto error_cleanup;
}
u_charsToUChars(tzid, entry->id, tzidLen + 1);
if (territory == NULL || u_strcmp(territory, gWorld) == 0) {
entry->country = NULL;
} else {
entry->country = (UChar*)uprv_malloc((territoryLen + 1) * sizeof(UChar));
if (entry->country == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
deleteCanonicalMapEntry(entry);
goto error_cleanup;
}
u_strcpy(entry->country, territory);
}
canonicalMap->put(UnicodeString(alias), entry, status);
if (U_FAILURE(status)) {
deleteCanonicalMapEntry(entry);
goto error_cleanup;
}
}
ures_close(aliases);
ures_close(tzitem);
}
ures_close(zoneFormatting);
ures_close(supplementalDataBundle);
return canonicalMap;
error_cleanup:
ures_close(aliases);
ures_close(tzitem);
ures_close(zoneFormatting);
ures_close(supplementalDataBundle);
delete canonicalMap;
return NULL;
}
/*
* Creating Olson tzid to metazone mappings from resource (3.8.1 and beyond)
*/
Hashtable*
ZoneMeta::createOlsonToMetaMap(void) {
UErrorCode status = U_ZERO_ERROR;
Hashtable *olsonToMeta = NULL;
UResourceBundle *metazoneInfoBundle = NULL;
UResourceBundle *metazoneMappings = NULL;
StringEnumeration *tzids = NULL;
olsonToMeta = new Hashtable(uhash_compareUnicodeString, NULL, status);
if (U_FAILURE(status)) {
return NULL;
}
olsonToMeta->setValueDeleter(deleteUVector);
// Read metazone mappings from metazoneInfo bundle
metazoneInfoBundle = ures_openDirect(NULL, gMetazoneInfo, &status);
metazoneMappings = ures_getByKey(metazoneInfoBundle, gMetazoneMappings, NULL, &status);
if (U_FAILURE(status)) {
goto error_cleanup;
}
// Walk through all canonical tzids
char zidkey[ZID_KEY_MAX];
tzids = TimeZone::createEnumeration();
const char *tzid;
while ((tzid = tzids->next(NULL, status))) {
if (U_FAILURE(status)) {
goto error_cleanup;
}
// We may skip aliases, because the bundle
// contains only canonical IDs. For now, try
// all of them.
uprv_strcpy(zidkey, tzid);
// Replace '/' with ':'
UBool foundSep = FALSE;
char *p = zidkey;
while (*p) {
if (*p == '/') {
*p = ':';
foundSep = TRUE;
}
p++;
}
if (!foundSep) {
// A valid time zone key has at least one separator
continue;
}
UResourceBundle *zoneItem = ures_getByKey(metazoneMappings, zidkey, NULL, &status);
if (U_FAILURE(status)) {
status = U_ZERO_ERROR;
ures_close(zoneItem);
continue;
}
UVector *mzMappings = NULL;
while (ures_hasNext(zoneItem)) {
UResourceBundle *mz = ures_getNextResource(zoneItem, NULL, &status);
int32_t len;
const UChar *mz_name = ures_getStringByIndex(mz, 0, &len, &status);
const UChar *mz_from = ures_getStringByIndex(mz, 1, &len, &status);
const UChar *mz_to = ures_getStringByIndex(mz, 2, &len, &status);
ures_close(mz);
if(U_FAILURE(status)){
status = U_ZERO_ERROR;
continue;
}
// We do not want to use SimpleDateformat to parse boundary dates,
// because this code could be triggered by the initialization code
// used by SimpleDateFormat.
UDate from = parseDate(mz_from, status);
UDate to = parseDate(mz_to, status);
if (U_FAILURE(status)) {
status = U_ZERO_ERROR;
continue;
}
OlsonToMetaMappingEntry *entry = (OlsonToMetaMappingEntry*)uprv_malloc(sizeof(OlsonToMetaMappingEntry));
if (entry == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
break;
}
entry->mzid = (UChar*)uprv_malloc((u_strlen(mz_name) + 1) * sizeof(UChar));
if (entry->mzid == NULL) {
uprv_free(entry);
status = U_MEMORY_ALLOCATION_ERROR;
break;
}
u_strcpy(entry->mzid, mz_name);
entry->from = from;
entry->to = to;
if (mzMappings == NULL) {
mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status);
if (U_FAILURE(status)) {
delete mzMappings;
deleteOlsonToMetaMappingEntry(entry);
uprv_free(entry);
break;
}
}
mzMappings->addElement(entry, status);
if (U_FAILURE(status)) {
break;
}
}
ures_close(zoneItem);
if (U_FAILURE(status)) {
if (mzMappings != NULL) {
delete mzMappings;
}
goto error_cleanup;
}
if (mzMappings != NULL) {
olsonToMeta->put(UnicodeString(tzid), mzMappings, status);
if (U_FAILURE(status)) {
delete mzMappings;
goto error_cleanup;
}
}
}
delete tzids;
ures_close(metazoneMappings);
ures_close(metazoneInfoBundle);
return olsonToMeta;
error_cleanup:
if (tzids != NULL) {
delete tzids;
}
ures_close(metazoneMappings);
ures_close(metazoneInfoBundle);
if (olsonToMeta != NULL) {
delete olsonToMeta;
}
return NULL;
}
/*
* Creating Olson tzid to metazone mappings from ICU resource (3.8)
*/
Hashtable*
ZoneMeta::createOlsonToMetaMapOld(void) {
UErrorCode status = U_ZERO_ERROR;
Hashtable *olsonToMeta = NULL;
UResourceBundle *rootBundle = NULL;
UResourceBundle *zoneStringsArray = NULL;
StringEnumeration *tzids = NULL;
olsonToMeta = new Hashtable(uhash_compareUnicodeString, NULL, status);
if (U_FAILURE(status)) {
return NULL;
}
olsonToMeta->setValueDeleter(deleteUVector);
// Read metazone mappings from root bundle
rootBundle = ures_openDirect(NULL, "", &status);
zoneStringsArray = ures_getByKey(rootBundle, gZoneStringsTag, NULL, &status);
if (U_FAILURE(status)) {
goto error_cleanup;
}
// Walk through all canonical tzids
char zidkey[ZID_KEY_MAX];
tzids = TimeZone::createEnumeration();
const char *tzid;
while ((tzid = tzids->next(NULL, status))) {
if (U_FAILURE(status)) {
goto error_cleanup;
}
// We may skip aliases, because the bundle
// contains only canonical IDs. For now, try
// all of them.
uprv_strcpy(zidkey, tzid);
// Replace '/' with ':'
UBool foundSep = FALSE;
char *p = zidkey;
while (*p) {
if (*p == '/') {
*p = ':';
foundSep = TRUE;
}
p++;
}
if (!foundSep) {
// A valid time zone key has at least one separator
continue;
}
UResourceBundle *zoneItem = ures_getByKey(zoneStringsArray, zidkey, NULL, &status);
UResourceBundle *useMZ = ures_getByKey(zoneItem, gUseMetazoneTag, NULL, &status);
if (U_FAILURE(status)) {
status = U_ZERO_ERROR;
ures_close(zoneItem);
ures_close(useMZ);
continue;
}
UVector *mzMappings = NULL;
while (ures_hasNext(useMZ)) {
UResourceBundle *mz = ures_getNextResource(useMZ, NULL, &status);
int32_t len;
const UChar *mz_name = ures_getStringByIndex(mz, 0, &len, &status);
const UChar *mz_from = ures_getStringByIndex(mz, 1, &len, &status);
const UChar *mz_to = ures_getStringByIndex(mz, 2, &len, &status);
ures_close(mz);
if(U_FAILURE(status)){
status = U_ZERO_ERROR;
continue;
}
// We do not want to use SimpleDateformat to parse boundary dates,
// because this code could be triggered by the initialization code
// used by SimpleDateFormat.
UDate from = parseDate(mz_from, status);
UDate to = parseDate(mz_to, status);
if (U_FAILURE(status)) {
status = U_ZERO_ERROR;
continue;
}
OlsonToMetaMappingEntry *entry = (OlsonToMetaMappingEntry*)uprv_malloc(sizeof(OlsonToMetaMappingEntry));
if (entry == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
break;
}
entry->mzid = (UChar*)uprv_malloc((u_strlen(mz_name) + 1) * sizeof(UChar));
if (entry->mzid == NULL) {
uprv_free(entry);
status = U_MEMORY_ALLOCATION_ERROR;
break;
}
u_strcpy(entry->mzid, mz_name);
entry->from = from;
entry->to = to;
if (mzMappings == NULL) {
mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status);
if (U_FAILURE(status)) {
delete mzMappings;
deleteOlsonToMetaMappingEntry(entry);
uprv_free(entry);
break;
}
}
mzMappings->addElement(entry, status);
if (U_FAILURE(status)) {
break;
}
}
ures_close(zoneItem);
ures_close(useMZ);
if (U_FAILURE(status)) {
if (mzMappings != NULL) {
delete mzMappings;
}
goto error_cleanup;
}
if (mzMappings != NULL) {
olsonToMeta->put(UnicodeString(tzid), mzMappings, status);
if (U_FAILURE(status)) {
delete mzMappings;
goto error_cleanup;
}
}
}
delete tzids;
ures_close(zoneStringsArray);
ures_close(rootBundle);
return olsonToMeta;
error_cleanup:
if (tzids != NULL) {
delete tzids;
}
ures_close(zoneStringsArray);
ures_close(rootBundle);
if (olsonToMeta != NULL) {
delete olsonToMeta;
}
return NULL;
}
Hashtable*
ZoneMeta::createMetaToOlsonMap(void) {
UErrorCode status = U_ZERO_ERROR;
Hashtable *metaToOlson = NULL;
UResourceBundle *supplementalDataBundle = NULL;
UResourceBundle *mapTimezones = NULL;
UResourceBundle *metazones = NULL;
metaToOlson = new Hashtable(uhash_compareUnicodeString, NULL, status);
if (U_FAILURE(status)) {
return NULL;
}
metaToOlson->setValueDeleter(deleteUVector);
supplementalDataBundle = ures_openDirect(NULL, gSupplementalData, &status);
mapTimezones = ures_getByKey(supplementalDataBundle, gMapTimezonesTag, NULL, &status);
metazones = ures_getByKey(mapTimezones, gMetazonesTag, NULL, &status);
if (U_FAILURE(status)) {
goto error_cleanup;
}
while (ures_hasNext(metazones)) {
UResourceBundle *mz = ures_getNextResource(metazones, NULL, &status);
if (U_FAILURE(status)) {
ures_close(mz);
status = U_ZERO_ERROR;
continue;
}
const char *mzkey = ures_getKey(mz);
if (uprv_strncmp(mzkey, gMetazoneIdPrefix, MZID_PREFIX_LEN) == 0) {
const char *mzid = mzkey + MZID_PREFIX_LEN;
const char *territory = uprv_strrchr(mzid, '_');
int32_t mzidLen = 0;
int32_t territoryLen = 0;
if (territory) {
mzidLen = territory - mzid;
territory++;
territoryLen = uprv_strlen(territory);
}
if (mzidLen > 0 && territoryLen > 0) {
int32_t tzidLen;
const UChar *tzid = ures_getStringByIndex(mz, 0, &tzidLen, &status);
if (U_SUCCESS(status)) {
// Create MetaToOlsonMappingEntry
MetaToOlsonMappingEntry *entry = (MetaToOlsonMappingEntry*)uprv_malloc(sizeof(MetaToOlsonMappingEntry));
if (entry == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
ures_close(mz);
goto error_cleanup;
}
entry->id = (UChar*)uprv_malloc((tzidLen + 1) * sizeof(UChar));
if (entry->id == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
uprv_free(entry);
ures_close(mz);
goto error_cleanup;
}
u_strcpy(entry->id, tzid);
entry->territory = (UChar*)uprv_malloc((territoryLen + 1) * sizeof(UChar));
if (entry->territory == NULL) {
status = U_MEMORY_ALLOCATION_ERROR;
uprv_free(entry->id);
uprv_free(entry);
ures_close(mz);
goto error_cleanup;
}
u_charsToUChars(territory, entry->territory, territoryLen + 1);
// Check if mapping entries for metazone is already available
UnicodeString mzidStr(mzid, mzidLen);
UVector *tzMappings = (UVector*)metaToOlson->get(mzidStr);
if (tzMappings == NULL) {
// Create new UVector and put it into the hashtable
tzMappings = new UVector(deleteMetaToOlsonMappingEntry, NULL, status);
metaToOlson->put(mzidStr, tzMappings, status);
if (U_FAILURE(status)) {
if (tzMappings != NULL) {
delete tzMappings;
}
deleteMetaToOlsonMappingEntry(entry);
ures_close(mz);
goto error_cleanup;
}
}
tzMappings->addElement(entry, status);
if (U_FAILURE(status)) {
goto error_cleanup;
}
} else {
status = U_ZERO_ERROR;
}
}
}
ures_close(mz);
}
ures_close(metazones);
ures_close(mapTimezones);
ures_close(supplementalDataBundle);
return metaToOlson;
error_cleanup:
ures_close(metazones);
ures_close(mapTimezones);
ures_close(supplementalDataBundle);
if (metaToOlson != NULL) {
delete metaToOlson;
}
return NULL;
}
UnicodeString&
ZoneMeta::getCanonicalID(const UnicodeString &tzid, UnicodeString &canonicalID) {
const CanonicalMapEntry *entry = getCanonicalInfo(tzid);
if (entry != NULL) {
canonicalID.setTo(entry->id);
} else {
// Use the input tzid
canonicalID.setTo(tzid);
}
return canonicalID;
}
UnicodeString&
ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &canonicalCountry) {
const CanonicalMapEntry *entry = getCanonicalInfo(tzid);
if (entry != NULL && entry->country != NULL) {
canonicalCountry.setTo(entry->country);
} else {
// Use the input tzid
canonicalCountry.remove();
}
return canonicalCountry;
}
const CanonicalMapEntry*
ZoneMeta::getCanonicalInfo(const UnicodeString &tzid) {
initialize();
CanonicalMapEntry *entry = NULL;
UnicodeString canonicalOlsonId;
TimeZone::getOlsonCanonicalID(tzid, canonicalOlsonId);
if (!canonicalOlsonId.isEmpty()) {
if (gCanonicalMap != NULL) {
entry = (CanonicalMapEntry*)gCanonicalMap->get(tzid);
}
}
return entry;
}
UnicodeString&
ZoneMeta::getSingleCountry(const UnicodeString &tzid, UnicodeString &country) {
UErrorCode status = U_ZERO_ERROR;
// Get canonical country for the zone
getCanonicalCountry(tzid, country);
if (!country.isEmpty()) {
UResourceBundle *supplementalDataBundle = ures_openDirect(NULL, gSupplementalData, &status);
UResourceBundle *zoneFormatting = ures_getByKey(supplementalDataBundle, gZoneFormattingTag, NULL, &status);
UResourceBundle *multizone = ures_getByKey(zoneFormatting, gMultizoneTag, NULL, &status);
if (U_SUCCESS(status)) {
while (ures_hasNext(multizone)) {
int32_t len;
const UChar* multizoneCountry = ures_getNextString(multizone, &len, NULL, &status);
if (country.compare(multizoneCountry, len) == 0) {
// Included in the multizone country list
country.remove();
break;
}
}
}
ures_close(multizone);
ures_close(zoneFormatting);
ures_close(supplementalDataBundle);
}
return country;
}
UnicodeString&
ZoneMeta::getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &result) {
UBool isSet = FALSE;
const UVector *mappings = getMetazoneMappings(tzid);
if (mappings != NULL) {
for (int32_t i = 0; i < mappings->size(); i++) {
OlsonToMetaMappingEntry *mzm = (OlsonToMetaMappingEntry*)mappings->elementAt(i);
if (mzm->from <= date && mzm->to > date) {
result.setTo(mzm->mzid, -1);
isSet = TRUE;
break;
}
}
}
if (!isSet) {
result.remove();
}
return result;
}
const UVector*
ZoneMeta::getMetazoneMappings(const UnicodeString &tzid) {
initialize();
const UVector *result;
if (gOlsonToMeta != NULL) {
result = (UVector*)gOlsonToMeta->get(tzid);
}
return result;
}
UnicodeString&
ZoneMeta::getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &region, UnicodeString &result) {
initialize();
UBool isSet = FALSE;
if (gMetaToOlson != NULL) {
UVector *mappings = (UVector*)gMetaToOlson->get(mzid);
if (mappings != NULL) {
// Find a preferred time zone for the given region.
for (int32_t i = 0; i < mappings->size(); i++) {
MetaToOlsonMappingEntry *olsonmap = (MetaToOlsonMappingEntry*)mappings->elementAt(i);
if (region.compare(olsonmap->territory, -1) == 0) {
result.setTo(olsonmap->id);
isSet = TRUE;
break;
} else if (u_strcmp(olsonmap->territory, gWorld) == 0) {
result.setTo(olsonmap->id);
isSet = TRUE;
}
}
}
}
if (!isSet) {
result.remove();
}
return result;
}
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -0,0 +1,84 @@
/*
*******************************************************************************
* Copyright (C) 2007, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef ZONEMETA_H
#define ZONEMETA_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/unistr.h"
#include "hash.h"
U_NAMESPACE_BEGIN
typedef struct CanonicalMapEntry {
UChar *id;
UChar *country;
} CanonicalMapEntry;
typedef struct OlsonToMetaMappingEntry {
UChar *mzid;
UDate from;
UDate to;
} OlsonToMetaMappingEntry;
typedef struct MetaToOlsonMappingEntry {
UChar *id;
UChar *territory;
} MetaToOlsonMappingEntry;
class UVector;
class U_I18N_API ZoneMeta {
public:
/**
* Return the canonical id for this tzid, which might be the id itself.
* If there is no canonical id for it, return the passed-in id.
*/
static UnicodeString& getCanonicalID(const UnicodeString &tzid, UnicodeString &canonicalID);
/**
* Return the canonical country code for this tzid. If we have none, or if the time zone
* is not associated with a country, return null.
*/
static UnicodeString& getCanonicalCountry(const UnicodeString &tzid, UnicodeString &canonicalCountry);
/**
* Return the country code if this is a 'single' time zone that can fallback to just
* the country, otherwise return empty string. (Note, one must also check the locale data
* to see that there is a localization for the country in order to implement
* tr#35 appendix J step 5.)
*/
static UnicodeString& getSingleCountry(const UnicodeString &tzid, UnicodeString &country);
/**
* Returns a CLDR metazone ID for the given Olson tzid and time.
*/
static UnicodeString& getMetazoneID(const UnicodeString &tzid, UDate date, UnicodeString &result);
/**
* Returns an Olson ID for the ginve metazone and region
*/
static UnicodeString& getZoneIdByMetazone(const UnicodeString &mzid, const UnicodeString &region, UnicodeString &result);
static const UVector* getMetazoneMappings(const UnicodeString &tzid);
private:
static void initialize(void);
static const CanonicalMapEntry* getCanonicalInfo(const UnicodeString &tzid);
static Hashtable* createCanonicalMap(void);
static Hashtable* createOlsonToMetaMapOld(void);
static Hashtable* createOlsonToMetaMap(void);
static Hashtable* createMetaToOlsonMap(void);
};
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif // ZONEMETA_H

File diff suppressed because it is too large Load diff

439
icu4c/source/i18n/zstrfmt.h Normal file
View file

@ -0,0 +1,439 @@
/*
*******************************************************************************
* Copyright (C) 2007, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef ZSTRFMT_H
#define ZSTRFMT_H
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "unicode/uobject.h"
#include "unicode/unistr.h"
#include "unicode/calendar.h"
#include "hash.h"
U_NAMESPACE_BEGIN
class UVector;
/*
* Character node used by TextTrieMap
*/
class CharacterNode : public UMemory {
public:
CharacterNode(UChar32 c, UObjectDeleter *fn);
virtual ~CharacterNode();
inline UChar32 getCharacter(void) const;
inline UVector* getValues(void) const;
inline UVector* getChildNodes(void) const;
void addValue(void *value, UErrorCode &status);
CharacterNode* addChildNode(UChar32 c, UErrorCode &status);
CharacterNode* getChildNode(UChar32 c) const;
private:
UChar32 fCharacter;
UVector *fChildren;
UVector *fValues;
UObjectDeleter *fValueDeleter;
};
inline UChar32 CharacterNode::getCharacter(void) const {
return fCharacter;
}
inline UVector* CharacterNode::getValues(void) const {
return fValues;
}
inline UVector* CharacterNode::getChildNodes(void) const {
return fChildren;
}
/*
* Search result handler callback interface used by TextTrieMap search.
*/
class TextTrieMapSearchResultHandler {
public:
virtual UBool handleMatch(int32_t matchLength,
const UVector *values, UErrorCode& status) = 0;
};
/**
* TextTrieMap is a trie implementation for supporting
* fast prefix match for the string key.
*/
class TextTrieMap : public UMemory {
public:
TextTrieMap(UBool ignoreCase, UObjectDeleter *valueDeleterFunc);
virtual ~TextTrieMap();
void put(const UnicodeString &key, void *value, UErrorCode &status);
void search(const UnicodeString &text, int32_t start,
TextTrieMapSearchResultHandler *handler, UErrorCode& status) const;
private:
UBool fIgnoreCase;
UObjectDeleter *fValueDeleter;
CharacterNode *fRoot;
void search(CharacterNode *node, const UnicodeString &text, int32_t start,
int32_t index, TextTrieMapSearchResultHandler *handler, UErrorCode &status) const;
};
// Name types, these bit flag are used for zone string lookup
enum TimeZoneTranslationType {
LOCATION = 0x0001,
GENERIC_LONG = 0x0002,
GENERIC_SHORT = 0x0004,
STANDARD_LONG = 0x0008,
STANDARD_SHORT = 0x0010,
DAYLIGHT_LONG = 0x0020,
DAYLIGHT_SHORT = 0x0040
};
// Name type index, these constants are used for index in the zone strings array.
enum TimeZoneTranslationTypeIndex {
ZSIDX_LOCATION = 0,
ZSIDX_LONG_STANDARD,
ZSIDX_SHORT_STANDARD,
ZSIDX_LONG_DAYLIGHT,
ZSIDX_SHORT_DAYLIGHT,
ZSIDX_LONG_GENERIC,
ZSIDX_SHORT_GENERIC,
ZSIDX_COUNT
};
class MessageFormat;
/*
* ZoneStringInfo is a class holding a localized zone string
* information.
*/
class ZoneStringInfo : public UMemory {
public:
virtual ~ZoneStringInfo();
inline UnicodeString& getID(UnicodeString &result) const;
inline UnicodeString& getString(UnicodeString &result) const;
inline UBool isStandard(void) const;
inline UBool isDaylight(void) const;
inline UBool isGeneric(void) const;
private:
friend class ZoneStringFormat;
friend class ZoneStringSearchResultHandler;
ZoneStringInfo(const UnicodeString &id, const UnicodeString &str, TimeZoneTranslationType type);
UnicodeString fId;
UnicodeString fStr;
TimeZoneTranslationType fType;
};
inline UnicodeString& ZoneStringInfo::getID(UnicodeString &result) const {
return result.setTo(fId);
}
inline UnicodeString& ZoneStringInfo::getString(UnicodeString &result) const {
return result.setTo(fStr);
}
inline UBool ZoneStringInfo::isStandard(void) const {
return (fType == STANDARD_LONG || fType == STANDARD_SHORT);
}
inline UBool ZoneStringInfo::isDaylight(void) const {
return (fType == DAYLIGHT_LONG || fType == DAYLIGHT_SHORT);
}
inline UBool ZoneStringInfo::isGeneric(void) const {
return (fType == LOCATION || fType == GENERIC_LONG || fType == GENERIC_SHORT);
}
class SafeZoneStringFormatPtr;
class ZoneStringFormat : public UMemory {
public:
ZoneStringFormat(const UnicodeString* const* strings, int32_t rowCount, int32_t columnCount, UErrorCode &status);
ZoneStringFormat(const Locale& locale, UErrorCode &status);
virtual ~ZoneStringFormat();
static SafeZoneStringFormatPtr* getZoneStringFormat(const Locale& locale, UErrorCode &status);
/*
* Create a snapshot of old zone strings array for the given date
*/
UnicodeString** createZoneStringsArray(UDate date, int32_t &rowCount, int32_t &colCount, UErrorCode &status) const;
const UnicodeString** getZoneStrings(int32_t &rowCount, int32_t &columnCount) const;
UnicodeString& getSpecificLongString(const Calendar &cal,
UnicodeString &result, UErrorCode &status) const;
UnicodeString& getSpecificShortString(const Calendar &cal,
UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
UnicodeString& getGenericLongString(const Calendar &cal,
UnicodeString &result, UErrorCode &status) const;
UnicodeString& getGenericShortString(const Calendar &cal,
UBool commonlyUsedOnly, UnicodeString &result, UErrorCode &status) const;
UnicodeString& getGenericLocationString(const Calendar &cal,
UnicodeString &result, UErrorCode &status) const;
const ZoneStringInfo* findSpecificLong(const UnicodeString &text, int32_t start,
int32_t &matchLength, UErrorCode &status) const;
const ZoneStringInfo* findSpecificShort(const UnicodeString &text, int32_t start,
int32_t &matchLength, UErrorCode &status) const;
const ZoneStringInfo* findGenericLong(const UnicodeString &text, int32_t start,
int32_t &matchLength, UErrorCode &status) const;
const ZoneStringInfo* findGenericShort(const UnicodeString &text, int32_t start,
int32_t &matchLength, UErrorCode &status) const;
const ZoneStringInfo* findGenericLocation(const UnicodeString &text, int32_t start,
int32_t &matchLength, UErrorCode &status) const;
// Following APIs are not used by SimpleDateFormat, but public for testing purpose
inline UnicodeString& getLongStandard(const UnicodeString &tzid, UDate date,
UnicodeString &result) const;
inline UnicodeString& getLongDaylight(const UnicodeString &tzid, UDate date,
UnicodeString &result) const;
inline UnicodeString& getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
UnicodeString &result) const;
inline UnicodeString& getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
UnicodeString &result) const;
inline UnicodeString& getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
UnicodeString &result) const;
inline UnicodeString& getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
UnicodeString &result) const;
inline UnicodeString& getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
UnicodeString &result) const;
inline UnicodeString& getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
UnicodeString &result) const;
inline UnicodeString& getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const;
private:
Locale fLocale;
Hashtable *fTzidToStrings;
Hashtable *fMzidToStrings;
TextTrieMap *fZoneStringsTrie;
/*
* Private method to get a zone string except generic partial location types.
*/
UnicodeString& getString(const UnicodeString &tzid, TimeZoneTranslationTypeIndex typeIdx, UDate date,
UBool commonlyUsedOnly, UnicodeString& result) const;
/*
* Private method to get a generic string, with fallback logic involved,
* that is,
*
* 1. If a generic non-location string is avaiable for the zone, return it.
* 2. If a generic non-location string is associated with a metazone and
* the zone never use daylight time around the given date, use the standard
* string (if available).
*
* Note: In CLDR1.5.1, the same localization is used for generic and standard.
* In this case, we do not use the standard string and do the rest.
*
* 3. If a generic non-location string is associated with a metazone and
* the offset at the given time is different from the preferred zone for the
* current locale, then return the generic partial location string (if avaiable)
* 4. If a generic non-location string is not available, use generic location
* string.
*/
UnicodeString& getGenericString(const Calendar &cal, UBool isShort, UBool commonlyUsedOnly,
UnicodeString &result, UErrorCode &status) const;
/*
* Private method to get a generic partial location string
*/
UnicodeString& getGenericPartialLocationString(const UnicodeString &tzid, UBool isShort,
UDate date, UBool commonlyUsedOnly, UnicodeString &result) const;
/*
* Find a prefix matching time zone for the given zone string types.
* @param text The text contains a time zone string
* @param start The start index within the text
* @param types The bit mask representing a set of requested types
* @param matchLength Receives the match length
* @param status
* @return If any zone string matched for the requested types, returns a
* ZoneStringInfo for the longest match. If no matches are found for
* the requested types, returns a ZoneStringInfo for the longest match
* for any other types. If nothing matches at all, returns null.
*/
const ZoneStringInfo* find(const UnicodeString &text, int32_t start, int32_t types,
int32_t &matchLength, UErrorCode &status) const;
UnicodeString& getRegion(UnicodeString &region) const;
static MessageFormat* getFallbackFormat(const Locale &locale, UErrorCode &status);
static MessageFormat* getRegionFormat(const Locale &locale, UErrorCode &status);
static const UChar* getZoneStringFromBundle(const UResourceBundle *zoneitem, const char *key);
static UBool isCommonlyUsed(const UResourceBundle *zoneitem);
static UnicodeString& getLocalizedCountry(const UnicodeString &countryCode, const Locale &locale,
UnicodeString &displayCountry);
};
inline UnicodeString&
ZoneStringFormat::getLongStandard(const UnicodeString &tzid, UDate date,
UnicodeString &result) const {
return getString(tzid, ZSIDX_LONG_STANDARD, date, FALSE /* not used */, result);
}
inline UnicodeString&
ZoneStringFormat::getLongDaylight(const UnicodeString &tzid, UDate date,
UnicodeString &result) const {
return getString(tzid, ZSIDX_LONG_DAYLIGHT, date, FALSE /* not used */, result);
}
inline UnicodeString&
ZoneStringFormat::getLongGenericNonLocation(const UnicodeString &tzid, UDate date,
UnicodeString &result) const {
return getString(tzid, ZSIDX_LONG_GENERIC, date, FALSE /* not used */, result);
}
inline UnicodeString&
ZoneStringFormat::getLongGenericPartialLocation(const UnicodeString &tzid, UDate date,
UnicodeString &result) const {
return getGenericPartialLocationString(tzid, FALSE, date, FALSE /* not used */, result);
}
inline UnicodeString&
ZoneStringFormat::getShortStandard(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
UnicodeString &result) const {
return getString(tzid, ZSIDX_SHORT_STANDARD, date, commonlyUsedOnly, result);
}
inline UnicodeString&
ZoneStringFormat::getShortDaylight(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
UnicodeString &result) const {
return getString(tzid, ZSIDX_SHORT_DAYLIGHT, date, commonlyUsedOnly, result);
}
inline UnicodeString&
ZoneStringFormat::getShortGenericNonLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
UnicodeString &result) const {
return getString(tzid, ZSIDX_SHORT_GENERIC, date, commonlyUsedOnly, result);
}
inline UnicodeString&
ZoneStringFormat::getShortGenericPartialLocation(const UnicodeString &tzid, UDate date, UBool commonlyUsedOnly,
UnicodeString &result) const {
return getGenericPartialLocationString(tzid, TRUE, date, commonlyUsedOnly, result);
}
inline UnicodeString&
ZoneStringFormat::getGenericLocation(const UnicodeString &tzid, UnicodeString &result) const {
return getString(tzid, ZSIDX_LOCATION, 0 /*not used*/, FALSE /*not used*/, result);
}
/*
* ZooneStrings is a container of localized zone strings used by ZoneStringFormat
*/
class ZoneStrings : public UMemory {
public:
ZoneStrings(UnicodeString *strings, int32_t stringsCount, UBool commonlyUsed,
UnicodeString **genericPartialLocationStrings, int32_t genericRowCount, int32_t genericColCount);
virtual ~ZoneStrings();
UnicodeString& getString(int32_t typeIdx, UnicodeString &result) const;
inline UBool isShortFormatCommonlyUsed(void) const;
UnicodeString& getGenericPartialLocationString(const UnicodeString &mzid, UBool isShort,
UBool commonlyUsedOnly, UnicodeString &result) const;
private:
UnicodeString *fStrings;
int32_t fStringsCount;
UBool fIsCommonlyUsed;
UnicodeString **fGenericPartialLocationStrings;
int32_t fGenericPartialLocationRowCount;
int32_t fGenericPartialLocationColCount;
};
inline UBool
ZoneStrings::isShortFormatCommonlyUsed(void) const {
return fIsCommonlyUsed;
}
/*
* ZoneStringSearchResultHandler is an implementation of
* TextTrieMapSearchHandler. This class is used by ZoneStringFormat
* for collecting search results for localized zone strings.
*/
class ZoneStringSearchResultHandler : public UMemory, TextTrieMapSearchResultHandler {
public:
ZoneStringSearchResultHandler();
virtual ~ZoneStringSearchResultHandler();
virtual UBool handleMatch(int32_t matchLength, const UVector *values, UErrorCode &status);
int32_t countMatches(void);
const ZoneStringInfo* getMatch(int32_t index, int32_t &matchLength);
void clear(void);
private:
UVector *fResults;
int32_t fMatchLen[ZSIDX_COUNT];
};
/*
* ZoneStringFormat cache implementation
*/
class ZSFCacheEntry : public UMemory {
public:
~ZSFCacheEntry();
void delRef(void);
const ZoneStringFormat* getZoneStringFormat(void);
private:
friend class ZSFCache;
ZSFCacheEntry(const Locale &locale, ZoneStringFormat *zsf, ZSFCacheEntry *next);
Locale fLocale;
ZoneStringFormat *fZoneStringFormat;
ZSFCacheEntry *fNext;
int32_t fRefCount;
};
class SafeZoneStringFormatPtr : public UMemory {
public:
~SafeZoneStringFormatPtr();
const ZoneStringFormat* get() const;
private:
friend class ZSFCache;
SafeZoneStringFormatPtr(ZSFCacheEntry *cacheEntry);
ZSFCacheEntry *fCacheEntry;
};
class ZSFCache : public UMemory {
public:
ZSFCache(int32_t capacity);
~ZSFCache();
SafeZoneStringFormatPtr* get(const Locale &locale, UErrorCode &status);
private:
int32_t fCapacity;
ZSFCacheEntry *fFirst;
};
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif // ZSTRFMT_H

View file

@ -56,7 +56,7 @@ jamotest.o srchtest.o reptest.o regextst.o \
itrbnf.o itrbnfrt.o itrbnfp.o ucaconf.o icusvtst.o \
uobjtest.o idnaref.o idnaconf.o nptrans.o punyref.o testidn.o testidna.o incaltst.o \
calcasts.o v32test.o uvectest.o textfile.o tokiter.o utxttest.o \
windttst.o winnmtst.o winutil.o csdetest.o tzrulets.o
windttst.o winnmtst.o winutil.o csdetest.o tzrulets.o tzoffloc.o tzfmttst.o
DEPS = $(OBJECTS:.o=.d)

View file

@ -69,21 +69,20 @@ void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &nam
TESTCASE(23,TestGreekMay);
TESTCASE(24,TestGenericTime);
TESTCASE(25,TestGenericTimeZoneOrder);
TESTCASE(26,TestTimeZoneStringsAPI);
TESTCASE(27,TestHost);
TESTCASE(28,TestEras);
TESTCASE(29,TestNarrowNames);
TESTCASE(30,TestStandAloneDays);
TESTCASE(31,TestStandAloneMonths);
TESTCASE(32,TestQuarters);
TESTCASE(33,TestZTimeZoneParsing);
TESTCASE(34,TestRelative);
TESTCASE(35,TestRelativeClone);
TESTCASE(36,TestHostClone);
TESTCASE(37,TestTimeZoneDisplayName);
TESTCASE(26,TestHost);
TESTCASE(27,TestEras);
TESTCASE(28,TestNarrowNames);
TESTCASE(29,TestStandAloneDays);
TESTCASE(30,TestStandAloneMonths);
TESTCASE(31,TestQuarters);
TESTCASE(32,TestZTimeZoneParsing);
TESTCASE(33,TestRelative);
TESTCASE(34,TestRelativeClone);
TESTCASE(35,TestHostClone);
TESTCASE(36,TestTimeZoneDisplayName);
/*
TESTCASE(38,TestRelativeError);
TESTCASE(39,TestRelativeOther);
TESTCASE(37,TestRelativeError);
TESTCASE(38,TestRelativeOther);
*/
default: name = ""; break;
}
@ -100,7 +99,7 @@ void DateFormatTest::TestWallyWedel()
/*
* Computational variables.
*/
int32_t offset, hours, minutes;
int32_t offset, hours, minutes, seconds;
/*
* Instantiate a SimpleDateFormat set up to produce a full time
zone name.
@ -141,8 +140,12 @@ void DateFormatTest::TestWallyWedel()
}
hours = offset/3600000;
minutes = (offset%3600000)/60000;
seconds = (offset%60000)/1000;
UnicodeString dstOffset = (UnicodeString)"" + sign + (hours < 10 ? "0" : "") +
(int32_t)hours + ":" + (minutes < 10 ? "0" : "") + (int32_t)minutes;
if (seconds != 0) {
dstOffset = dstOffset + ":" + (seconds < 10 ? "0" : "") + seconds;
}
/*
* Instantiate a date so we can display the time zone name.
*/
@ -382,7 +385,7 @@ void DateFormatTest::TestFieldPosition() {
"Wed", "225", "2", "33", "3", "PM", "2", "2", "PDT", "1997", "4", "1997", "2450674", "52452513", "-0700", "PT", "4", "8", "3", "3","PDT",
"Anno Domini", "1997", "August", "0013", "0014", "0014", "0034", "0012", "5130",
"Wednesday", "0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "0004", "1997", "2450674", "52452513", "-0700",
"Wednesday", "0225", "0002", "0033", "0003", "PM", "0002", "0002", "Pacific Daylight Time", "1997", "0004", "1997", "2450674", "52452513", "GMT-07:00",
"Pacific Time", "Wednesday", "August", "3rd quarter", "3rd quarter", "United States (Los Angeles)"
};
@ -1752,7 +1755,7 @@ void DateFormatTest::TestGenericTime() {
"y/M/d H:mm zzzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Standard Time",
"y/M/d H:mm zzz", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PST",
"y/M/d H:mm vvvv", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 Pacific Time",
"y/M/d H:mm vvv", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PT",
"y/M/d H:mm v", "F", "2004 01 01 01:00 PST", "2004/1/1 1:00 PT",
// non-generic timezone string influences dst offset even if wrong for date/time
"y/M/d H:mm zzz", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 PST",
"y/M/d H:mm vvvv", "pf", "2004/1/1 1:00 PDT", "2004 01 01 01:00 PDT", "2004/1/1 0:00 Pacific Time",
@ -1765,21 +1768,25 @@ void DateFormatTest::TestGenericTime() {
"y/M/d H:mm vvvv", "pf", "2004/7/1 1:00 PT", "2004 07 01 01:00 PDT", "2004/7/1 1:00 Pacific Time",
// daylight savings time transition edge cases.
// time to parse does not really exist, PT interpreted as earlier time
"y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PST", // adjust earlier
"y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
"y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PDT",
"y/M/d H:mm zzz", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PST",
"y/M/d H:mm vvv", "pf", "2005/4/3 2:30 PT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PT", // adjust earlier
"y/M/d H:mm vvv", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
"y/M/d H:mm vvv", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PT",
"y/M/d H:mm", "pf", "2005/4/3 2:30", "2005 04 03 01:30 PST", "2005/4/3 1:30",
// time to parse is ambiguous, PT interpreted as LATER time (?)
"y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST", // 1:30a PT -> 1:30a PST (later)
"y/M/d H:mm v", "pf", "2005/4/3 2:30 PT", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
"y/M/d H:mm v", "pf", "2005/4/3 2:30 PST", "2005 04 03 03:30 PDT", "2005/4/3 3:30 PT",
"y/M/d H:mm v", "pf", "2005/4/3 2:30 PDT", "2005 04 03 01:30 PST", "2005/4/3 1:30 PT",
"y/M/d H:mm", "pf", "2005/4/3 2:30", "2005 04 03 03:30 PDT", "2005/4/3 3:30",
// time to parse is ambiguous, PT interpreted as later time
"y/M/d H:mm zzz", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30 PST",
"y/M/d H:mm v", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30 PT",
"y/M/d H:mm", "pf", "2005/10/30 1:30 PT", "2005 10 30 01:30 PST", "2005/10/30 1:30",
"y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
"y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PST",
"y/M/d H:mm zzz", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PDT",
"y/M/d H:mm vvv", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT", // 1:30a PT -> 1:30a PST (later)
"y/M/d H:mm vvv", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
"y/M/d H:mm vvv", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PT",
"y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30", // 1:30a PT -> 1:30a PST (later)
"y/M/d H:mm v", "pf", "2004/10/31 1:30 PT", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
"y/M/d H:mm v", "pf", "2004/10/31 1:30 PST", "2004 10 31 01:30 PST", "2004/10/31 1:30 PT",
"y/M/d H:mm v", "pf", "2004/10/31 1:30 PDT", "2004 10 31 01:30 PDT", "2004/10/31 1:30 PT",
"y/M/d H:mm", "pf", "2004/10/31 1:30", "2004 10 31 01:30 PST", "2004/10/31 1:30",
};
const int32_t ZDATA_length = sizeof(ZDATA)/ sizeof(ZDATA[0]);
expect(ZDATA, ZDATA_length, en);
@ -1864,66 +1871,6 @@ void DateFormatTest::TestGenericTimeZoneOrder() {
expect(XDATA, XDATA_length, en);
}
void DateFormatTest::TestTimeZoneStringsAPI() {
// Verify data
UErrorCode status = U_ZERO_ERROR;
DateFormatSymbols symbols(Locale::getUS(), status);
StringEnumeration* keys = symbols.createZoneStringIDs(status);
if(U_FAILURE(status)){
errln("Could not create the StringEnumeration for Locale::getUS(). Error: %s", u_errorName(status));
return;
}
StringEnumeration* keys2 = symbols.createZoneStringIDs(status);
ASSERT_OK(status);
if(*keys2!=*keys){
errln("operator!= failed for TimeZoneStringsEnum");
}
const UnicodeString* key = NULL;
while( (key = keys->snext(status))!=NULL){
logln(prettify(*key));
}
if(U_FAILURE(status)){
errln("Could not iterate over the StringEnumeration. Error: %s", u_errorName(status));
return;
}
UnicodeString expectedKey("meta/Alaska");
UnicodeString expectedStrs[DateFormatSymbols::TIMEZONE_COUNT];
expectedStrs[DateFormatSymbols::TIMEZONE_SHORT_GENERIC].setTo("AKT");
expectedStrs[DateFormatSymbols::TIMEZONE_SHORT_STANDARD].setTo("AKST");
expectedStrs[DateFormatSymbols::TIMEZONE_SHORT_DAYLIGHT].setTo("AKDT");
expectedStrs[DateFormatSymbols::TIMEZONE_LONG_GENERIC].setTo("Alaska Time");
expectedStrs[DateFormatSymbols::TIMEZONE_LONG_STANDARD].setTo("Alaska Standard Time");
expectedStrs[DateFormatSymbols::TIMEZONE_LONG_DAYLIGHT].setTo("Alaska Daylight Time");
expectedStrs[DateFormatSymbols::TIMEZONE_EXEMPLAR_CITY].setTo("");
for(int32_t i=0; i<DateFormatSymbols::TIMEZONE_COUNT; i++){
UnicodeString result;
result = symbols.getZoneString(expectedKey, (DateFormatSymbols::TimeZoneTranslationType)i, result,status);
if(U_FAILURE(status)){
errln("Could not retrieve display name. Error: %s", u_errorName(status));
return;
}
if(expectedStrs[i] != result){
errln("Did not get the expected string. Expected: "+expectedStrs[i]+ UnicodeString(" Got: ") + result );
}
}
expectedKey.setTo("America/Los_Angeles",0);
UnicodeString exemplarCity("Phoenix");
UnicodeString result;
symbols.setZoneString(expectedKey,DateFormatSymbols::TIMEZONE_EXEMPLAR_CITY, exemplarCity, status);
if(U_FAILURE(status)){
errln("setZoneString() did not succeed. Error: %s", u_errorName(status));
return;
}
result = symbols.getZoneString(expectedKey, DateFormatSymbols::TIMEZONE_EXEMPLAR_CITY, result,status);
if(result != exemplarCity){
errln("setZoneString() did not succeed. Expected: " + exemplarCity + " Got: " + result);
}
delete keys;
delete keys2;
}
void DateFormatTest::TestZTimeZoneParsing(void) {
UErrorCode status = U_ZERO_ERROR;
const Locale en("en");

View file

@ -789,6 +789,22 @@
RelativePath=".\tzbdtest.h"
>
</File>
<File
RelativePath=".\tzfmttst.cpp"
>
</File>
<File
RelativePath=".\tzfmttst.h"
>
</File>
<File
RelativePath=".\tzoffloc.cpp"
>
</File>
<File
RelativePath=".\tzoffloc.h"
>
</File>
<File
RelativePath=".\tzregts.cpp"
>

View file

@ -46,6 +46,8 @@
#include "dadrcal.h" // DataDrivenCalendarTest
#include "dadrfmt.h" // DataDrivenFormatTest
#include "dtptngts.h" // IntlTestDateTimePatternGeneratorAPI
#include "tzoffloc.h" // TimeZoneOffsetLocalTest
#include "tzfmttst.h" // TimeZoneFormatTest
#define TESTCLASS(id, TestClass) \
@ -110,6 +112,8 @@ void IntlTestFormat::runIndexedTest( int32_t index, UBool exec, const char* &nam
TESTCLASS(30,DataDrivenCalendarTest);
TESTCLASS(31,DataDrivenFormatTest);
TESTCLASS(32,IntlTestDateTimePatternGeneratorAPI);
TESTCLASS(33,TimeZoneOffsetLocalTest);
TESTCLASS(34,TimeZoneFormatTest);
default: name = ""; break; //needed to end loop

View file

@ -857,8 +857,8 @@ LocaleTest::TestGetLangsAndCountries()
;
/* TODO: Change this test to be more like the cloctst version? */
if (testCount != 488)
errln("Expected getISOLanguages() to return 488 languages; it returned %d", testCount);
if (testCount != 489)
errln("Expected getISOLanguages() to return 489 languages; it returned %d", testCount);
else {
for (i = 0; i < 15; i++) {
int32_t j;

View file

@ -313,7 +313,7 @@ DateFormatMiscTests::test4117335()
UnicodeString jstShort = "JST";
UnicodeString tzID = "meta/Japan";
UnicodeString tzID = "Asia/Tokyo";
UnicodeString jdtLong(jdtLongC, 5, 5);

View file

@ -0,0 +1,457 @@
/*
*******************************************************************************
* Copyright (C) 2007, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "tzfmttst.h"
#include "unicode/timezone.h"
#include "unicode/simpletz.h"
#include "unicode/calendar.h"
#include "unicode/strenum.h"
#include "unicode/smpdtfmt.h"
#include "unicode/uchar.h"
#include "unicode/basictz.h"
#include "cstring.h"
#include "zonemeta.h"
#define DEBUG_ALL 0
static const char* PATTERNS[] = {"z", "zzzz", "Z", "ZZZZ", "v", "vvvv", "V", "VVVV"};
static const int NUM_PATTERNS = sizeof(PATTERNS)/sizeof(const char*);
void
TimeZoneFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
{
if (exec) {
logln("TestSuite TimeZoneFormatTest");
}
switch (index) {
TESTCASE(0, TestTimeZoneRoundTrip);
TESTCASE(1, TestTimeRoundTrip);
default: name = ""; break;
}
}
void
TimeZoneFormatTest::TestTimeZoneRoundTrip(void) {
UErrorCode status = U_ZERO_ERROR;
SimpleTimeZone unknownZone(-31415, (UnicodeString)"Etc/Unknown");
int32_t badDstOffset = -1234;
int32_t badZoneOffset = -2345;
int32_t testDateData[][3] = {
{2007, 1, 15},
{2007, 6, 15},
{1990, 1, 15},
{1990, 6, 15},
{1960, 1, 15},
{1960, 6, 15},
};
Calendar *cal = Calendar::createInstance(TimeZone::createTimeZone((UnicodeString)"UTC"), status);
if (U_FAILURE(status)) {
errln("Calendar::createInstance failed");
return;
}
// Set up rule equivalency test range
UDate low, high;
cal->set(1900, UCAL_JANUARY, 1);
low = cal->getTime(status);
cal->set(2040, UCAL_JANUARY, 1);
high = cal->getTime(status);
if (U_FAILURE(status)) {
errln("getTime failed");
return;
}
// Set up test dates
UDate DATES[(sizeof(testDateData)/sizeof(int32_t))/3];
const int32_t nDates = (sizeof(testDateData)/sizeof(int32_t))/3;
cal->clear();
for (int32_t i = 0; i < nDates; i++) {
cal->set(testDateData[i][0], testDateData[i][1], testDateData[i][2]);
DATES[i] = cal->getTime(status);
if (U_FAILURE(status)) {
errln("getTime failed");
return;
}
}
// Set up test locales
const Locale locales1[] = {
Locale("en_US")
};
const Locale locales2[] = {
Locale("en_US"),
Locale("en"),
Locale("en_CA"),
Locale("fr"),
Locale("zh_Hant")
};
const Locale *LOCALES;
int32_t nLocales;
if (DEBUG_ALL) {
LOCALES = Locale::getAvailableLocales(nLocales);
} else if (quick) {
LOCALES = locales1;
nLocales = sizeof(locales1)/sizeof(Locale);
} else {
LOCALES = locales2;
nLocales = sizeof(locales2)/sizeof(Locale);
}
StringEnumeration *tzids = TimeZone::createEnumeration();
if (U_FAILURE(status)) {
errln("tzids->count failed");
return;
}
int32_t inRaw, inDst;
int32_t outRaw, outDst;
// Run the roundtrip test
for (int32_t locidx = 0; locidx < nLocales; locidx++) {
for (int32_t patidx = 0; patidx < NUM_PATTERNS; patidx++) {
//DEBUG static const char* PATTERNS[] = {"z", "zzzz", "Z", "ZZZZ", "v", "vvvv", "V", "VVVV"};
//if (patidx != 1) continue;
SimpleDateFormat *sdf = new SimpleDateFormat((UnicodeString)PATTERNS[patidx], LOCALES[locidx], status);
if (U_FAILURE(status)) {
errln((UnicodeString)"new SimpleDateFormat failed for pattern " +
PATTERNS[patidx] + " for locale " + LOCALES[locidx].getName());
status = U_ZERO_ERROR;
continue;
}
tzids->reset(status);
const UnicodeString *tzid;
while ((tzid = tzids->snext(status))) {
TimeZone *tz = TimeZone::createTimeZone(*tzid);
for (int32_t datidx = 0; datidx < nDates; datidx++) {
UnicodeString tzstr;
FieldPosition fpos(0);
// Format
sdf->setTimeZone(*tz);
sdf->format(DATES[datidx], tzstr, fpos);
// Before parse, set unknown zone to SimpleDateFormat instance
// just for making sure that it does not depends on the time zone
// originally set.
sdf->setTimeZone(unknownZone);
// Parse
ParsePosition pos(0);
Calendar *outcal = Calendar::createInstance(unknownZone, status);
if (U_FAILURE(status)) {
errln("Failed to create an instance of calendar for receiving parse result.");
status = U_ZERO_ERROR;
continue;
}
outcal->set(UCAL_DST_OFFSET, badDstOffset);
outcal->set(UCAL_ZONE_OFFSET, badZoneOffset);
sdf->parse(tzstr, *outcal, pos);
// Check the result
const TimeZone &outtz = outcal->getTimeZone();
UnicodeString outtzid;
outtz.getID(outtzid);
tz->getOffset(DATES[datidx], false, inRaw, inDst, status);
if (U_FAILURE(status)) {
errln((UnicodeString)"Failed to get offsets from time zone" + *tzid);
status = U_ZERO_ERROR;
}
outtz.getOffset(DATES[datidx], false, outRaw, outDst, status);
if (U_FAILURE(status)) {
errln((UnicodeString)"Failed to get offsets from time zone" + outtzid);
status = U_ZERO_ERROR;
}
// Check if localized GMT format or RFC format is used.
int32_t numDigits = 0;
for (int n = 0; n < tzstr.length(); n++) {
if (u_isdigit(tzstr.charAt(n))) {
numDigits++;
}
}
if (numDigits >= 4) {
// Localized GMT or RFC: total offset (raw + dst) must be preserved.
int32_t inOffset = inRaw + inDst;
int32_t outOffset = outRaw + outDst;
if (inOffset != outOffset) {
errln((UnicodeString)"Offset round trip failed; tz=" + *tzid
+ ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
+ ", time=" + DATES[datidx] + ", str=" + tzstr
+ ", inOffset=" + inOffset + ", outOffset=" + outOffset);
}
} else if (uprv_strcmp(PATTERNS[patidx], "z") == 0 || uprv_strcmp(PATTERNS[patidx], "zzzz") == 0
|| uprv_strcmp(PATTERNS[patidx], "v") == 0 || uprv_strcmp(PATTERNS[patidx], "vvvv") == 0
|| uprv_strcmp(PATTERNS[patidx], "V") == 0) {
// Specific or generic: raw offset must be preserved.
if (inRaw != outRaw) {
errln((UnicodeString)"Raw offset round trip failed; tz=" + *tzid
+ ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
+ ", time=" + DATES[datidx] + ", str=" + tzstr
+ ", inRawOffset=" + inRaw + ", outRawOffset=" + outRaw);
}
} else { // "VVVV"
// Location: time zone rule must be preserved.
UnicodeString canonical;
ZoneMeta::getCanonicalID(*tzid, canonical);
if (outtzid != canonical) {
// Canonical ID did not match - check the rules
if (!((BasicTimeZone*)&outtz)->hasEquivalentTransitions((BasicTimeZone&)*tz, low, high, TRUE, status)) {
errln("Canonical round trip failed; tz=" + *tzid
+ ", locale=" + LOCALES[locidx].getName() + ", pattern=" + PATTERNS[patidx]
+ ", time=" + DATES[datidx] + ", str=" + tzstr
+ ", outtz=" + outtzid);
}
if (U_FAILURE(status)) {
errln("hasEquivalentTransitions failed");
status = U_ZERO_ERROR;
}
}
}
}
delete tz;
}
delete sdf;
}
}
delete cal;
delete tzids;
}
void
TimeZoneFormatTest::TestTimeRoundTrip(void) {
UErrorCode status = U_ZERO_ERROR;
Calendar *cal = Calendar::createInstance(TimeZone::createTimeZone((UnicodeString)"UTC"), status);
if (U_FAILURE(status)) {
errln("Calendar::createInstance failed");
return;
}
UDate START_TIME, END_TIME;
if (DEBUG_ALL) {
cal->set(1900, UCAL_JANUARY, 1);
} else {
cal->set(1965, UCAL_JANUARY, 1);
}
START_TIME = cal->getTime(status);
cal->set(2015, UCAL_JANUARY, 1);
END_TIME = cal->getTime(status);
if (U_FAILURE(status)) {
errln("getTime failed");
return;
}
// Whether each pattern is ambiguous at DST->STD local time overlap
UBool AMBIGUOUS_DST_DECESSION[] = {FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE};
// Whether each pattern is ambiguous at STD->STD/DST->DST local time overlap
UBool AMBIGUOUS_NEGATIVE_SHIFT[] = {TRUE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE};
UnicodeString BASEPATTERN("yyyy-MM-dd'T'HH:mm:ss.SSS");
// timer for performance analysis
UDate timer;
UDate times[NUM_PATTERNS];
for (int32_t i = 0; i < NUM_PATTERNS; i++) {
times[i] = 0;
}
UBool REALLY_VERBOSE = FALSE;
// Set up test locales
const Locale locales1[] = {
Locale("en_US")
};
const Locale locales2[] = {
Locale("en_US"),
Locale("en"),
Locale("de_DE"),
Locale("es_ES"),
Locale("fr_FR"),
Locale("it_IT"),
Locale("ja_JP"),
Locale("ko_KR"),
Locale("pt_BR"),
Locale("zh_Hans_CN"),
Locale("zh_Hant_TW")
};
const Locale *LOCALES;
int32_t nLocales;
if (DEBUG_ALL) {
LOCALES = Locale::getAvailableLocales(nLocales);
} else if (quick) {
LOCALES = locales1;
nLocales = sizeof(locales1)/sizeof(Locale);
} else {
LOCALES = locales2;
nLocales = sizeof(locales2)/sizeof(Locale);
}
StringEnumeration *tzids = TimeZone::createEnumeration();
if (U_FAILURE(status)) {
errln("tzids->count failed");
return;
}
int32_t testCounts = 0;
UDate testTimes[4];
UBool expectedRoundTrip[4];
int32_t testLen = 0;
for (int32_t locidx = 0; locidx < nLocales; locidx++) {
logln((UnicodeString)"Locale: " + LOCALES[locidx].getName());
for (int32_t patidx = 0; patidx < NUM_PATTERNS; patidx++) {
logln((UnicodeString)" pattern: " + PATTERNS[patidx]);
//DEBUG static const char* PATTERNS[] = {"z", "zzzz", "Z", "ZZZZ", "v", "vvvv", "V", "VVVV"};
//if (patidx != 1) continue;
UnicodeString pattern(BASEPATTERN);
pattern.append(" ").append(PATTERNS[patidx]);
SimpleDateFormat *sdf = new SimpleDateFormat(pattern, LOCALES[locidx], status);
if (U_FAILURE(status)) {
errln((UnicodeString)"new SimpleDateFormat failed for pattern " +
pattern + " for locale " + LOCALES[locidx].getName());
status = U_ZERO_ERROR;
continue;
}
tzids->reset(status);
const UnicodeString *tzid;
timer = Calendar::getNow();
while ((tzid = tzids->snext(status))) {
UnicodeString canonical;
ZoneMeta::getCanonicalID(*tzid, canonical);
if (*tzid != canonical) {
// Skip aliases
continue;
}
BasicTimeZone *tz = (BasicTimeZone*)TimeZone::createTimeZone(*tzid);
sdf->setTimeZone(*tz);
UDate t = START_TIME;
TimeZoneTransition tzt;
UBool tztAvail = FALSE;
UBool middle = TRUE;
while (t < END_TIME) {
if (!tztAvail) {
testTimes[0] = t;
expectedRoundTrip[0] = TRUE;
testLen = 1;
} else {
int32_t fromOffset = tzt.getFrom()->getRawOffset() + tzt.getFrom()->getDSTSavings();
int32_t toOffset = tzt.getTo()->getRawOffset() + tzt.getTo()->getDSTSavings();
int32_t delta = toOffset - fromOffset;
if (delta < 0) {
UBool isDstDecession = tzt.getFrom()->getDSTSavings() > 0 && tzt.getTo()->getDSTSavings() == 0;
testTimes[0] = t + delta - 1;
expectedRoundTrip[0] = TRUE;
testTimes[1] = t + delta;
expectedRoundTrip[1] = isDstDecession ?
!AMBIGUOUS_DST_DECESSION[patidx] : !AMBIGUOUS_NEGATIVE_SHIFT[patidx];
testTimes[2] = t - 1;
expectedRoundTrip[2] = isDstDecession ?
!AMBIGUOUS_DST_DECESSION[patidx] : !AMBIGUOUS_NEGATIVE_SHIFT[patidx];
testTimes[3] = t;
expectedRoundTrip[3] = TRUE;
testLen = 4;
} else {
testTimes[0] = t - 1;
expectedRoundTrip[0] = TRUE;
testTimes[1] = t;
expectedRoundTrip[1] = TRUE;
testLen = 2;
}
}
for (int32_t testidx = 0; testidx < testLen; testidx++) {
if (quick) {
// reduce regular test time
if (!expectedRoundTrip[testidx]) {
continue;
}
}
testCounts++;
UnicodeString text;
FieldPosition fpos(0);
sdf->format(testTimes[testidx], text, fpos);
UDate parsedDate = sdf->parse(text, status);
if (U_FAILURE(status)) {
errln((UnicodeString)"Failed to parse " + text);
status = U_ZERO_ERROR;
continue;
}
if (parsedDate != testTimes[testidx]) {
UnicodeString msg = (UnicodeString)"Time round trip failed for "
+ "tzid=" + *tzid
+ ", locale=" + LOCALES[locidx].getName()
+ ", pattern=" + PATTERNS[patidx]
+ ", text=" + text
+ ", time=" + testTimes[testidx]
+ ", restime=" + parsedDate
+ ", diff=" + (parsedDate - testTimes[testidx]);
if (expectedRoundTrip[testidx]) {
errln((UnicodeString)"FAIL: " + msg);
} else if (REALLY_VERBOSE) {
logln(msg);
}
}
}
tztAvail = tz->getNextTransition(t, FALSE, tzt);
if (!tztAvail) {
break;
}
if (middle) {
// Test the date in the middle of two transitions.
t += (int64_t)((tzt.getTime() - t)/2);
middle = FALSE;
tztAvail = FALSE;
} else {
t = tzt.getTime();
}
}
delete tz;
}
times[patidx] += (Calendar::getNow() - timer);
delete sdf;
}
}
UDate total = 0;
logln("### Elapsed time by patterns ###");
for (int32_t i = 0; i < NUM_PATTERNS; i++) {
logln(UnicodeString("") + times[i] + "ms (" + PATTERNS[i] + ")");
total += times[i];
}
logln((UnicodeString)"Total: " + total + "ms");
logln((UnicodeString)"Iteration: " + testCounts);
delete cal;
delete tzids;
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -0,0 +1,27 @@
/*
*******************************************************************************
* Copyright (C) 2007, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef _TIMEZONEFORMATTEST_
#define _TIMEZONEFORMATTEST_
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "intltest.h"
class TimeZoneFormatTest : public IntlTest {
// IntlTest override
void runIndexedTest(int32_t index, UBool exec, const char*& name, char* par);
void TestTimeZoneRoundTrip(void);
void TestTimeRoundTrip(void);
};
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif // _TIMEZONEFORMATTEST_

View file

@ -0,0 +1,329 @@
/*
*******************************************************************************
* Copyright (C) 2007, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "tzoffloc.h"
#include "unicode/ucal.h"
#include "unicode/timezone.h"
#include "unicode/calendar.h"
#include "unicode/dtrule.h"
#include "unicode/tzrule.h"
#include "unicode/rbtz.h"
#include "unicode/simpletz.h"
#include "unicode/tzrule.h"
#include "unicode/smpdtfmt.h"
#include "unicode/gregocal.h"
void
TimeZoneOffsetLocalTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
{
if (exec) {
logln("TestSuite TimeZoneOffsetLocalTest");
}
switch (index) {
TESTCASE(0, TestGetOffsetAroundTransition);
default: name = ""; break;
}
}
/*
* Testing getOffset APIs around rule transition by local standard/wall time.
*/
void
TimeZoneOffsetLocalTest::TestGetOffsetAroundTransition() {
const int32_t NUM_DATES = 10;
const int32_t NUM_TIMEZONES = 3;
const int32_t HOUR = 60*60*1000;
const int32_t MINUTE = 60*1000;
const int32_t DATES[NUM_DATES][6] = {
{2006, UCAL_APRIL, 2, 1, 30, 1*HOUR+30*MINUTE},
{2006, UCAL_APRIL, 2, 2, 00, 2*HOUR},
{2006, UCAL_APRIL, 2, 2, 30, 2*HOUR+30*MINUTE},
{2006, UCAL_APRIL, 2, 3, 00, 3*HOUR},
{2006, UCAL_APRIL, 2, 3, 30, 3*HOUR+30*MINUTE},
{2006, UCAL_OCTOBER, 29, 0, 30, 0*HOUR+30*MINUTE},
{2006, UCAL_OCTOBER, 29, 1, 00, 1*HOUR},
{2006, UCAL_OCTOBER, 29, 1, 30, 1*HOUR+30*MINUTE},
{2006, UCAL_OCTOBER, 29, 2, 00, 2*HOUR},
{2006, UCAL_OCTOBER, 29, 2, 30, 2*HOUR+30*MINUTE},
};
// Expected offsets by int32_t getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
// uint8_t dayOfWeek, int32_t millis, UErrorCode& status)
const int32_t OFFSETS1[NUM_DATES] = {
// April 2, 2006
-8*HOUR,
-7*HOUR,
-7*HOUR,
-7*HOUR,
-7*HOUR,
// October 29, 2006
-7*HOUR,
-8*HOUR,
-8*HOUR,
-8*HOUR,
-8*HOUR,
};
// Expected offsets by void getOffset(UDate date, UBool local, int32_t& rawOffset,
// int32_t& dstOffset, UErrorCode& ec) with local=TRUE
// or void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
// int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with
// nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard
const int32_t OFFSETS2[NUM_DATES][2] = {
// April 2, 2006
{-8*HOUR, 0},
{-8*HOUR, 0},
{-8*HOUR, 0},
{-8*HOUR, 1*HOUR},
{-8*HOUR, 1*HOUR},
// Oct 29, 2006
{-8*HOUR, 1*HOUR},
{-8*HOUR, 0},
{-8*HOUR, 0},
{-8*HOUR, 0},
{-8*HOUR, 0},
};
// Expected offsets by void getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt,
// int32_t duplicatedTimeOpt, int32_t& rawOffset, int32_t& dstOffset, UErrorCode& status) with
// nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight
const int32_t OFFSETS3[][2] = {
// April 2, 2006
{-8*HOUR, 0},
{-8*HOUR, 1*HOUR},
{-8*HOUR, 1*HOUR},
{-8*HOUR, 1*HOUR},
{-8*HOUR, 1*HOUR},
// October 29, 2006
{-8*HOUR, 1*HOUR},
{-8*HOUR, 1*HOUR},
{-8*HOUR, 1*HOUR},
{-8*HOUR, 0},
{-8*HOUR, 0},
};
UErrorCode status = U_ZERO_ERROR;
int32_t rawOffset, dstOffset;
TimeZone* utc = TimeZone::createTimeZone("UTC");
Calendar* cal = Calendar::createInstance(*utc, status);
if (U_FAILURE(status)) {
errln("Calendar::createInstance failed");
return;
}
cal->clear();
// Set up TimeZone objects - OlsonTimeZone, SimpleTimeZone and RuleBasedTimeZone
BasicTimeZone *TESTZONES[NUM_TIMEZONES];
TESTZONES[0] = (BasicTimeZone*)TimeZone::createTimeZone("America/Los_Angeles");
TESTZONES[1] = new SimpleTimeZone(-8*HOUR, "Simple Pacific Time",
UCAL_APRIL, 1, UCAL_SUNDAY, 2*HOUR,
UCAL_OCTOBER, -1, UCAL_SUNDAY, 2*HOUR, status);
if (U_FAILURE(status)) {
errln("SimpleTimeZone constructor failed");
return;
}
InitialTimeZoneRule *ir = new InitialTimeZoneRule(
"Pacific Standard Time", // Initial time Name
-8*HOUR, // Raw offset
0*HOUR); // DST saving amount
RuleBasedTimeZone *rbPT = new RuleBasedTimeZone("Rule based Pacific Time", ir);
DateTimeRule *dtr;
AnnualTimeZoneRule *atzr;
const int32_t STARTYEAR = 2000;
dtr = new DateTimeRule(UCAL_APRIL, 1, UCAL_SUNDAY,
2*HOUR, DateTimeRule::WALL_TIME); // 1st Sunday in April, at 2AM wall time
atzr = new AnnualTimeZoneRule("Pacific Daylight Time",
-8*HOUR /* rawOffset */, 1*HOUR /* dstSavings */, dtr,
STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
rbPT->addTransitionRule(atzr, status);
if (U_FAILURE(status)) {
errln("Could not add DST start rule to the RuleBasedTimeZone rbPT");
return;
}
dtr = new DateTimeRule(UCAL_OCTOBER, -1, UCAL_SUNDAY,
2*HOUR, DateTimeRule::WALL_TIME); // last Sunday in October, at 2AM wall time
atzr = new AnnualTimeZoneRule("Pacific Standard Time",
-8*HOUR /* rawOffset */, 0 /* dstSavings */, dtr,
STARTYEAR, AnnualTimeZoneRule::MAX_YEAR);
rbPT->addTransitionRule(atzr, status);
if (U_FAILURE(status)) {
errln("Could not add STD start rule to the RuleBasedTimeZone rbPT");
return;
}
rbPT->complete(status);
if (U_FAILURE(status)) {
errln("complete() failed for RuleBasedTimeZone rbPT");
return;
}
TESTZONES[2] = rbPT;
// Calculate millis
UDate MILLIS[NUM_DATES];
for (int32_t i = 0; i < NUM_DATES; i++) {
cal->clear();
cal->set(DATES[i][0], DATES[i][1], DATES[i][2], DATES[i][3], DATES[i][4]);
MILLIS[i] = cal->getTime(status);
if (U_FAILURE(status)) {
errln("cal->getTime failed");
return;
}
}
SimpleDateFormat df(UnicodeString("yyyy-MM-dd HH:mm:ss"), status);
if (U_FAILURE(status)) {
errln("Failed to initialize a SimpleDateFormat");
}
df.setTimeZone(*utc);
UnicodeString dateStr;
// Test getOffset(uint8_t era, int32_t year, int32_t month, int32_t day,
// uint8_t dayOfWeek, int32_t millis, UErrorCode& status)
for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
for (int32_t d = 0; d < NUM_DATES; d++) {
status = U_ZERO_ERROR;
int32_t offset = TESTZONES[i]->getOffset(GregorianCalendar::AD, DATES[d][0], DATES[d][1], DATES[d][2],
UCAL_SUNDAY, DATES[d][5], status);
if (U_FAILURE(status)) {
errln((UnicodeString)"getOffset(era,year,month,day,dayOfWeek,millis,status) failed for TESTZONES[" + i + "]");
} else if (offset != OFFSETS1[d]) {
dateStr.remove();
df.format(MILLIS[d], dateStr);
errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ dateStr + "(standard) - Got: " + offset + " Expected: " + OFFSETS1[d]);
}
}
}
// Test getOffset(UDate date, UBool local, int32_t& rawOffset,
// int32_t& dstOffset, UErrorCode& ec) with local = TRUE
for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
for (int32_t m = 0; m < NUM_DATES; m++) {
status = U_ZERO_ERROR;
TESTZONES[i]->getOffset(MILLIS[m], TRUE, rawOffset, dstOffset, status);
if (U_FAILURE(status)) {
errln((UnicodeString)"getOffset(date,local,rawOfset,dstOffset,ec) failed for TESTZONES[" + i + "]");
} else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
dateStr.remove();
df.format(MILLIS[m], dateStr);
errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ dateStr + "(wall) - Got: "
+ rawOffset + "/" + dstOffset
+ " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
}
}
}
// Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
// int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
// with nonExistingTimeOpt=kStandard/duplicatedTimeOpt=kStandard
for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
for (int m = 0; m < NUM_DATES; m++) {
status = U_ZERO_ERROR;
TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kStandard, BasicTimeZone::kStandard,
rawOffset, dstOffset, status);
if (U_FAILURE(status)) {
errln((UnicodeString)"getOffsetFromLocal with kStandard/kStandard failed for TESTZONES[" + i + "]");
} else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
dateStr.remove();
df.format(MILLIS[m], dateStr);
errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ dateStr + "(wall/kStandard/kStandard) - Got: "
+ rawOffset + "/" + dstOffset
+ " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
}
}
}
// Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
// int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
// with nonExistingTimeOpt=kDaylight/duplicatedTimeOpt=kDaylight
for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
for (int m = 0; m < NUM_DATES; m++) {
status = U_ZERO_ERROR;
TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kDaylight, BasicTimeZone::kDaylight,
rawOffset, dstOffset, status);
if (U_FAILURE(status)) {
errln((UnicodeString)"getOffsetFromLocal with kDaylight/kDaylight failed for TESTZONES[" + i + "]");
} else if (rawOffset != OFFSETS3[m][0] || dstOffset != OFFSETS3[m][1]) {
dateStr.remove();
df.format(MILLIS[m], dateStr);
errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ dateStr + "(wall/kDaylight/kDaylight) - Got: "
+ rawOffset + "/" + dstOffset
+ " Expected: " + OFFSETS3[m][0] + "/" + OFFSETS3[m][1]);
}
}
}
// Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
// int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
// with nonExistingTimeOpt=kFormer/duplicatedTimeOpt=kLatter
for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
for (int m = 0; m < NUM_DATES; m++) {
status = U_ZERO_ERROR;
TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kFormer, BasicTimeZone::kLatter,
rawOffset, dstOffset, status);
if (U_FAILURE(status)) {
errln((UnicodeString)"getOffsetFromLocal with kFormer/kLatter failed for TESTZONES[" + i + "]");
} else if (rawOffset != OFFSETS2[m][0] || dstOffset != OFFSETS2[m][1]) {
dateStr.remove();
df.format(MILLIS[m], dateStr);
errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ dateStr + "(wall/kFormer/kLatter) - Got: "
+ rawOffset + "/" + dstOffset
+ " Expected: " + OFFSETS2[m][0] + "/" + OFFSETS2[m][1]);
}
}
}
// Test getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_t duplicatedTimeOpt,
// int32_t& rawOffset, int32_t& dstOffset, UErroCode& status)
// with nonExistingTimeOpt=kLatter/duplicatedTimeOpt=kFormer
for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
for (int m = 0; m < NUM_DATES; m++) {
status = U_ZERO_ERROR;
TESTZONES[i]->getOffsetFromLocal(MILLIS[m], BasicTimeZone::kLatter, BasicTimeZone::kFormer,
rawOffset, dstOffset, status);
if (U_FAILURE(status)) {
errln((UnicodeString)"getOffsetFromLocal with kLatter/kFormer failed for TESTZONES[" + i + "]");
} else if (rawOffset != OFFSETS3[m][0] || dstOffset != OFFSETS3[m][1]) {
dateStr.remove();
df.format(MILLIS[m], dateStr);
errln((UnicodeString)"Bad offset returned by TESTZONES[" + i + "] at "
+ dateStr + "(wall/kLatter/kFormer) - Got: "
+ rawOffset + "/" + dstOffset
+ " Expected: " + OFFSETS3[m][0] + "/" + OFFSETS3[m][1]);
}
}
}
for (int32_t i = 0; i < NUM_TIMEZONES; i++) {
delete TESTZONES[i];
}
delete utc;
delete cal;
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -0,0 +1,26 @@
/*
*******************************************************************************
* Copyright (C) 2007, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
#ifndef _TIMEZONEOFFSETLOCALTEST_
#define _TIMEZONEOFFSETLOCALTEST_
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "intltest.h"
class TimeZoneOffsetLocalTest : public IntlTest {
// IntlTest override
void runIndexedTest(int32_t index, UBool exec, const char*& name, char* par);
void TestGetOffsetAroundTransition(void);
};
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif // _TIMEZONEOFFSETLOCALTEST_

View file

@ -18,6 +18,7 @@
#include "cmemory.h"
#include "putilimp.h"
#include "cstring.h"
#include "olsontz.h"
#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
@ -755,53 +756,92 @@ void TimeZoneTest::TestShortZoneIDs()
}
}
/**
* Utility function for TestCustomParse
*/
UnicodeString& TimeZoneTest::formatMinutes(int32_t min, UnicodeString& rv, UBool insertSep/*=TRUE*/)
{
rv.remove();
UnicodeString& TimeZoneTest::formatOffset(int32_t offset, UnicodeString &rv) {
rv.remove();
UChar sign = 0x002B;
if (offset < 0) {
sign = 0x002D;
offset = -offset;
}
UChar sign = 0x002B;
if (min < 0) {
sign = 0x002D;
min = -min;
int32_t s = offset % 60;
offset /= 60;
int32_t m = offset % 60;
int32_t h = offset / 60;
rv += (UChar)(sign);
if (h >= 10) {
rv += (UChar)(0x0030 + (h/10));
} else {
rv += (UChar)0x0030;
}
rv += (UChar)(0x0030 + (h%10));
rv += (UChar)0x003A; /* ':' */
if (m >= 10) {
rv += (UChar)(0x0030 + (m/10));
} else {
rv += (UChar)0x0030;
}
rv += (UChar)(0x0030 + (m%10));
if (s) {
rv += (UChar)0x003A; /* ':' */
if (s >= 10) {
rv += (UChar)(0x0030 + (s/10));
} else {
rv += (UChar)0x0030;
}
int h = min/60;
min = min%60;
rv += (UChar)(sign);
if(h >= 10)
rv += (UChar)(0x0030 + (h/10));
else
rv += "0";
rv += (UChar)(0x0030 + (h%10));
if (insertSep)
rv += ":";
if(min >= 10)
rv += (UChar)(0x0030 + (min/10));
else
rv += "0";
rv += (UChar)(0x0030 + (min%10));
return rv;
rv += (UChar)(0x0030 + (s%10));
}
return rv;
}
/**
* Utility function for TestCustomParse, generating RFC822 style
* time zone string for the give offset in minutes
* Utility function for TestCustomParse, generating time zone ID
* string for the give offset.
*/
UnicodeString& TimeZoneTest::formatRFC822TZ(int32_t min, UnicodeString& rv)
{
UnicodeString offsetStr;
formatMinutes(min, offsetStr, FALSE);
UnicodeString& TimeZoneTest::formatTZID(int32_t offset, UnicodeString &rv) {
rv.remove();
UChar sign = 0x002B;
if (offset < 0) {
sign = 0x002D;
offset = -offset;
}
int32_t s = offset % 60;
offset /= 60;
int32_t m = offset % 60;
int32_t h = offset / 60;
rv += "GMT";
rv += offsetStr;
rv += (UChar)(sign);
if (h >= 10) {
rv += (UChar)(0x0030 + (h/10));
} else {
rv += (UChar)0x0030;
}
rv += (UChar)(0x0030 + (h%10));
if (m >= 10) {
rv += (UChar)(0x0030 + (m/10));
} else {
rv += (UChar)0x0030;
}
rv += (UChar)(0x0030 + (m%10));
if (s) {
if (s >= 10) {
rv += (UChar)(0x0030 + (s/10));
} else {
rv += (UChar)0x0030;
}
rv += (UChar)(0x0030 + (s%10));
}
return rv;
}
@ -825,92 +865,63 @@ void TimeZoneTest::TestCustomParse()
}
kData[] =
{
// ID Expected offset in minutes
//{"GMT", kUnparseable}, //Isn't custom. Can't test it here. [returns normal GMT]
// ID Expected offset in seconds
{"GMT", kUnparseable}, //Isn't custom. [returns normal GMT]
{"GMT-YOUR.AD.HERE", kUnparseable},
// {"GMT0", kUnparseable}, // ICU 2.8: An Olson zone ID
// {"GMT+0", (0)}, // ICU 2.8: An Olson zone ID
{"GMT+1", (60)},
{"GMT-0030", (-30)},
{"GMT0", kUnparseable},
{"GMT+0", (0)},
{"GMT+1", (1*60*60)},
{"GMT-0030", (-30*60)},
{"GMT+15:99", kUnparseable},
{"GMT+", kUnparseable},
{"GMT-", kUnparseable},
{"GMT+0:", kUnparseable},
{"GMT-:", kUnparseable},
{"GMT-YOUR.AD.HERE", kUnparseable},
{"GMT+0010", (10)}, // Interpret this as 00:10
{"GMT-10", (-10*60)},
{"GMT+30", (30)},
{"GMT-3:30", (-(3*60+30))},
{"GMT-230", (-(2*60+30))},
{"GMT-YOUR.AD.HERE", kUnparseable},
{"GMT+0010", (10*60)}, // Interpret this as 00:10
{"GMT-10", (-10*60*60)},
{"GMT+30", kUnparseable},
{"GMT-3:30", (-(3*60+30)*60)},
{"GMT-230", (-(2*60+30)*60)},
{"GMT+05:13:05", ((5*60+13)*60+5)},
{"GMT-71023", (-((7*60+10)*60+23))},
{"GMT+01:23:45:67", kUnparseable},
{"GMT+01:234", kUnparseable},
{"GMT-2:31:123", kUnparseable},
{"GMT+3:75", kUnparseable},
{"GMT-01010101", kUnparseable},
{0, 0}
};
for (i=0; kData[i].customId != 0; i++)
{
for (i=0; kData[i].customId != 0; i++) {
UnicodeString id(kData[i].customId);
int32_t exp = kData[i].expectedOffset;
/*
{ // for no data test Jitterbug 4354
UErrorCode success = U_ZERO_ERROR;
NumberFormat* numberFormat = NumberFormat::createInstance(success);
if (U_FAILURE(success)) {
dataerrln(" NumberFormat::createInstance() error");
return;
}
delete numberFormat;
}
*/
TimeZone *zone = TimeZone::createTimeZone(id);
UnicodeString itsID, temp;
logln();
logln("testing # " + formatMinutes(i, temp) + id);
/*
if(zone == NULL)
{
errln("FAIL: Could not createTimeZone(" + id + "). Returned NULL.");
continue;
}
*/
if (! zone->getID(itsID).compare("GMT"))
//if(zone == NULL)
{
logln(id + " -> generic GMT");
// When TimeZone.getTimeZone() can't parse the id, it
// returns GMT -- a dubious practice, but required for
// backward compatibility.
if (exp != kUnparseable) {
errln("FAIL: Expected offset of " + formatMinutes(exp,temp) +
" for " + id + ", got parse failure");
}
}
else
{
if (zone->getDynamicClassID() == OlsonTimeZone::getStaticClassID()) {
logln(id + " -> Olson time zone");
} else {
zone->getID(itsID);
int32_t ioffset = zone->getRawOffset()/60000;
int32_t ioffset = zone->getRawOffset()/1000;
UnicodeString offset, expectedID;
formatMinutes(ioffset, offset);
formatRFC822TZ(ioffset, expectedID);
logln(id + " -> " + itsID + " GMT" + offset);
if (exp == kUnparseable)
{
errln("FAIL: Expected parse failure for " + id +
", got offset of " + offset +
", id " + itsID);
formatOffset(ioffset, offset);
formatTZID(ioffset, expectedID);
logln(id + " -> " + itsID + " " + offset);
if (exp == kUnparseable && itsID != "GMT") {
errln("Expected parse failure for " + id +
", got offset of " + offset +
", id " + itsID);
}
else if (ioffset != exp ||
(itsID.compare(expectedID) != 0))
{
errln("Expected offset of " + formatMinutes(exp,temp) +
", id " + expectedID +
", for " + id +
", got offset of " + offset +
", id " + itsID);
// JDK 1.3 creates custom zones with the ID "Custom"
// JDK 1.4 creates custom zones with IDs of the form "GMT+02:00"
// ICU creates custom zones with IDs of the form "GMT+0200"
else if (exp != kUnparseable && (ioffset != exp || itsID != expectedID)) {
errln("Expected offset of " + formatOffset(exp, temp) +
", id " + expectedID +
", for " + id +
", got offset of " + offset +
", id " + itsID);
}
}
delete zone;

View file

@ -92,8 +92,8 @@ public:
private:
// internal functions
static UnicodeString& formatMinutes(int32_t min, UnicodeString& rv, UBool insertSep = TRUE);
static UnicodeString& formatRFC822TZ(int32_t min, UnicodeString& rv);
static UnicodeString& formatOffset(int32_t offset, UnicodeString& rv);
static UnicodeString& formatTZID(int32_t offset, UnicodeString& rv);
};
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -1897,6 +1897,7 @@ structLocale:table(nofallback){
ypk{""}
za{""}
zap{""}
zbl{""}
zen{""}
zh{""}
zh_Hans{""}
@ -1938,6 +1939,7 @@ structLocale:table(nofallback){
Scripts{
Arab{""}
Armn{""}
Avst{""}
Bali{""}
Batk{""}
Beng{""}
@ -2001,6 +2003,7 @@ structLocale:table(nofallback){
Lyci{""}
Lydi{""}
Mand{""}
Mani{""}
Maya{""}
Mero{""}
Mlym{""}
@ -2016,12 +2019,14 @@ structLocale:table(nofallback){
Osma{""}
Perm{""}
Phag{""}
Phlv{""}
Phnx{""}
Plrd{""}
Qaai{""}
Rjng{""}
Roro{""}
Runr{""}
Samr{""}
Sara{""}
Saur{""}
Sgnw{""}
@ -2080,6 +2085,7 @@ structLocale:table(nofallback){
1606NICT{""}
1694ACAD{""}
1901{""}
1994{""}
1996{""}
AREVELA{""}
AREVMDA{""}
@ -2091,6 +2097,7 @@ structLocale:table(nofallback){
GAULISH{""}
GUOYU{""}
HAKKA{""}
LIPAW{""}
LOJBAN{""}
MONOTON{""}
NEDIS{""}
@ -2102,6 +2109,7 @@ structLocale:table(nofallback){
REVISED{""}
ROZAJ{""}
SAAHO{""}
SCOTLAND{""}
SCOUSE{""}
SOLBA{""}
TARASK{""}