Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   *  Copyright 2001-2010 Stephen Colebourne
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
 package org.joda.time.tz;
 
 import java.io.File;
 import java.util.List;
 import java.util.Map;
 
Compiles Olson ZoneInfo database files into binary files for each time zone in the database. DateTimeZoneBuilder is used to construct and encode compiled data files. ZoneInfoProvider loads the encoded files and converts them back into org.joda.time.DateTimeZone objects.

Although this tool is similar to zic, the binary formats are not compatible. The latest Olson database files may be obtained here.

ZoneInfoCompiler is mutable and not thread-safe, although the main method may be safely invoked by multiple threads.

Author(s):
Brian S O'Neill
Since:
1.0
 
 public class ZoneInfoCompiler {
     static DateTimeOfYear cStartOfYear;
 
     static Chronology cLenientISO;
 
     static ThreadLocal<BooleancVerbose = new ThreadLocal<Boolean>();
     static {
         .set(.);
     }

    
Gets a flag indicating that verbose logging is required.

Returns:
true to log verbosely
 
     public static boolean verbose() {
         return .get();
     }
 
     //-----------------------------------------------------------------------
     
Launches the ZoneInfoCompiler tool.
 Usage: java org.joda.time.tz.ZoneInfoCompiler <options> <source files>
 where possible options include:
   -src <directory>    Specify where to read source files
   -dst <directory>    Specify where to write generated files
   -verbose            Output verbosely (default false)
 
 
     public static void main(String[] argsthrows Exception {
         if (args.length == 0) {
             printUsage();
             return;
         }
 
         File inputDir = null;
        File outputDir = null;
        boolean verbose = false;
        int i;
        for (i=0; i<args.lengthi++) {
            try {
                if ("-src".equals(args[i])) {
                    inputDir = new File(args[++i]);
                } else if ("-dst".equals(args[i])) {
                    outputDir = new File(args[++i]);
                } else if ("-verbose".equals(args[i])) {
                    verbose = true;
                } else if ("-?".equals(args[i])) {
                    printUsage();
                    return;
                } else {
                    break;
                }
            } catch (IndexOutOfBoundsException e) {
                printUsage();
                return;
            }
        }
        if (i >= args.length) {
            printUsage();
            return;
        }
        File[] sources = new File[args.length - i];
        for (int j=0; i<args.lengthi++,j++) {
            sources[j] = inputDir == null ? new File(args[i]) : new File(inputDirargs[i]);
        }
        .set(verbose);
        ZoneInfoCompiler zic = new ZoneInfoCompiler();
        zic.compile(outputDirsources);
    }
    private static void printUsage() {
        ..println("Usage: java org.joda.time.tz.ZoneInfoCompiler <options> <source files>");
        ..println("where possible options include:");
        ..println("  -src <directory>    Specify where to read source files");
        ..println("  -dst <directory>    Specify where to write generated files");
        ..println("  -verbose            Output verbosely (default false)");
    }
    static DateTimeOfYear getStartOfYear() {
        if ( == null) {
             = new DateTimeOfYear();
        }
        return ;
    }
        if ( == null) {
             = LenientChronology.getInstance(ISOChronology.getInstanceUTC());
        }
        return ;
    }

    

Parameters:
zimap maps string ids to DateTimeZone objects.
    static void writeZoneInfoMap(DataOutputStream doutMap<StringDateTimeZonezimapthrows IOException {
        // Build the string pool.
        Map<StringShortidToIndex = new HashMap<StringShort>(zimap.size());
        TreeMap<ShortStringindexToId = new TreeMap<ShortString>();
        short count = 0;
        for (Entry<StringDateTimeZoneentry : zimap.entrySet()) {
            String id = (String)entry.getKey();
            if (!idToIndex.containsKey(id)) {
                Short index = Short.valueOf(count);
                idToIndex.put(idindex);
                indexToId.put(indexid);
                if (++count == 0) {
                    throw new InternalError("Too many time zone ids");
                }
            }
            id = ((DateTimeZone)entry.getValue()).getID();
            if (!idToIndex.containsKey(id)) {
                Short index = Short.valueOf(count);
                idToIndex.put(idindex);
                indexToId.put(indexid);
                if (++count == 0) {
                    throw new InternalError("Too many time zone ids");
                }
            }
        }
        // Write the string pool, ordered by index.
        dout.writeShort(indexToId.size());
        for (String id : indexToId.values()) {
            dout.writeUTF(id);
        }
        // Write the mappings.
        dout.writeShort(zimap.size());
        for (Entry<StringDateTimeZoneentry : zimap.entrySet()) {
            String id = entry.getKey();
            dout.writeShort(idToIndex.get(id).shortValue());
            id = entry.getValue().getID();
            dout.writeShort(idToIndex.get(id).shortValue());
        }
    }
    static int parseYear(String strint def) {
        str = str.toLowerCase();
        if (str.equals("minimum") || str.equals("min")) {
            return .;
        } else if (str.equals("maximum") || str.equals("max")) {
            return .;
        } else if (str.equals("only")) {
            return def;
        }
        return Integer.parseInt(str);
    }
    static int parseMonth(String str) {
        DateTimeField field = ISOChronology.getInstanceUTC().monthOfYear();
        return field.get(field.set(0, str.));
    }
    static int parseDayOfWeek(String str) {
        DateTimeField field = ISOChronology.getInstanceUTC().dayOfWeek();
        return field.get(field.set(0, str.));
    }
    
    static String parseOptional(String str) {
        return (str.equals("-")) ? null : str;
    }
    static int parseTime(String str) {
        DateTimeFormatter p = ISODateTimeFormat.hourMinuteSecondFraction();
        MutableDateTime mdt = new MutableDateTime(0, getLenientISOChronology());
        int pos = 0;
        if (str.startsWith("-")) {
            pos = 1;
        }
        int newPos = p.parseInto(mdtstrpos);
        if (newPos == ~pos) {
            throw new IllegalArgumentException(str);
        }
        int millis = (int)mdt.getMillis();
        if (pos == 1) {
            millis = -millis;
        }
        return millis;
    }
    static char parseZoneChar(char c) {
        switch (c) {
        case 's'case 'S':
            // Standard time
            return 's';
        case 'u'case 'U'case 'g'case 'G'case 'z'case 'Z':
            // UTC
            return 'u';
        case 'w'case 'W'default:
            // Wall time
            return 'w';
        }
    }

    

Returns:
false if error.
    static boolean test(String idDateTimeZone tz) {
        if (!id.equals(tz.getID())) {
            return true;
        }
        // Test to ensure that reported transitions are not duplicated.
        long millis = ISOChronology.getInstanceUTC().year().set(0, 1850);
        long end = ISOChronology.getInstanceUTC().year().set(0, 2050);
        int offset = tz.getOffset(millis);
        String key = tz.getNameKey(millis);
        List<Longtransitions = new ArrayList<Long>();
        while (true) {
            long next = tz.nextTransition(millis);
            if (next == millis || next > end) {
                break;
            }
            millis = next;
            int nextOffset = tz.getOffset(millis);
            String nextKey = tz.getNameKey(millis);
            if (offset == nextOffset
                && key.equals(nextKey)) {
                ..println("*d* Error in " + tz.getID() + " "
                                   + new DateTime(millis,
                                                  ISOChronology.getInstanceUTC()));
                return false;
            }
            if (nextKey == null || (nextKey.length() < 3 && !"??".equals(nextKey))) {
                ..println("*s* Error in " + tz.getID() + " "
                                   + new DateTime(millis,
                                                  ISOChronology.getInstanceUTC())
                                   + ", nameKey=" + nextKey);
                return false;
            }
            transitions.add(Long.valueOf(millis));
            offset = nextOffset;
            key = nextKey;
        }
        // Now verify that reverse transitions match up.
        millis = ISOChronology.getInstanceUTC().year().set(0, 2050);
        end = ISOChronology.getInstanceUTC().year().set(0, 1850);
        for (int i=transitions.size(); --i>= 0; ) {
            long prev = tz.previousTransition(millis);
            if (prev == millis || prev < end) {
                break;
            }
            millis = prev;
            long trans = transitions.get(i).longValue();
            
            if (trans - 1 != millis) {
                ..println("*r* Error in " + tz.getID() + " "
                                   + new DateTime(millis,
                                                  ISOChronology.getInstanceUTC()) + " != "
                                   + new DateTime(trans - 1,
                                                  ISOChronology.getInstanceUTC()));
                                   
                return false;
            }
        }
        return true;
    }
    // Maps names to RuleSets.
    private Map<StringRuleSetiRuleSets;
    // List of Zone objects.
    private List<ZoneiZones;
    // List String pairs to link.
    private List<StringiLinks;
    public ZoneInfoCompiler() {
         = new HashMap<StringRuleSet>();
         = new ArrayList<Zone>();
         = new ArrayList<String>();
    }

    
Returns a map of ids to DateTimeZones.

Parameters:
outputDir optional directory to write compiled data files to
sources optional list of source files to parse
    public Map<StringDateTimeZonecompile(File outputDirFile[] sourcesthrows IOException {
        if (sources != null) {
            for (int i=0; i<sources.lengthi++) {
                BufferedReader in = new BufferedReader(new FileReader(sources[i]));
                parseDataFile(in);
                in.close();
            }
        }
        if (outputDir != null) {
            if (!outputDir.exists()) {
                throw new IOException("Destination directory doesn't exist: " + outputDir);
            }
            if (!outputDir.isDirectory()) {
                throw new IOException("Destination is not a directory: " + outputDir);
            }
        }
        Map<StringDateTimeZonemap = new TreeMap<StringDateTimeZone>();
        ..println("Writing zoneinfo files");
        for (int i=0; i<.size(); i++) {
            Zone zone = .get(i);
            DateTimeZoneBuilder builder = new DateTimeZoneBuilder();
            zone.addToBuilder(builder);
            final DateTimeZone original = builder.toDateTimeZone(zone.iNametrue);
            DateTimeZone tz = original;
            if (test(tz.getID(), tz)) {
                map.put(tz.getID(), tz);
                if (outputDir != null) {
                    if (ZoneInfoCompiler.verbose()) {
                        ..println("Writing " + tz.getID());
                    }
                    File file = new File(outputDirtz.getID());
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                    OutputStream out = new FileOutputStream(file);
                    try {
                        builder.writeTo(zone.iNameout);
                    } finally {
                        out.close();
                    }
                    // Test if it can be read back.
                    InputStream in = new FileInputStream(file);
                    DateTimeZone tz2 = DateTimeZoneBuilder.readFrom(intz.getID());
                    in.close();
                    if (!original.equals(tz2)) {
                        ..println("*e* Error in " + tz.getID() +
                                           ": Didn't read properly from file");
                    }
                }
            }
        }
        for (int pass=0; pass<2; pass++) {
            for (int i=0; i<.size(); i += 2) {
                String id = .get(i);
                String alias = .get(i + 1);
                DateTimeZone tz = map.get(id);
                if (tz == null) {
                    if (pass > 0) {
                        ..println("Cannot find time zone '" + id +
                                           "' to link alias '" + alias + "' to");
                    }
                } else {
                    map.put(aliastz);
                }
            }
        }
        if (outputDir != null) {
            ..println("Writing ZoneInfoMap");
            File file = new File(outputDir"ZoneInfoMap");
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            OutputStream out = new FileOutputStream(file);
            DataOutputStream dout = new DataOutputStream(out);
            try {
                // Sort and filter out any duplicates that match case.
                Map<StringDateTimeZonezimap = new TreeMap<StringDateTimeZone>(.);
                zimap.putAll(map);
                writeZoneInfoMap(doutzimap);
            } finally {
                dout.close();
            }
        }
        return map;
    }
    public void parseDataFile(BufferedReader inthrows IOException {
        Zone zone = null;
        String line;
        while ((line = in.readLine()) != null) {
            String trimmed = line.trim();
            if (trimmed.length() == 0 || trimmed.charAt(0) == '#') {
                continue;
            }
            int index = line.indexOf('#');
            if (index >= 0) {
                line = line.substring(0, index);
            }
            //System.out.println(line);
            StringTokenizer st = new StringTokenizer(line" \t");
            if (Character.isWhitespace(line.charAt(0)) && st.hasMoreTokens()) {
                if (zone != null) {
                    // Zone continuation
                    zone.chain(st);
                }
                continue;
            } else {
                if (zone != null) {
                    .add(zone);
                }
                zone = null;
            }
            if (st.hasMoreTokens()) {
                String token = st.nextToken();
                if (token.equalsIgnoreCase("Rule")) {
                    Rule r = new Rule(st);
                    RuleSet rs = .get(r.iName);
                    if (rs == null) {
                        rs = new RuleSet(r);
                        .put(r.iNamers);
                    } else {
                        rs.addRule(r);
                    }
                } else if (token.equalsIgnoreCase("Zone")) {
                    zone = new Zone(st);
                } else if (token.equalsIgnoreCase("Link")) {
                    .add(st.nextToken());
                    .add(st.nextToken());
                } else {
                    ..println("Unknown line: " + line);
                }
            }
        }
        if (zone != null) {
            .add(zone);
        }
    }
    static class DateTimeOfYear {
        public final int iMonthOfYear;
        public final int iDayOfMonth;
        public final int iDayOfWeek;
        public final boolean iAdvanceDayOfWeek;
        public final int iMillisOfDay;
        public final char iZoneChar;
        DateTimeOfYear() {
             = 1;
             = 1;
             = 0;
             = false;
             = 0;
             = 'w';
        }
        DateTimeOfYear(StringTokenizer st) {
            int month = 1;
            int day = 1;
            int dayOfWeek = 0;
            int millis = 0;
            boolean advance = false;
            char zoneChar = 'w';
            if (st.hasMoreTokens()) {
                month = parseMonth(st.nextToken());
                if (st.hasMoreTokens()) {
                    String str = st.nextToken();
                    if (str.startsWith("last")) {
                        day = -1;
                        dayOfWeek = parseDayOfWeek(str.substring(4));
                        advance = false;
                    } else {
                        try {
                            day = Integer.parseInt(str);
                            dayOfWeek = 0;
                            advance = false;
                        } catch (NumberFormatException e) {
                            int index = str.indexOf(">=");
                            if (index > 0) {
                                day = Integer.parseInt(str.substring(index + 2));
                                dayOfWeek = parseDayOfWeek(str.substring(0, index));
                                advance = true;
                            } else {
                                index = str.indexOf("<=");
                                if (index > 0) {
                                    day = Integer.parseInt(str.substring(index + 2));
                                    dayOfWeek = parseDayOfWeek(str.substring(0, index));
                                    advance = false;
                                } else {
                                    throw new IllegalArgumentException(str);
                                }
                            }
                        }
                    }
                    if (st.hasMoreTokens()) {
                        str = st.nextToken();
                        zoneChar = parseZoneChar(str.charAt(str.length() - 1));
                        if (str.equals("24:00")) {
                            LocalDate date = (day == -1 ?
                                    new LocalDate(2001, month, 1).plusMonths(1) :
                                    new LocalDate(2001, monthday).plusDays(1));
                            advance = (day != -1);
                            month = date.getMonthOfYear();
                            day = date.getDayOfMonth();
                            dayOfWeek = ((dayOfWeek - 1 + 1) % 7) + 1;
                        } else {
                            millis = parseTime(str);
                        }
                    }
                }
            }
             = month;
             = day;
             = dayOfWeek;
             = advance;
             = millis;
             = zoneChar;
        }

        
Adds a recurring savings rule to the builder.
        public void addRecurring(DateTimeZoneBuilder builderString nameKey,
                                 int saveMillisint fromYearint toYear)
        {
            builder.addRecurringSavings(nameKeysaveMillis,
                                        fromYeartoYear,
                                        ,
                                        ,
                                        ,
                                        ,
                                        ,
                                        );
        }

        
Adds a cutover to the builder.
        public void addCutover(DateTimeZoneBuilder builderint year) {
            builder.addCutover(year,
                               ,
                               ,
                               ,
                               ,
                               ,
                               );
        }
        public String toString() {
            return
                "MonthOfYear: " +  + "\n" +
                "DayOfMonth: " +  + "\n" +
                "DayOfWeek: " +  + "\n" +
                "AdvanceDayOfWeek: " +  + "\n" +
                "MillisOfDay: " +  + "\n" +
                "ZoneChar: " +  + "\n";
        }
    }
    private static class Rule {
        public final String iName;
        public final int iFromYear;
        public final int iToYear;
        public final String iType;
        public final DateTimeOfYear iDateTimeOfYear;
        public final int iSaveMillis;
        public final String iLetterS;
        Rule(StringTokenizer st) {
             = st.nextToken().intern();
             = parseYear(st.nextToken(), 0);
             = parseYear(st.nextToken(), );
            if ( < ) {
                throw new IllegalArgumentException();
            }
             = parseOptional(st.nextToken());
             = new DateTimeOfYear(st);
             = parseTime(st.nextToken());
             = parseOptional(st.nextToken());
        }

        
Adds a recurring savings rule to the builder.
        public void addRecurring(DateTimeZoneBuilder builderString nameFormat) {
            String nameKey = formatName(nameFormat);
            .addRecurring
                (buildernameKey);
        }
        private String formatName(String nameFormat) {
            int index = nameFormat.indexOf('/');
            if (index > 0) {
                if ( == 0) {
                    // Extract standard name.
                    return nameFormat.substring(0, index).intern();
                } else {
                    return nameFormat.substring(index + 1).intern();
                }
            }
            index = nameFormat.indexOf("%s");
            if (index < 0) {
                return nameFormat;
            }
            String left = nameFormat.substring(0, index);
            String right = nameFormat.substring(index + 2);
            String name;
            if ( == null) {
                name = left.concat(right);
            } else {
                name = left +  + right;
            }
            return name.intern();
        }
        public String toString() {
            return
                "[Rule]\n" + 
                "Name: " +  + "\n" +
                "FromYear: " +  + "\n" +
                "ToYear: " +  + "\n" +
                "Type: " +  + "\n" +
                 +
                "SaveMillis: " +  + "\n" +
                "LetterS: " +  + "\n";
        }
    }
    private static class RuleSet {
        private List<RuleiRules;
        RuleSet(Rule rule) {
             = new ArrayList<Rule>();
            .add(rule);
        }
        void addRule(Rule rule) {
            if (!(rule.iName.equals(.get(0).))) {
                throw new IllegalArgumentException("Rule name mismatch");
            }
            .add(rule);
        }

        
Adds recurring savings rules to the builder.
        public void addRecurring(DateTimeZoneBuilder builderString nameFormat) {
            for (int i=0; i<.size(); i++) {
                Rule rule = .get(i);
                rule.addRecurring(buildernameFormat);
            }
        }
    }
    private static class Zone {
        public final String iName;
        public final int iOffsetMillis;
        public final String iRules;
        public final String iFormat;
        public final int iUntilYear;
        public final DateTimeOfYear iUntilDateTimeOfYear;
        private Zone iNext;
        Zone(StringTokenizer st) {
            this(st.nextToken(), st);
        }
        private Zone(String nameStringTokenizer st) {
             = name.intern();
             = parseTime(st.nextToken());
             = parseOptional(st.nextToken());
             = st.nextToken().intern();
            int year = .;
            DateTimeOfYear dtOfYear = getStartOfYear();
            if (st.hasMoreTokens()) {
                year = Integer.parseInt(st.nextToken());
                if (st.hasMoreTokens()) {
                    dtOfYear = new DateTimeOfYear(st);
                }
            }
             = year;
             = dtOfYear;
        }
        void chain(StringTokenizer st) {
            if ( != null) {
                .chain(st);
            } else {
                 = new Zone(st);
            }
        }
        /*
        public DateTimeZone buildDateTimeZone(Map ruleSets) {
            DateTimeZoneBuilder builder = new DateTimeZoneBuilder();
            addToBuilder(builder, ruleSets);
            return builder.toDateTimeZone(iName);
        }
        */

        
Adds zone info to the builder.
        public void addToBuilder(DateTimeZoneBuilder builderMap<StringRuleSetruleSets) {
            addToBuilder(thisbuilderruleSets);
        }
        private static void addToBuilder(Zone zone,
                                         DateTimeZoneBuilder builder,
                                         Map<StringRuleSetruleSets)
        {
            for (; zone != nullzone = zone.iNext) {
                builder.setStandardOffset(zone.iOffsetMillis);
                if (zone.iRules == null) {
                    builder.setFixedSavings(zone.iFormat, 0);
                } else {
                    try {
                        // Check if iRules actually just refers to a savings.
                        int saveMillis = parseTime(zone.iRules);
                        builder.setFixedSavings(zone.iFormatsaveMillis);
                    }
                    catch (Exception e) {
                        RuleSet rs = ruleSets.get(zone.iRules);
                        if (rs == null) {
                            throw new IllegalArgumentException
                                ("Rules not found: " + zone.iRules);
                        }
                        rs.addRecurring(builderzone.iFormat);
                    }
                }
                if (zone.iUntilYear == .) {
                    break;
                }
                zone.iUntilDateTimeOfYear.addCutover(builderzone.iUntilYear);
            }
        }
        public String toString() {
            String str =
                "[Zone]\n" + 
                "Name: " +  + "\n" +
                "OffsetMillis: " +  + "\n" +
                "Rules: " +  + "\n" +
                "Format: " +  + "\n" +
                "UntilYear: " +  + "\n" +
                ;
            if ( == null) {
                return str;
            }
            return str + "...\n" + .toString();
        }
    }
New to GrepCode? Check out our FAQ X