Home | History | Annotate | Download | only in calendar
      1 /*
      2  * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package sun.util.calendar;
     27 
     28 import java.io.File;
     29 import java.io.FileInputStream;
     30 import java.io.IOException;
     31 import java.security.AccessController;
     32 import java.security.PrivilegedAction;
     33 import java.security.PrivilegedActionException;
     34 import java.security.PrivilegedExceptionAction;
     35 import java.util.ArrayList;
     36 import java.util.List;
     37 import java.util.Properties;
     38 import java.util.StringTokenizer;
     39 import java.util.TimeZone;
     40 
     41 /**
     42  *
     43  * @author Masayoshi Okutsu
     44  * @since 1.6
     45  */
     46 
     47 public class LocalGregorianCalendar extends BaseCalendar {
     48     private String name;
     49     private Era[] eras;
     50 
     51     public static class Date extends BaseCalendar.Date {
     52 
     53         protected Date() {
     54             super();
     55         }
     56 
     57         protected Date(TimeZone zone) {
     58             super(zone);
     59         }
     60 
     61         private int gregorianYear = FIELD_UNDEFINED;
     62 
     63         public Date setEra(Era era) {
     64             if (getEra() != era) {
     65                 super.setEra(era);
     66                 gregorianYear = FIELD_UNDEFINED;
     67             }
     68             return this;
     69         }
     70 
     71         public Date addYear(int localYear) {
     72             super.addYear(localYear);
     73             gregorianYear += localYear;
     74             return this;
     75         }
     76 
     77         public Date setYear(int localYear) {
     78             if (getYear() != localYear) {
     79                 super.setYear(localYear);
     80                 gregorianYear = FIELD_UNDEFINED;
     81             }
     82             return this;
     83         }
     84 
     85         public int getNormalizedYear() {
     86             return gregorianYear;
     87         }
     88 
     89         public void setNormalizedYear(int normalizedYear) {
     90             this.gregorianYear = normalizedYear;
     91         }
     92 
     93         void setLocalEra(Era era) {
     94             super.setEra(era);
     95         }
     96 
     97         void setLocalYear(int year) {
     98             super.setYear(year);
     99         }
    100 
    101         public String toString() {
    102             String time = super.toString();
    103             time = time.substring(time.indexOf('T'));
    104             StringBuffer sb = new StringBuffer();
    105             Era era = getEra();
    106             if (era != null) {
    107                 String abbr = era.getAbbreviation();
    108                 if (abbr != null) {
    109                     sb.append(abbr);
    110                 }
    111             }
    112             sb.append(getYear()).append('.');
    113             CalendarUtils.sprintf0d(sb, getMonth(), 2).append('.');
    114             CalendarUtils.sprintf0d(sb, getDayOfMonth(), 2);
    115             sb.append(time);
    116             return sb.toString();
    117         }
    118     }
    119 
    120     static LocalGregorianCalendar getLocalGregorianCalendar(String name) {
    121         Properties calendarProps = null;
    122         try {
    123             String homeDir = AccessController.doPrivileged(
    124                 new sun.security.action.GetPropertyAction("java.home"));
    125             final String fname = homeDir + File.separator + "lib" + File.separator
    126                                  + "calendars.properties";
    127             calendarProps = (Properties) AccessController.doPrivileged(new PrivilegedExceptionAction() {
    128                 public Object run() throws IOException {
    129                     Properties props = new Properties();
    130                     try (FileInputStream fis = new FileInputStream(fname)) {
    131                         props.load(fis);
    132                     }
    133                     return props;
    134                 }
    135             });
    136         } catch (PrivilegedActionException e) {
    137             throw new RuntimeException(e.getException());
    138         }
    139 
    140         // Parse calendar.*.eras
    141         String props = calendarProps.getProperty("calendar." + name + ".eras");
    142         if (props == null) {
    143             return null;
    144         }
    145         List<Era> eras = new ArrayList<Era>();
    146         StringTokenizer eraTokens = new StringTokenizer(props, ";");
    147         while (eraTokens.hasMoreTokens()) {
    148             String items = eraTokens.nextToken().trim();
    149             StringTokenizer itemTokens = new StringTokenizer(items, ",");
    150             String eraName = null;
    151             boolean localTime = true;
    152             long since = 0;
    153             String abbr = null;
    154 
    155             while (itemTokens.hasMoreTokens()) {
    156                 String item = itemTokens.nextToken();
    157                 int index = item.indexOf('=');
    158                 // it must be in the key=value form.
    159                 if (index == -1) {
    160                     return null;
    161                 }
    162                 String key = item.substring(0, index);
    163                 String value = item.substring(index + 1);
    164                 if ("name".equals(key)) {
    165                     eraName = value;
    166                 } else if ("since".equals(key)) {
    167                     if (value.endsWith("u")) {
    168                         localTime = false;
    169                         since = Long.parseLong(value.substring(0, value.length() - 1));
    170                     } else {
    171                         since = Long.parseLong(value);
    172                     }
    173                 } else if ("abbr".equals(key)) {
    174                     abbr = value;
    175                 } else {
    176                     throw new RuntimeException("Unknown key word: " + key);
    177                 }
    178             }
    179             Era era = new Era(eraName, abbr, since, localTime);
    180             eras.add(era);
    181         }
    182         Era[] eraArray = new Era[eras.size()];
    183         eras.toArray(eraArray);
    184 
    185         return new LocalGregorianCalendar(name, eraArray);
    186     }
    187 
    188     private LocalGregorianCalendar(String name, Era[] eras) {
    189         this.name = name;
    190         this.eras = eras;
    191         setEras(eras);
    192     }
    193 
    194     public String getName() {
    195         return name;
    196     }
    197 
    198     public Date getCalendarDate() {
    199         return getCalendarDate(System.currentTimeMillis(), newCalendarDate());
    200     }
    201 
    202     public Date getCalendarDate(long millis) {
    203         return getCalendarDate(millis, newCalendarDate());
    204     }
    205 
    206     public Date getCalendarDate(long millis, TimeZone zone) {
    207         return getCalendarDate(millis, newCalendarDate(zone));
    208     }
    209 
    210     public Date getCalendarDate(long millis, CalendarDate date) {
    211         Date ldate = (Date) super.getCalendarDate(millis, date);
    212         return adjustYear(ldate, millis, ldate.getZoneOffset());
    213     }
    214 
    215     private Date adjustYear(Date ldate, long millis, int zoneOffset) {
    216         int i;
    217         for (i = eras.length - 1; i >= 0; --i) {
    218             Era era = eras[i];
    219             long since = era.getSince(null);
    220             if (era.isLocalTime()) {
    221                 since -= zoneOffset;
    222             }
    223             if (millis >= since) {
    224                 ldate.setLocalEra(era);
    225                 int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
    226                 ldate.setLocalYear(y);
    227                 break;
    228             }
    229         }
    230         if (i < 0) {
    231             ldate.setLocalEra(null);
    232             ldate.setLocalYear(ldate.getNormalizedYear());
    233         }
    234         ldate.setNormalized(true);
    235         return ldate;
    236     }
    237 
    238     public Date newCalendarDate() {
    239         return new Date();
    240     }
    241 
    242     public Date newCalendarDate(TimeZone zone) {
    243         return new Date(zone);
    244     }
    245 
    246     public boolean validate(CalendarDate date) {
    247         Date ldate = (Date) date;
    248         Era era = ldate.getEra();
    249         if (era != null) {
    250             if (!validateEra(era)) {
    251                 return false;
    252             }
    253             ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear());
    254         } else {
    255             ldate.setNormalizedYear(ldate.getYear());
    256         }
    257         return super.validate(ldate);
    258     }
    259 
    260     private boolean validateEra(Era era) {
    261         // Validate the era
    262         for (int i = 0; i < eras.length; i++) {
    263             if (era == eras[i]) {
    264                 return true;
    265             }
    266         }
    267         return false;
    268     }
    269 
    270     public boolean normalize(CalendarDate date) {
    271         if (date.isNormalized()) {
    272             return true;
    273         }
    274 
    275         normalizeYear(date);
    276         Date ldate = (Date) date;
    277 
    278         // Normalize it as a Gregorian date and get its millisecond value
    279         super.normalize(ldate);
    280 
    281         boolean hasMillis = false;
    282         long millis = 0;
    283         int year = ldate.getNormalizedYear();
    284         int i;
    285         Era era = null;
    286         for (i = eras.length - 1; i >= 0; --i) {
    287             era = eras[i];
    288             if (era.isLocalTime()) {
    289                 CalendarDate sinceDate = era.getSinceDate();
    290                 int sinceYear = sinceDate.getYear();
    291                 if (year > sinceYear) {
    292                     break;
    293                 }
    294                 if (year == sinceYear) {
    295                     int month = ldate.getMonth();
    296                     int sinceMonth = sinceDate.getMonth();
    297                     if (month > sinceMonth) {
    298                         break;
    299                     }
    300                     if (month == sinceMonth) {
    301                         int day = ldate.getDayOfMonth();
    302                         int sinceDay = sinceDate.getDayOfMonth();
    303                         if (day > sinceDay) {
    304                             break;
    305                         }
    306                         if (day == sinceDay) {
    307                             long timeOfDay = ldate.getTimeOfDay();
    308                             long sinceTimeOfDay = sinceDate.getTimeOfDay();
    309                             if (timeOfDay >= sinceTimeOfDay) {
    310                                 break;
    311                             }
    312                             --i;
    313                             break;
    314                         }
    315                     }
    316                 }
    317             } else {
    318                 if (!hasMillis) {
    319                     millis  = super.getTime(date);
    320                     hasMillis = true;
    321                 }
    322 
    323                 long since = era.getSince(date.getZone());
    324                 if (millis >= since) {
    325                     break;
    326                 }
    327             }
    328         }
    329         if (i >= 0) {
    330             ldate.setLocalEra(era);
    331             int y = ldate.getNormalizedYear() - era.getSinceDate().getYear() + 1;
    332             ldate.setLocalYear(y);
    333         } else {
    334             // Set Gregorian year with no era
    335             ldate.setEra(null);
    336             ldate.setLocalYear(year);
    337             ldate.setNormalizedYear(year);
    338         }
    339         ldate.setNormalized(true);
    340         return true;
    341     }
    342 
    343     void normalizeMonth(CalendarDate date) {
    344         normalizeYear(date);
    345         super.normalizeMonth(date);
    346     }
    347 
    348     void normalizeYear(CalendarDate date) {
    349         Date ldate = (Date) date;
    350         // Set the supposed-to-be-correct Gregorian year first
    351         // e.g., Showa 90 becomes 2015 (1926 + 90 - 1).
    352         Era era = ldate.getEra();
    353         if (era == null || !validateEra(era)) {
    354             ldate.setNormalizedYear(ldate.getYear());
    355         } else {
    356             ldate.setNormalizedYear(era.getSinceDate().getYear() + ldate.getYear() - 1);
    357         }
    358     }
    359 
    360     /**
    361      * Returns whether the specified Gregorian year is a leap year.
    362      * @see #isLeapYear(Era, int)
    363      */
    364     public boolean isLeapYear(int gregorianYear) {
    365         return CalendarUtils.isGregorianLeapYear(gregorianYear);
    366     }
    367 
    368     public boolean isLeapYear(Era era, int year) {
    369         if (era == null) {
    370             return isLeapYear(year);
    371         }
    372         int gyear = era.getSinceDate().getYear() + year - 1;
    373         return isLeapYear(gyear);
    374     }
    375 
    376     public void getCalendarDateFromFixedDate(CalendarDate date, long fixedDate) {
    377         Date ldate = (Date) date;
    378         super.getCalendarDateFromFixedDate(ldate, fixedDate);
    379         adjustYear(ldate, (fixedDate - EPOCH_OFFSET) * DAY_IN_MILLIS, 0);
    380     }
    381 }
    382