001    package railo.commons.date;
002    
003    import java.util.Calendar;
004    import java.util.HashMap;
005    import java.util.Map;
006    import java.util.TimeZone;
007    
008    import railo.commons.lang.StringUtil;
009    import railo.runtime.engine.ThreadLocalPageContext;
010    import railo.runtime.exp.ExpressionException;
011    import railo.runtime.op.Caster;
012    import railo.runtime.type.util.ListUtil;
013    
014    public class TimeZoneUtil {
015    
016            private static final Map<String,TimeZone> IDS=new HashMap<String,TimeZone>();
017            
018            static {
019                    String[] ids=TimeZone.getAvailableIDs();
020                    for(int i=0;i<ids.length;i++){
021                            IDS.put(ids[i].toLowerCase(), TimeZone.getTimeZone(ids[i]));
022                    }
023                    TimeZone def = TimeZone.getDefault();
024                    if(def!=null)IDS.put(def.getID(),def);
025                    IDS.put("jvm", TimeZone.getDefault());
026                    IDS.put("default", TimeZone.getDefault());
027                    IDS.put("", TimeZone.getDefault());
028    
029                    // MS specific Timezone definions
030                    set("Dateline Standard Time",TimeZoneConstants.ETC_GMT_PLUS_12); // (GMT-12:00) International Date Line West
031                    set("Samoa Standard Time",TimeZoneConstants.PACIFIC_MIDWAY); //         (GMT-11:00) Midway Island, Samoa
032                    set("Hawaiian Standard Time",TimeZoneConstants.HST); // (GMT-10:00) Hawaii
033                    set("Alaskan Standard Time",TimeZoneConstants.AST); // (GMT-09:00) Alaska
034                    set("Pacific Standard Time",TimeZoneConstants.PST); // (GMT-08:00) Pacific Time (US and Canada); Tijuana
035                    set("Mountain Standard Time",TimeZoneConstants.MST); // (GMT-07:00) Mountain Time (US and Canada)
036                    set("Mexico Standard Time",TimeZoneConstants.MEXICO_GENERAL); // (GMT-06:00) Guadalajara, Mexico City, Monterrey
037                    set("Mexico Standard Time 2",TimeZoneConstants.AMERICA_CHIHUAHUA); // (GMT-07:00) Chihuahua, La Paz, Mazatlan
038                    set("U.S. Mountain Standard Time",TimeZoneConstants.MST); // (GMT-07:00) Arizona
039                    set("Central Standard Time",TimeZoneConstants.CST); // (GMT-06:00) Central Time (US and Canada
040                    set("Canada Central Standard Time",TimeZoneConstants.CANADA_CENTRAL); // (GMT-06:00) Saskatchewan
041                    set("Central America Standard Time",TimeZoneConstants.CST); // (GMT-06:00) Central America
042                    set("Eastern Standard Time",TimeZoneConstants.EST); // (GMT-05:00) Eastern Time (US and Canada)
043                    set("U.S. Eastern Standard Time",TimeZoneConstants.EST); // (GMT-05:00) Indiana (East)
044                    set("S.A. Pacific Standard Time",TimeZoneConstants.AMERICA_BOGOTA); // (GMT-05:00) Bogota, Lima, Quito
045                    set("Atlantic Standard Time",TimeZoneConstants.CANADA_ATLANTIC); // (GMT-04:00) Atlantic Time (Canada)
046                    set("S.A. Western Standard Time",TimeZoneConstants.AMERICA_ANTIGUA); // (GMT-04:00) Caracas, La Paz
047                    set("Pacific S.A. Standard Time",TimeZoneConstants.AMERICA_SANTIAGO); // (GMT-04:00) Santiago
048                    set("Newfoundland and Labrador Standard Time",TimeZoneConstants.CNT); // (GMT-03:30) Newfoundland and Labrador
049                    set("E. South America Standard Time",TimeZoneConstants.BET); // (GMT-03:00) Brasilia
050                    set("S.A. Eastern Standard Time",TimeZoneConstants.AMERICA_ARGENTINA_BUENOS_AIRES); // (GMT-03:00) Buenos Aires, Georgetown
051                    set("Greenland Standard Time",TimeZoneConstants.AMERICA_GODTHAB); // (GMT-03:00) Greenland
052                    set("Mid-Atlantic Standard Time",TimeZoneConstants.AMERICA_NORONHA); // (GMT-02:00) Mid-Atlantic
053                    set("Azores Standard Time",TimeZoneConstants.ATLANTIC_AZORES); // (GMT-01:00) Azores
054                    set("Cape Verde Standard Time",TimeZoneConstants.ATLANTIC_CAPE_VERDE); // (GMT-01:00) Cape Verde Islands
055                    set("Central Europe Standard Time",TimeZoneConstants.CET); // (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague
056                    set("Central European Standard Time",TimeZoneConstants.CET); // (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb
057                    set("Romance Standard Time",TimeZoneConstants.EUROPE_BRUSSELS); // (GMT+01:00) Brussels, Copenhagen, Madrid, Paris
058                    set("W. Europe Standard Time",TimeZoneConstants.CET); // (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna
059                    set("W. Central Africa Standard Time",null); // (GMT+01:00) West Central Africa
060                    set("E. Europe Standard Time",TimeZoneConstants.ART); // (GMT+02:00) Bucharest
061                    set("Egypt Standard Time",TimeZoneConstants.EGYPT); // (GMT+02:00) Cairo
062                    set("FLE Standard Time",TimeZoneConstants.EET); // (GMT+02:00) Helsinki, Kiev, Riga, Sofia, Tallinn, Vilnius
063                    set("GTB Standard Time",TimeZoneConstants.EUROPE_ATHENS); // (GMT+02:00) Athens, Istanbul, Minsk
064                    set("Israel Standard Time",TimeZoneConstants.ASIA_JERUSALEM); // (GMT+02:00) Jerusalem
065                    set("South Africa Standard Time",TimeZoneConstants.AFRICA_JOHANNESBURG); // (GMT+02:00) Harare, Pretoria
066                    set("Russian Standard Time",TimeZoneConstants.EUROPE_MOSCOW); // (GMT+03:00) Moscow, St. Petersburg, Volgograd
067                    set("Arab Standard Time",TimeZoneConstants.ASIA_KUWAIT); // (GMT+03:00) Kuwait, Riyadh
068                    set("E. Africa Standard Time",TimeZoneConstants.AFRICA_NAIROBI); // (GMT+03:00) Nairobi
069                    set("Arabic Standard Time",TimeZoneConstants.ASIA_BAGHDAD); // (GMT+03:00) Baghdad
070                    set("Iran Standard Time",TimeZoneConstants.ASIA_TEHRAN); // (GMT+03:30) Tehran
071                    set("Arabian Standard Time",TimeZoneConstants.ASIA_MUSCAT); // (GMT+04:00) Abu Dhabi, Muscat
072                    set("Caucasus Standard Time",TimeZoneConstants.ASIA_YEREVAN); // (GMT+04:00) Baku, Tbilisi, Yerevan
073                    set("Transitional Islamic State of Afghanistan Standard Time",TimeZoneConstants.ASIA_KABUL); // (GMT+04:30) Kabul
074                    set("Ekaterinburg Standard Time",TimeZoneConstants.ASIA_YEKATERINBURG); // (GMT+05:00) Ekaterinburg
075                    set("West Asia Standard Time",TimeZoneConstants.ASIA_KARACHI); // (GMT+05:00) Islamabad, Karachi, Tashkent
076                    set("India Standard Time",TimeZoneConstants.IST); // (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi
077                    set("Nepal Standard Time",TimeZoneConstants.ASIA_KATMANDU); // (GMT+05:45) Kathmandu
078                    set("Central Asia Standard Time",TimeZoneConstants.ASIA_DHAKA); //(GMT+06:00) Astana, Dhaka 
079                    set("Sri Lanka Standard Time",TimeZoneConstants.ASIA_COLOMBO); // (GMT+06:00) Sri Jayawardenepura
080                    set("N. Central Asia Standard Time",TimeZoneConstants.ASIA_ALMATY); // (GMT+06:00) Almaty, Novosibirsk
081                    set("Myanmar Standard Time",TimeZoneConstants.ASIA_RANGOON); // (GMT+06:30) Yangon Rangoon
082                    set("S.E. Asia Standard Time",TimeZoneConstants.ASIA_BANGKOK); // (GMT+07:00) Bangkok, Hanoi, Jakarta
083                    set("North Asia Standard Time",TimeZoneConstants.ASIA_KRASNOYARSK); // (GMT+07:00) Krasnoyarsk
084                    set("China Standard Time",TimeZoneConstants.CTT); // (GMT+08:00) Beijing, Chongqing, Hong Kong SAR, Urumqi
085                    set("Singapore Standard Time",TimeZoneConstants.ASIA_SINGAPORE); // (GMT+08:00) Kuala Lumpur, Singapore
086                    set("Taipei Standard Time",TimeZoneConstants.ASIA_TAIPEI); // (GMT+08:00) Taipei
087                    set("W. Australia Standard Time",TimeZoneConstants.AUSTRALIA_PERTH); // (GMT+08:00) Perth
088                    set("North Asia East Standard Time",TimeZoneConstants.ASIA_IRKUTSK); // (GMT+08:00) Irkutsk, Ulaanbaatar
089                    set("Korea Standard Time",TimeZoneConstants.ASIA_SEOUL); // (GMT+09:00) Seoul
090                    set("Tokyo Standard Time",TimeZoneConstants.ASIA_TOKYO); // (GMT+09:00) Osaka, Sapporo, Tokyo
091                    set("Yakutsk Standard Time",TimeZoneConstants.ASIA_YAKUTSK); // (GMT+09:00) Yakutsk
092                    set("A.U.S. Central Standard Time",TimeZoneConstants.ACT); // (GMT+09:30) Darwin
093                    set("Cen. Australia Standard Time",TimeZoneConstants.ACT); // (GMT+09:30) Adelaide
094                    set("A.U.S. Eastern Standard Time",TimeZoneConstants.AET); // (GMT+10:00) Canberra, Melbourne, Sydney
095                    set("E. Australia Standard Time",TimeZoneConstants.AET); // (GMT+10:00) Brisbane
096                    set("Tasmania Standard Time",TimeZoneConstants.AUSTRALIA_TASMANIA); // (GMT+10:00) Hobart
097                    set("Vladivostok Standard Time",TimeZoneConstants.ASIA_VLADIVOSTOK); // (GMT+10:00) Vladivostok
098                    set("West Pacific Standard Time",TimeZoneConstants.PACIFIC_GUAM); // (GMT+10:00) Guam, Port Moresby
099                    set("Central Pacific Standard Time",TimeZoneConstants.ASIA_MAGADAN); // (GMT+11:00) Magadan, Solomon Islands, New Caledonia
100                    set("Fiji Islands Standard Time",TimeZoneConstants.PACIFIC_FIJI); // (GMT+12:00) Fiji Islands, Kamchatka, Marshall Islands
101                    set("New Zealand Standard Time",TimeZoneConstants.NZ); // (GMT+12:00) Auckland, Wellington
102                    set("Tonga Standard Time",TimeZoneConstants.PACIFIC_TONGATAPU); // (GMT+13:00) Nuku'alofa
103                    
104                    
105            }
106            
107            private static void set(String name, TimeZone tz) {
108                    if(tz==null) return;
109                    name=StringUtil.replace(name.trim().toLowerCase(), " ", "", false);
110                    IDS.put(name.toLowerCase(), tz);
111            }
112    
113            /**
114             * return the string format of the Timezone
115             * @param timezone
116             * @return
117             */
118            public static String toString(TimeZone timezone){
119                    return timezone.getID();
120            }
121    
122            private static String getSupportedTimeZonesAsString() {
123                    return ListUtil.arrayToList(TimeZone.getAvailableIDs(),", ");
124            }
125            
126            /**
127             * translate timezone string format to a timezone
128             * @param strTimezone
129             * @return
130             */
131            public static TimeZone toTimeZone(String strTimezone,TimeZone defaultValue){
132                    if(strTimezone==null) return defaultValue;
133                    strTimezone=StringUtil.replace(strTimezone.trim().toLowerCase(), " ", "", false);
134                    TimeZone tz = IDS.get(strTimezone);
135                    if(tz!=null) return tz;
136                    
137                    //parse GMT followd by a number
138                    float gmtOffset=Float.NaN;
139                    if(strTimezone.startsWith("gmt")) gmtOffset=getGMTOffset(strTimezone.substring(3).trim(),Float.NaN);
140                    else if(strTimezone.startsWith("etc/gmt")) gmtOffset=getGMTOffset(strTimezone.substring(7).trim(),Float.NaN);
141                    else if(strTimezone.startsWith("utc")) gmtOffset=getGMTOffset(strTimezone.substring(3).trim(),Float.NaN);
142                    else if(strTimezone.startsWith("etc/utc")) gmtOffset=getGMTOffset(strTimezone.substring(7).trim(),Float.NaN);
143                    
144    
145                    
146                    if(!Float.isNaN(gmtOffset)) {
147                            strTimezone="etc/gmt"+(gmtOffset>=0?"+":"")+Caster.toString(gmtOffset);
148                            tz =  IDS.get(strTimezone);
149                            if(tz!=null) return tz;
150                            
151                    }
152                    
153                    
154                    
155                    
156                    return defaultValue;
157            }
158            
159            private static float getGMTOffset(String str, float defaultValue) {
160                    int index;
161                    String left=null,right=null;
162                    if((index=str.indexOf(':'))!=-1) {
163                            left = str.substring(0,index);
164                            right=str.substring(index+1);
165                    }
166                    else if(str.startsWith("-")) {
167                            if(str.length()>=4 && str.indexOf('.')==-1){
168                                    left = str.substring(0,str.length()-2);
169                                    right=str.substring(str.length()-2);
170                            }
171                    }
172                    else if(str.length()>=3 && str.indexOf('.')==-1) {
173                            left = str.substring(0,str.length()-2);
174                            right=str.substring(str.length()-2);
175                    }
176                    if(left!=null) {
177                            int l = Caster.toIntValue(left,Integer.MIN_VALUE);
178                            int r = Caster.toIntValue(right,Integer.MIN_VALUE);
179                            if(l==Integer.MIN_VALUE || r==Integer.MIN_VALUE || r>59) return defaultValue;
180                            return l+(r/60f);
181                    }
182                    
183                    
184                    float f=Caster.toFloatValue(str,Float.NaN);
185                    if(Float.isNaN(f)) return defaultValue;
186                    return f;
187            }
188    
189            public static TimeZone toTimeZone(String strTimezone) throws ExpressionException{
190                    TimeZone tz = toTimeZone(strTimezone, null);
191                    if(tz!=null) return tz;
192                    throw new ExpressionException("can't cast value ("+strTimezone+") to a TimeZone","supported TimeZones are:"+getSupportedTimeZonesAsString());
193            }
194    
195            public static Calendar getCalendar(TimeZone tz) {
196                    return Calendar.getInstance(ThreadLocalPageContext.getTimeZone(tz));
197            }
198    }