HttpDateTime.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.webkit; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.format.Time; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Calendar; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.regex.Matcher; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.regex.Pattern; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass HttpDateTime { 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Regular expression for parsing HTTP-date. 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Wdy, DD Mon YYYY HH:MM:SS GMT 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * RFC 822, updated by RFC 1123 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Weekday, DD-Mon-YY HH:MM:SS GMT 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * RFC 850, obsoleted by RFC 1036 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Wdy Mon DD HH:MM:SS YYYY 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ANSI C's asctime() format 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * with following variations 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Wdy, DD-Mon-YYYY HH:MM:SS GMT 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Wdy, (SP)D Mon YYYY HH:MM:SS GMT 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Wdy,DD Mon YYYY HH:MM:SS GMT 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Wdy, DD-Mon-YY HH:MM:SS GMT 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Wdy, DD Mon YYYY HH:MM:SS -HHMM 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Wdy, DD Mon YYYY HH:MM:SS 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Wdy Mon (SP)D HH:MM:SS YYYY 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Wdy Mon DD HH:MM:SS YYYY GMT 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String HTTP_DATE_RFC_REGEXP = 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "([0-9]{1,2})[- ]([A-Za-z]{3,3})[- ]([0-9]{2,4})[ ]" 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])"; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String HTTP_DATE_ANSIC_REGEXP = 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "[ ]([A-Za-z]{3,3})[ ]+([0-9]{1,2})[ ]" 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + "([0-9][0-9]:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})"; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The compiled version of the HTTP-date regular expressions. 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final Pattern HTTP_DATE_RFC_PATTERN = 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Pattern.compile(HTTP_DATE_RFC_REGEXP); 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final Pattern HTTP_DATE_ANSIC_PATTERN = 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Pattern.compile(HTTP_DATE_ANSIC_REGEXP); 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static class TimeOfDay { 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int hour; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int minute; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int second; 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static Long parse(String timeString) 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throws IllegalArgumentException { 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int date = 1; 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int month = Calendar.JANUARY; 789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int year = 1970; 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TimeOfDay timeOfDay = new TimeOfDay(); 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Matcher rfcMatcher = HTTP_DATE_RFC_PATTERN.matcher(timeString); 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rfcMatcher.find()) { 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project date = getDate(rfcMatcher.group(1)); 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project month = getMonth(rfcMatcher.group(2)); 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project year = getYear(rfcMatcher.group(3)); 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project timeOfDay = getTime(rfcMatcher.group(4)); 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Matcher ansicMatcher = HTTP_DATE_ANSIC_PATTERN.matcher(timeString); 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ansicMatcher.find()) { 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project month = getMonth(ansicMatcher.group(1)); 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project date = getDate(ansicMatcher.group(2)); 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project timeOfDay = getTime(ansicMatcher.group(3)); 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project year = getYear(ansicMatcher.group(4)); 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException(); 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // FIXME: Y2038 BUG! 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (year >= 2038) { 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project year = 2038; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project month = Calendar.JANUARY; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project date = 1; 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Time time = new Time(Time.TIMEZONE_UTC); 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project time.set(timeOfDay.second, timeOfDay.minute, timeOfDay.hour, date, 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project month, year); 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return time.toMillis(false /* use isDst */); 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static int getDate(String dateString) { 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (dateString.length() == 2) { 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (dateString.charAt(0) - '0') * 10 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (dateString.charAt(1) - '0'); 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (dateString.charAt(0) - '0'); 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * jan = 9 + 0 + 13 = 22 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * feb = 5 + 4 + 1 = 10 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * mar = 12 + 0 + 17 = 29 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * apr = 0 + 15 + 17 = 32 1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * may = 12 + 0 + 24 = 36 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * jun = 9 + 20 + 13 = 42 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * jul = 9 + 20 + 11 = 40 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * aug = 0 + 20 + 6 = 26 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sep = 18 + 4 + 15 = 37 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * oct = 14 + 2 + 19 = 35 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * nov = 13 + 14 + 21 = 48 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * dec = 3 + 4 + 2 = 9 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static int getMonth(String monthString) { 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int hash = Character.toLowerCase(monthString.charAt(0)) + 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Character.toLowerCase(monthString.charAt(1)) + 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Character.toLowerCase(monthString.charAt(2)) - 3 * 'a'; 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (hash) { 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 22: 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.JANUARY; 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 10: 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.FEBRUARY; 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 29: 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.MARCH; 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 32: 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.APRIL; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 36: 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.MAY; 1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 42: 1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.JUNE; 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 40: 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.JULY; 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 26: 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.AUGUST; 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 37: 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.SEPTEMBER; 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 35: 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.OCTOBER; 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 48: 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.NOVEMBER; 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case 9: 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return Calendar.DECEMBER; 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException(); 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static int getYear(String yearString) { 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (yearString.length() == 2) { 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int year = (yearString.charAt(0) - '0') * 10 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (yearString.charAt(1) - '0'); 1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (year >= 70) { 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return year + 1900; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return year + 2000; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (yearString.charAt(0) - '0') * 1000 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (yearString.charAt(1) - '0') * 100 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (yearString.charAt(2) - '0') * 10 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (yearString.charAt(3) - '0'); 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static TimeOfDay getTime(String timeString) { 1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project TimeOfDay time = new TimeOfDay(); 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project time.hour = (timeString.charAt(0) - '0') * 10 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (timeString.charAt(1) - '0'); 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project time.minute = (timeString.charAt(3) - '0') * 10 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (timeString.charAt(4) - '0'); 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project time.second = (timeString.charAt(6) - '0') * 10 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + (timeString.charAt(7) - '0'); 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return time; 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 196