122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelpackage com.xtremelabs.robolectric.shadows;
222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelimport android.text.format.Time;
522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelimport android.util.TimeFormatException;
622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelimport com.xtremelabs.robolectric.internal.Implementation;
722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelimport com.xtremelabs.robolectric.internal.Implements;
822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelimport com.xtremelabs.robolectric.internal.RealObject;
922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
1022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelimport java.lang.reflect.Constructor;
1122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelimport java.lang.reflect.InvocationTargetException;
1222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelimport java.text.ParseException;
1322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelimport java.text.SimpleDateFormat;
1422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelimport java.util.*;
1522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
1622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel@Implements(Time.class)
1722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkelpublic class ShadowTime {
1822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @RealObject
1922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    private Time time;
2022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
214bbf62814947c2b192db055300561cdf5b3e7a3dJan Berkel    private static final long SECOND_IN_MILLIS = 1000;
224bbf62814947c2b192db055300561cdf5b3e7a3dJan Berkel    private static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
234bbf62814947c2b192db055300561cdf5b3e7a3dJan Berkel    private static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
244bbf62814947c2b192db055300561cdf5b3e7a3dJan Berkel    private static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
254bbf62814947c2b192db055300561cdf5b3e7a3dJan Berkel
2622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public void __constructor__() {
2722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        __constructor__(getCurrentTimezone());
2822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
2922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
3022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public void __constructor__(String timezone) {
3122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        if (timezone == null) {
3222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            throw new NullPointerException("timezone is null!");
3322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
3422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.timezone = timezone;
3522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.year = 1970;
3622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.monthDay = 1;
3722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.isDst = -1;
3822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
3922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
4022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public void __constructor__(Time other) {
4122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        set(other);
4222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
4322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
4422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
4522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public void set(Time other) {
4622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.timezone = other.timezone;
4722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.second = other.second;
4822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.minute = other.minute;
4922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.hour = other.hour;
5022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.monthDay = other.monthDay;
5122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.month = other.month;
5222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.year = other.year;
5322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.weekDay = other.weekDay;
5422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.yearDay = other.yearDay;
5522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.isDst = other.isDst;
5622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.gmtoff = other.gmtoff;
5722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
5822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
5922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
6022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public void setToNow() {
6122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        set(System.currentTimeMillis());
6222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
6322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
64f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison
65f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison    @Implementation
66167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison    public static boolean isEpoch(Time time) {
67167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        long millis = time.toMillis(true);
68167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        return getJulianDay(millis, 0) == Time.EPOCH_JULIAN_DAY;
69167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison    }
70167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison
71f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison
72167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison    @Implementation
73167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison    public static int getJulianDay(long millis, long gmtoff) {
74167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        long offsetMillis = gmtoff * 1000;
75f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison        long julianDay = (millis + offsetMillis) / DAY_IN_MILLIS;
76167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        return (int) julianDay + Time.EPOCH_JULIAN_DAY;
77167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison    }
78f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison
79f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison    @Implementation
80f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison    public long setJulianDay(int julianDay) {
81167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        // Don't bother with the GMT offset since we don't know the correct
82167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        // value for the given Julian day.  Just get close and then adjust
83167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        // the day.
84f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison        //long millis = (julianDay - EPOCH_JULIAN_DAY) * DateUtils.DAY_IN_MILLIS;
85f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison        long millis = (julianDay - Time.EPOCH_JULIAN_DAY) * DAY_IN_MILLIS;
86167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        set(millis);
87167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison
88167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        // Figure out how close we are to the requested Julian day.
89167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        // We can't be off by more than a day.
90167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        int approximateDay = getJulianDay(millis, time.gmtoff);
91167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        int diff = julianDay - approximateDay;
92167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        time.monthDay += diff;
93167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison
94167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        // Set the time to 12am and re-normalize.
95167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        time.hour = 0;
96167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        time.minute = 0;
97167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        time.second = 0;
98167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        millis = time.normalize(true);
99167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison        return millis;
100167730cf6c09cde1a3284c90cc27ab7f02cf9a55roflharrison    }
101f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison
10222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
10322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public void set(long millis) {
10422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        Calendar c = getCalendar();
10522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        c.setTimeInMillis(millis);
10622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        set(
107f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison                c.get(Calendar.SECOND),
108f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison                c.get(Calendar.MINUTE),
109f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison                c.get(Calendar.HOUR_OF_DAY),
110f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison                c.get(Calendar.DAY_OF_MONTH),
111f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison                c.get(Calendar.MONTH),
112f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison                c.get(Calendar.YEAR)
11322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        );
11422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
11522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
11622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
11722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public long toMillis(boolean ignoreDst) {
11822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        Calendar c = getCalendar();
11922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        return c.getTimeInMillis();
12022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
12122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
12222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
12322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public void set(int second, int minute, int hour, int monthDay, int month, int year) {
12422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.second = second;
12522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.minute = minute;
12622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.hour = hour;
12722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.monthDay = monthDay;
12822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.month = month;
12922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.year = year;
13022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.weekDay = 0;
13122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.yearDay = 0;
13222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.isDst = -1;
13322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.gmtoff = 0;
13422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
13522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
13622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
13722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public void set(int monthDay, int month, int year) {
13822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        set(0, 0, 0, monthDay, month, year);
13922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
14022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
14122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
14222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public void clear(String timezone) {
14322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        if (timezone == null) {
14422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            throw new NullPointerException("timezone is null!");
14522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
14622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.timezone = timezone;
14722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.allDay = false;
14822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.second = 0;
14922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.minute = 0;
15022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.hour = 0;
15122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.monthDay = 0;
15222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.month = 0;
15322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.year = 0;
15422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.weekDay = 0;
15522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.yearDay = 0;
15622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.gmtoff = 0;
15722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.isDst = -1;
15822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
15922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
16022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
16122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public static String getCurrentTimezone() {
16222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        return TimeZone.getDefault().getID();
16322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
16422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
16522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
16622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public static int compare(Time a, Time b) {
16722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        long ams = a.toMillis(false);
16822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        long bms = b.toMillis(false);
16922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        if (ams == bms) {
17022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            return 0;
17122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        } else if (ams < bms) {
17222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            return -1;
17322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        } else {
17422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            return 1;
17522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
17622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
17722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
17822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
17922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public boolean before(Time other) {
18022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        return Time.compare(time, other) < 0;
18122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
18222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
18322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
18422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public boolean after(Time other) {
18522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        return Time.compare(time, other) > 0;
18622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
18722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
18822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
18922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public boolean parse(String timeString) {
19022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        TimeZone tz;
19122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        if (timeString.endsWith("Z")) {
19222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            timeString = timeString.substring(0, timeString.length() - 1);
19322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            tz = TimeZone.getTimeZone("UTC");
19422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        } else {
19522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            tz = TimeZone.getTimeZone(time.timezone);
19622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
197e3f746175b10f25da1be5d1bf60ee691f6f72955Jan Berkel        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ENGLISH);
198e3f746175b10f25da1be5d1bf60ee691f6f72955Jan Berkel        SimpleDateFormat dfShort = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH);
19922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        df.setTimeZone(tz);
20022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        dfShort.setTimeZone(tz);
20122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        time.timezone = tz.getID();
20222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        try {
20322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            set(df.parse(timeString).getTime());
20422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        } catch (ParseException e) {
20522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            try {
20622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                set(dfShort.parse(timeString).getTime());
20722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            } catch (ParseException e2) {
20822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                throwTimeFormatException();
20922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            }
21022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
21122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        return "UTC".equals(tz.getID());
21222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
21322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
21422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
21522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public String format(String format) {
216e3f746175b10f25da1be5d1bf60ee691f6f72955Jan Berkel        Strftime strftime = new Strftime(format, Locale.getDefault());
217e3f746175b10f25da1be5d1bf60ee691f6f72955Jan Berkel        strftime.setTimeZone(TimeZone.getTimeZone(time.timezone));
218e3f746175b10f25da1be5d1bf60ee691f6f72955Jan Berkel        return strftime.format(new Date(toMillis(false)));
21922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
22022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
22122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
22222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public String format2445() {
22322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        return format("%Y%m%dT%H%M%S");
22422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
22522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
22622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    @Implementation
22722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public String format3339(boolean allDay) {
22822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        if (allDay) {
22922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            return format("%Y-%m-%d");
23022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        } else if ("UTC".equals(time.timezone)) {
23122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            return format("%Y-%m-%dT%H:%M:%S.000Z");
23222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        } else {
23322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            String base = format("%Y-%m-%dT%H:%M:%S.000");
23422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            String sign = (time.gmtoff < 0) ? "-" : "+";
235f798c4cd7ba4400e26f7c8cc74ce7e8a86d0b053roflharrison            int offset = (int) Math.abs(time.gmtoff);
23622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            int minutes = (offset % 3600) / 60;
23722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            int hours = offset / 3600;
23822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            return String.format("%s%s%02d:%02d", base, sign, hours, minutes);
23922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
24022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
24122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
24222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    private void throwTimeFormatException() {
24322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        try {
24422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            Constructor<TimeFormatException> c = TimeFormatException.class.getDeclaredConstructor();
24522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            c.setAccessible(true);
24622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            throw c.newInstance();
24722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        } catch (InvocationTargetException e) {
24822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            throw new RuntimeException(e);
24922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        } catch (InstantiationException e) {
25022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            throw new RuntimeException(e);
25122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        } catch (IllegalAccessException e) {
25222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            throw new RuntimeException(e);
25322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        } catch (NoSuchMethodException e) {
25422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            throw new RuntimeException(e);
25522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
25622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
25722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
25822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    private Calendar getCalendar() {
25922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        Calendar c = Calendar.getInstance(TimeZone.getTimeZone(time.timezone));
26022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        c.set(time.year, time.month, time.monthDay, time.hour, time.minute, time.second);
26122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        c.set(Calendar.MILLISECOND, 0);
26222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        return c;
26322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
26422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
26522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    // taken from org.apache.catalina.util.Strftime.java
26622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    // see http://javasourcecode.org/html/open-source/tomcat/tomcat-6.0.32/org/apache/catalina/util/Strftime.java.html
26722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    /*
26822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    * Licensed to the Apache Software Foundation (ASF) under one or more
26922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    * contributor license agreements.  See the NOTICE file distributed with
27022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    * this work for additional information regarding copyright ownership.
27122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    * The ASF licenses this file to You under the Apache License, Version 2.0
27222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    * (the "License"); you may not use this file except in compliance with
27322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    * the License.  You may obtain a copy of the License at
27422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    *
27522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    *      http://www.apache.org/licenses/LICENSE-2.0
27622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    *
27722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    * Unless required by applicable law or agreed to in writing, software
27822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    * distributed under the License is distributed on an "AS IS" BASIS,
27922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    * See the License for the specific language governing permissions and
28122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    * limitations under the License.
28222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    */
28322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    public static class Strftime {
28422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        protected static Properties translate;
28522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        protected SimpleDateFormat simpleDateFormat;
28622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
28722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        /**
28822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * Initialize our pattern translation
28922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         */
29022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        static {
29122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate = new Properties();
29222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("a", "EEE");
29322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("A", "EEEE");
29422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("b", "MMM");
29522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("B", "MMMM");
29622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("c", "EEE MMM d HH:mm:ss yyyy");
29722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
29822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //There's no way to specify the century in SimpleDateFormat.  We don't want to hard-code
29922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //20 since this could be wrong for the pre-2000 files.
30022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //translate.put("C", "20");
30122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("d", "dd");
30222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("D", "MM/dd/yy");
30322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("e", "dd"); //will show as '03' instead of ' 3'
30422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("F", "yyyy-MM-dd");
30522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("g", "yy");
30622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("G", "yyyy");
30722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("H", "HH");
30822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("h", "MMM");
30922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("I", "hh");
31022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("j", "DDD");
31122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("k", "HH"); //will show as '07' instead of ' 7'
31222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("l", "hh"); //will show as '07' instead of ' 7'
31322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("m", "MM");
31422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("M", "mm");
31522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("n", "\n");
31622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("p", "a");
31722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("P", "a");  //will show as pm instead of PM
31822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("r", "hh:mm:ss a");
31922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("R", "HH:mm");
32022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //There's no way to specify this with SimpleDateFormat
32122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //translate.put("s","seconds since ecpoch");
32222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("S", "ss");
32322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("t", "\t");
32422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("T", "HH:mm:ss");
32522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //There's no way to specify this with SimpleDateFormat
32622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //translate.put("u","day of week ( 1-7 )");
32722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
32822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //There's no way to specify this with SimpleDateFormat
32922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //translate.put("U","week in year with first sunday as first day...");
33022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
33122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("V", "ww"); //I'm not sure this is always exactly the same
33222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
33322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //There's no way to specify this with SimpleDateFormat
33422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //translate.put("W","week in year with first monday as first day...");
33522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
33622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //There's no way to specify this with SimpleDateFormat
33722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //translate.put("w","E");
33822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("X", "HH:mm:ss");
33922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("x", "MM/dd/yy");
34022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("y", "yy");
34122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("Y", "yyyy");
34222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("Z", "z");
34322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("z", "Z");
34422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            translate.put("%", "%");
34522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
34622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
34722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
34822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        /**
34922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * Create an instance of this date formatting class
35022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         *
35122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @see #Strftime(String, Locale)
35222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         */
35322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        public Strftime(String origFormat) {
35422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            String convertedFormat = convertDateFormat(origFormat);
35522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            simpleDateFormat = new SimpleDateFormat(convertedFormat);
35622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
35722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
35822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        /**
35922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * Create an instance of this date formatting class
36022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         *
36122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @param origFormat the strftime-style formatting string
36222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @param locale     the locale to use for locale-specific conversions
36322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         */
36422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        public Strftime(String origFormat, Locale locale) {
36522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            String convertedFormat = convertDateFormat(origFormat);
36622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            simpleDateFormat = new SimpleDateFormat(convertedFormat, locale);
36722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
36822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
36922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        /**
37022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * Format the date according to the strftime-style string given in the constructor.
37122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         *
37222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @param date the date to format
37322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @return the formatted date
37422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         */
37522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        public String format(Date date) {
37622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            return simpleDateFormat.format(date);
37722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
37822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
37922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        /**
38022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * Get the timezone used for formatting conversions
38122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         *
38222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @return the timezone
38322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         */
38422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        public TimeZone getTimeZone() {
38522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            return simpleDateFormat.getTimeZone();
38622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
38722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
38822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        /**
38922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * Change the timezone used to format dates
39022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         *
39122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @see SimpleDateFormat#setTimeZone
39222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         */
39322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        public void setTimeZone(TimeZone timeZone) {
39422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            simpleDateFormat.setTimeZone(timeZone);
39522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
39622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
39722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        /**
39822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * Search the provided pattern and get the C standard
39922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * Date/Time formatting rules and convert them to the
40022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * Java equivalent.
40122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         *
40222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @param pattern The pattern to search
40322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @return The modified pattern
40422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         */
40522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        protected String convertDateFormat(String pattern) {
40622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            boolean inside = false;
40722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            boolean mark = false;
40822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            boolean modifiedCommand = false;
40922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
41022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            StringBuffer buf = new StringBuffer();
41122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
41222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            for (int i = 0; i < pattern.length(); i++) {
41322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                char c = pattern.charAt(i);
41422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
41522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                if (c == '%' && !mark) {
41622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    mark = true;
41722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                } else {
41822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    if (mark) {
41922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                        if (modifiedCommand) {
42022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                            //don't do anything--we just wanted to skip a char
42122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                            modifiedCommand = false;
42222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                            mark = false;
42322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                        } else {
42422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                            inside = translateCommand(buf, pattern, i, inside);
42522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                            //It's a modifier code
42622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                            if (c == 'O' || c == 'E') {
42722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                                modifiedCommand = true;
42822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                            } else {
42922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                                mark = false;
43022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                            }
43122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                        }
43222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    } else {
43322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                        if (!inside && c != ' ') {
43422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                            //We start a literal, which we need to quote
43522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                            buf.append("'");
43622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                            inside = true;
43722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                        }
43822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
43922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                        buf.append(c);
44022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    }
44122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                }
44222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            }
44322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
44422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            if (buf.length() > 0) {
44522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                char lastChar = buf.charAt(buf.length() - 1);
44622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
44722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                if (lastChar != '\'' && inside) {
44822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    buf.append('\'');
44922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                }
45022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            }
45122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            return buf.toString();
45222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
45322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
45422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        protected String quote(String str, boolean insideQuotes) {
45522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            String retVal = str;
45622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            if (!insideQuotes) {
45722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                retVal = '\'' + retVal + '\'';
45822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            }
45922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            return retVal;
46022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
46122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
46222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        /**
46322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * Try to get the Java Date/Time formatting associated with
46422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * the C standard provided.
46522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         *
46622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @param buf       The buffer
46722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @param pattern   The date/time pattern
46822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @param index     The char index
46922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @param oldInside Flag value
47022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         * @return True if new is inside buffer
47122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel         */
47222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        protected boolean translateCommand(StringBuffer buf, String pattern, int index, boolean oldInside) {
47322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            char firstChar = pattern.charAt(index);
47422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            boolean newInside = oldInside;
47522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
47622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //O and E are modifiers, they mean to present an alternative representation of the next char
47722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            //we just handle the next char as if the O or E wasn't there
47822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            if (firstChar == 'O' || firstChar == 'E') {
47922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                if (index + 1 < pattern.length()) {
48022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    newInside = translateCommand(buf, pattern, index + 1, oldInside);
48122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                } else {
48222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    buf.append(quote("%" + firstChar, oldInside));
48322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                }
48422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            } else {
48522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                String command = translate.getProperty(String.valueOf(firstChar));
48622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel
48722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                //If we don't find a format, treat it as a literal--That's what apache does
48822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                if (command == null) {
48922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    buf.append(quote("%" + firstChar, oldInside));
49022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                } else {
49122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    //If we were inside quotes, close the quotes
49222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    if (oldInside) {
49322dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                        buf.append('\'');
49422dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    }
49522dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    buf.append(command);
49622dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                    newInside = false;
49722dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel                }
49822dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            }
49922dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel            return newInside;
50022dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel        }
50122dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel    }
50222dd87d4de604631bc6dabd1186be58dbed71929Jan Berkel}
503