OLD | NEW |
1 /* | 1 /* |
2 ******************************************************************************* | 2 ******************************************************************************* |
3 * Copyright (C) 1997-2013, International Business Machines Corporation and * | 3 * Copyright (C) 1997-2014, International Business Machines Corporation and * |
4 * others. All Rights Reserved. * | 4 * others. All Rights Reserved. * |
5 ******************************************************************************* | 5 ******************************************************************************* |
6 * | 6 * |
7 * File CALENDAR.CPP | 7 * File CALENDAR.CPP |
8 * | 8 * |
9 * Modification History: | 9 * Modification History: |
10 * | 10 * |
11 * Date Name Description | 11 * Date Name Description |
12 * 02/03/97 clhuang Creation. | 12 * 02/03/97 clhuang Creation. |
13 * 04/22/97 aliu Cleaned up, fixed memory leak, made | 13 * 04/22/97 aliu Cleaned up, fixed memory leak, made |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 #include <stdio.h> | 99 #include <stdio.h> |
100 | 100 |
101 /** | 101 /** |
102 * convert a UCalendarDateFields into a string - for debugging | 102 * convert a UCalendarDateFields into a string - for debugging |
103 * @param f field enum | 103 * @param f field enum |
104 * @return static string to the field name | 104 * @return static string to the field name |
105 * @internal | 105 * @internal |
106 */ | 106 */ |
107 | 107 |
108 const char* fldName(UCalendarDateFields f) { | 108 const char* fldName(UCalendarDateFields f) { |
109 » return udbg_enumName(UDBG_UCalendarDateFields, (int32_t)f); | 109 return udbg_enumName(UDBG_UCalendarDateFields, (int32_t)f); |
110 } | 110 } |
111 | 111 |
112 #if UCAL_DEBUG_DUMP | 112 #if UCAL_DEBUG_DUMP |
113 // from CalendarTest::calToStr - but doesn't modify contents. | 113 // from CalendarTest::calToStr - but doesn't modify contents. |
114 void ucal_dump(const Calendar &cal) { | 114 void ucal_dump(const Calendar &cal) { |
115 cal.dump(); | 115 cal.dump(); |
116 } | 116 } |
117 | 117 |
118 void Calendar::dump() const { | 118 void Calendar::dump() const { |
119 int i; | 119 int i; |
(...skipping 553 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
673 | 673 |
674 Calendar::Calendar(UErrorCode& success) | 674 Calendar::Calendar(UErrorCode& success) |
675 : UObject(), | 675 : UObject(), |
676 fIsTimeSet(FALSE), | 676 fIsTimeSet(FALSE), |
677 fAreFieldsSet(FALSE), | 677 fAreFieldsSet(FALSE), |
678 fAreAllFieldsSet(FALSE), | 678 fAreAllFieldsSet(FALSE), |
679 fAreFieldsVirtuallySet(FALSE), | 679 fAreFieldsVirtuallySet(FALSE), |
680 fNextStamp((int32_t)kMinimumUserStamp), | 680 fNextStamp((int32_t)kMinimumUserStamp), |
681 fTime(0), | 681 fTime(0), |
682 fLenient(TRUE), | 682 fLenient(TRUE), |
683 fZone(0), | 683 fZone(NULL), |
684 fRepeatedWallTime(UCAL_WALLTIME_LAST), | 684 fRepeatedWallTime(UCAL_WALLTIME_LAST), |
685 fSkippedWallTime(UCAL_WALLTIME_LAST) | 685 fSkippedWallTime(UCAL_WALLTIME_LAST) |
686 { | 686 { |
687 clear(); | 687 clear(); |
| 688 if (U_FAILURE(success)) { |
| 689 return; |
| 690 } |
688 fZone = TimeZone::createDefault(); | 691 fZone = TimeZone::createDefault(); |
689 if (fZone == NULL) { | 692 if (fZone == NULL) { |
690 success = U_MEMORY_ALLOCATION_ERROR; | 693 success = U_MEMORY_ALLOCATION_ERROR; |
691 } | 694 } |
692 setWeekData(Locale::getDefault(), NULL, success); | 695 setWeekData(Locale::getDefault(), NULL, success); |
693 } | 696 } |
694 | 697 |
695 // ------------------------------------- | 698 // ------------------------------------- |
696 | 699 |
697 Calendar::Calendar(TimeZone* zone, const Locale& aLocale, UErrorCode& success) | 700 Calendar::Calendar(TimeZone* zone, const Locale& aLocale, UErrorCode& success) |
698 : UObject(), | 701 : UObject(), |
699 fIsTimeSet(FALSE), | 702 fIsTimeSet(FALSE), |
700 fAreFieldsSet(FALSE), | 703 fAreFieldsSet(FALSE), |
701 fAreAllFieldsSet(FALSE), | 704 fAreAllFieldsSet(FALSE), |
702 fAreFieldsVirtuallySet(FALSE), | 705 fAreFieldsVirtuallySet(FALSE), |
703 fNextStamp((int32_t)kMinimumUserStamp), | 706 fNextStamp((int32_t)kMinimumUserStamp), |
704 fTime(0), | 707 fTime(0), |
705 fLenient(TRUE), | 708 fLenient(TRUE), |
706 fZone(0), | 709 fZone(NULL), |
707 fRepeatedWallTime(UCAL_WALLTIME_LAST), | 710 fRepeatedWallTime(UCAL_WALLTIME_LAST), |
708 fSkippedWallTime(UCAL_WALLTIME_LAST) | 711 fSkippedWallTime(UCAL_WALLTIME_LAST) |
709 { | 712 { |
| 713 if (U_FAILURE(success)) { |
| 714 return; |
| 715 } |
710 if(zone == 0) { | 716 if(zone == 0) { |
711 #if defined (U_DEBUG_CAL) | 717 #if defined (U_DEBUG_CAL) |
712 fprintf(stderr, "%s:%d: ILLEGAL ARG because timezone cannot be 0\n", | 718 fprintf(stderr, "%s:%d: ILLEGAL ARG because timezone cannot be 0\n", |
713 __FILE__, __LINE__); | 719 __FILE__, __LINE__); |
714 #endif | 720 #endif |
715 success = U_ILLEGAL_ARGUMENT_ERROR; | 721 success = U_ILLEGAL_ARGUMENT_ERROR; |
716 return; | 722 return; |
717 } | 723 } |
718 | 724 |
719 clear(); | 725 clear(); |
720 fZone = zone; | 726 fZone = zone; |
721 | |
722 setWeekData(aLocale, NULL, success); | 727 setWeekData(aLocale, NULL, success); |
723 } | 728 } |
724 | 729 |
725 // ------------------------------------- | 730 // ------------------------------------- |
726 | 731 |
727 Calendar::Calendar(const TimeZone& zone, const Locale& aLocale, UErrorCode& succ
ess) | 732 Calendar::Calendar(const TimeZone& zone, const Locale& aLocale, UErrorCode& succ
ess) |
728 : UObject(), | 733 : UObject(), |
729 fIsTimeSet(FALSE), | 734 fIsTimeSet(FALSE), |
730 fAreFieldsSet(FALSE), | 735 fAreFieldsSet(FALSE), |
731 fAreAllFieldsSet(FALSE), | 736 fAreAllFieldsSet(FALSE), |
732 fAreFieldsVirtuallySet(FALSE), | 737 fAreFieldsVirtuallySet(FALSE), |
733 fNextStamp((int32_t)kMinimumUserStamp), | 738 fNextStamp((int32_t)kMinimumUserStamp), |
734 fTime(0), | 739 fTime(0), |
735 fLenient(TRUE), | 740 fLenient(TRUE), |
736 fZone(0), | 741 fZone(NULL), |
737 fRepeatedWallTime(UCAL_WALLTIME_LAST), | 742 fRepeatedWallTime(UCAL_WALLTIME_LAST), |
738 fSkippedWallTime(UCAL_WALLTIME_LAST) | 743 fSkippedWallTime(UCAL_WALLTIME_LAST) |
739 { | 744 { |
| 745 if (U_FAILURE(success)) { |
| 746 return; |
| 747 } |
740 clear(); | 748 clear(); |
741 fZone = zone.clone(); | 749 fZone = zone.clone(); |
742 if (fZone == NULL) { | 750 if (fZone == NULL) { |
743 » success = U_MEMORY_ALLOCATION_ERROR; | 751 success = U_MEMORY_ALLOCATION_ERROR; |
744 } | 752 } |
745 setWeekData(aLocale, NULL, success); | 753 setWeekData(aLocale, NULL, success); |
746 } | 754 } |
747 | 755 |
748 // ------------------------------------- | 756 // ------------------------------------- |
749 | 757 |
750 Calendar::~Calendar() | 758 Calendar::~Calendar() |
751 { | 759 { |
752 delete fZone; | 760 delete fZone; |
753 } | 761 } |
754 | 762 |
755 // ------------------------------------- | 763 // ------------------------------------- |
756 | 764 |
757 Calendar::Calendar(const Calendar &source) | 765 Calendar::Calendar(const Calendar &source) |
758 : UObject(source) | 766 : UObject(source) |
759 { | 767 { |
760 fZone = 0; | 768 fZone = NULL; |
761 *this = source; | 769 *this = source; |
762 } | 770 } |
763 | 771 |
764 // ------------------------------------- | 772 // ------------------------------------- |
765 | 773 |
766 Calendar & | 774 Calendar & |
767 Calendar::operator=(const Calendar &right) | 775 Calendar::operator=(const Calendar &right) |
768 { | 776 { |
769 if (this != &right) { | 777 if (this != &right) { |
770 uprv_arrayCopy(right.fFields, fFields, UCAL_FIELD_COUNT); | 778 uprv_arrayCopy(right.fFields, fFields, UCAL_FIELD_COUNT); |
771 uprv_arrayCopy(right.fIsSet, fIsSet, UCAL_FIELD_COUNT); | 779 uprv_arrayCopy(right.fIsSet, fIsSet, UCAL_FIELD_COUNT); |
772 uprv_arrayCopy(right.fStamp, fStamp, UCAL_FIELD_COUNT); | 780 uprv_arrayCopy(right.fStamp, fStamp, UCAL_FIELD_COUNT); |
773 fTime = right.fTime; | 781 fTime = right.fTime; |
774 fIsTimeSet = right.fIsTimeSet; | 782 fIsTimeSet = right.fIsTimeSet; |
775 fAreAllFieldsSet = right.fAreAllFieldsSet; | 783 fAreAllFieldsSet = right.fAreAllFieldsSet; |
776 fAreFieldsSet = right.fAreFieldsSet; | 784 fAreFieldsSet = right.fAreFieldsSet; |
777 fAreFieldsVirtuallySet = right.fAreFieldsVirtuallySet; | 785 fAreFieldsVirtuallySet = right.fAreFieldsVirtuallySet; |
778 fLenient = right.fLenient; | 786 fLenient = right.fLenient; |
779 fRepeatedWallTime = right.fRepeatedWallTime; | 787 fRepeatedWallTime = right.fRepeatedWallTime; |
780 fSkippedWallTime = right.fSkippedWallTime; | 788 fSkippedWallTime = right.fSkippedWallTime; |
781 if (fZone != NULL) { | 789 delete fZone; |
782 delete fZone; | 790 fZone = NULL; |
783 } | |
784 if (right.fZone != NULL) { | 791 if (right.fZone != NULL) { |
785 fZone = right.fZone->clone(); | 792 fZone = right.fZone->clone(); |
786 } | 793 } |
787 fFirstDayOfWeek = right.fFirstDayOfWeek; | 794 fFirstDayOfWeek = right.fFirstDayOfWeek; |
788 fMinimalDaysInFirstWeek = right.fMinimalDaysInFirstWeek; | 795 fMinimalDaysInFirstWeek = right.fMinimalDaysInFirstWeek; |
789 fWeekendOnset = right.fWeekendOnset; | 796 fWeekendOnset = right.fWeekendOnset; |
790 fWeekendOnsetMillis = right.fWeekendOnsetMillis; | 797 fWeekendOnsetMillis = right.fWeekendOnsetMillis; |
791 fWeekendCease = right.fWeekendCease; | 798 fWeekendCease = right.fWeekendCease; |
792 fWeekendCeaseMillis = right.fWeekendCeaseMillis; | 799 fWeekendCeaseMillis = right.fWeekendCeaseMillis; |
793 fNextStamp = right.fNextStamp; | 800 fNextStamp = right.fNextStamp; |
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1157 { | 1164 { |
1158 set(UCAL_YEAR, year); | 1165 set(UCAL_YEAR, year); |
1159 set(UCAL_MONTH, month); | 1166 set(UCAL_MONTH, month); |
1160 set(UCAL_DATE, date); | 1167 set(UCAL_DATE, date); |
1161 set(UCAL_HOUR_OF_DAY, hour); | 1168 set(UCAL_HOUR_OF_DAY, hour); |
1162 set(UCAL_MINUTE, minute); | 1169 set(UCAL_MINUTE, minute); |
1163 set(UCAL_SECOND, second); | 1170 set(UCAL_SECOND, second); |
1164 } | 1171 } |
1165 | 1172 |
1166 // ------------------------------------- | 1173 // ------------------------------------- |
| 1174 // For now the full getRelatedYear implementation is here; |
| 1175 // per #10752 move the non-default implementation to subclasses |
| 1176 // (default implementation will do no year adjustment) |
| 1177 |
| 1178 static int32_t gregoYearFromIslamicStart(int32_t year) { |
| 1179 // ad hoc conversion, improve under #10752 |
| 1180 // rough est for now, ok for grego 1846-2138, |
| 1181 // otherwise occasionally wrong (for 3% of years) |
| 1182 int cycle, offset, shift = 0; |
| 1183 if (year >= 1397) { |
| 1184 cycle = (year - 1397) / 67; |
| 1185 offset = (year - 1397) % 67; |
| 1186 shift = 2*cycle + ((offset >= 33)? 1: 0); |
| 1187 } else { |
| 1188 cycle = (year - 1396) / 67 - 1; |
| 1189 offset = -(year - 1396) % 67; |
| 1190 shift = 2*cycle + ((offset <= 33)? 1: 0); |
| 1191 } |
| 1192 return year + 579 - shift; |
| 1193 } |
| 1194 |
| 1195 int32_t Calendar::getRelatedYear(UErrorCode &status) const |
| 1196 { |
| 1197 if (U_FAILURE(status)) { |
| 1198 return 0; |
| 1199 } |
| 1200 int32_t year = get(UCAL_EXTENDED_YEAR, status); |
| 1201 if (U_FAILURE(status)) { |
| 1202 return 0; |
| 1203 } |
| 1204 // modify for calendar type |
| 1205 ECalType type = getCalendarType(getType()); |
| 1206 switch (type) { |
| 1207 case CALTYPE_PERSIAN: |
| 1208 year += 622; break; |
| 1209 case CALTYPE_HEBREW: |
| 1210 year -= 3760; break; |
| 1211 case CALTYPE_CHINESE: |
| 1212 year -= 2637; break; |
| 1213 case CALTYPE_INDIAN: |
| 1214 year += 79; break; |
| 1215 case CALTYPE_COPTIC: |
| 1216 year += 284; break; |
| 1217 case CALTYPE_ETHIOPIC: |
| 1218 year += 8; break; |
| 1219 case CALTYPE_ETHIOPIC_AMETE_ALEM: |
| 1220 year -=5492; break; |
| 1221 case CALTYPE_DANGI: |
| 1222 year -= 2333; break; |
| 1223 case CALTYPE_ISLAMIC_CIVIL: |
| 1224 case CALTYPE_ISLAMIC: |
| 1225 case CALTYPE_ISLAMIC_UMALQURA: |
| 1226 case CALTYPE_ISLAMIC_TBLA: |
| 1227 case CALTYPE_ISLAMIC_RGSA: |
| 1228 year = gregoYearFromIslamicStart(year); break; |
| 1229 default: |
| 1230 // CALTYPE_GREGORIAN |
| 1231 // CALTYPE_JAPANESE |
| 1232 // CALTYPE_BUDDHIST |
| 1233 // CALTYPE_ROC |
| 1234 // CALTYPE_ISO8601 |
| 1235 // do nothing, EXTENDED_YEAR same as Gregorian |
| 1236 break; |
| 1237 } |
| 1238 return year; |
| 1239 } |
| 1240 |
| 1241 // ------------------------------------- |
| 1242 // For now the full setRelatedYear implementation is here; |
| 1243 // per #10752 move the non-default implementation to subclasses |
| 1244 // (default implementation will do no year adjustment) |
| 1245 |
| 1246 static int32_t firstIslamicStartYearFromGrego(int32_t year) { |
| 1247 // ad hoc conversion, improve under #10752 |
| 1248 // rough est for now, ok for grego 1846-2138, |
| 1249 // otherwise occasionally wrong (for 3% of years) |
| 1250 int cycle, offset, shift = 0; |
| 1251 if (year >= 1977) { |
| 1252 cycle = (year - 1977) / 65; |
| 1253 offset = (year - 1977) % 65; |
| 1254 shift = 2*cycle + ((offset >= 32)? 1: 0); |
| 1255 } else { |
| 1256 cycle = (year - 1976) / 65 - 1; |
| 1257 offset = -(year - 1976) % 65; |
| 1258 shift = 2*cycle + ((offset <= 32)? 1: 0); |
| 1259 } |
| 1260 return year - 579 + shift; |
| 1261 } |
| 1262 void Calendar::setRelatedYear(int32_t year) |
| 1263 { |
| 1264 // modify for calendar type |
| 1265 ECalType type = getCalendarType(getType()); |
| 1266 switch (type) { |
| 1267 case CALTYPE_PERSIAN: |
| 1268 year -= 622; break; |
| 1269 case CALTYPE_HEBREW: |
| 1270 year += 3760; break; |
| 1271 case CALTYPE_CHINESE: |
| 1272 year += 2637; break; |
| 1273 case CALTYPE_INDIAN: |
| 1274 year -= 79; break; |
| 1275 case CALTYPE_COPTIC: |
| 1276 year -= 284; break; |
| 1277 case CALTYPE_ETHIOPIC: |
| 1278 year -= 8; break; |
| 1279 case CALTYPE_ETHIOPIC_AMETE_ALEM: |
| 1280 year +=5492; break; |
| 1281 case CALTYPE_DANGI: |
| 1282 year += 2333; break; |
| 1283 case CALTYPE_ISLAMIC_CIVIL: |
| 1284 case CALTYPE_ISLAMIC: |
| 1285 case CALTYPE_ISLAMIC_UMALQURA: |
| 1286 case CALTYPE_ISLAMIC_TBLA: |
| 1287 case CALTYPE_ISLAMIC_RGSA: |
| 1288 year = firstIslamicStartYearFromGrego(year); break; |
| 1289 default: |
| 1290 // CALTYPE_GREGORIAN |
| 1291 // CALTYPE_JAPANESE |
| 1292 // CALTYPE_BUDDHIST |
| 1293 // CALTYPE_ROC |
| 1294 // CALTYPE_ISO8601 |
| 1295 // do nothing, EXTENDED_YEAR same as Gregorian |
| 1296 break; |
| 1297 } |
| 1298 // set extended year |
| 1299 set(UCAL_EXTENDED_YEAR, year); |
| 1300 } |
| 1301 |
| 1302 // ------------------------------------- |
1167 | 1303 |
1168 void | 1304 void |
1169 Calendar::clear() | 1305 Calendar::clear() |
1170 { | 1306 { |
1171 for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) { | 1307 for (int32_t i=0; i<UCAL_FIELD_COUNT; ++i) { |
1172 fFields[i] = 0; // Must do this; other code depends on it | 1308 fFields[i] = 0; // Must do this; other code depends on it |
1173 fStamp[i] = kUnset; | 1309 fStamp[i] = kUnset; |
1174 fIsSet[i] = FALSE; // Remove later | 1310 fIsSet[i] = FALSE; // Remove later |
1175 } | 1311 } |
1176 fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = FAL
SE; | 1312 fIsTimeSet = fAreFieldsSet = fAreAllFieldsSet = fAreFieldsVirtuallySet = FAL
SE; |
(...skipping 710 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1887 void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
) | 2023 void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
) |
1888 { | 2024 { |
1889 if (amount == 0) { | 2025 if (amount == 0) { |
1890 return; // Do nothing! | 2026 return; // Do nothing! |
1891 } | 2027 } |
1892 | 2028 |
1893 // We handle most fields in the same way. The algorithm is to add | 2029 // We handle most fields in the same way. The algorithm is to add |
1894 // a computed amount of millis to the current millis. The only | 2030 // a computed amount of millis to the current millis. The only |
1895 // wrinkle is with DST (and/or a change to the zone's UTC offset, which | 2031 // wrinkle is with DST (and/or a change to the zone's UTC offset, which |
1896 // we'll include with DST) -- for some fields, like the DAY_OF_MONTH, | 2032 // we'll include with DST) -- for some fields, like the DAY_OF_MONTH, |
1897 // we don't want the HOUR to shift due to changes in DST. If the | 2033 // we don't want the wall time to shift due to changes in DST. If the |
1898 // result of the add operation is to move from DST to Standard, or | 2034 // result of the add operation is to move from DST to Standard, or |
1899 // vice versa, we need to adjust by an hour forward or back, | 2035 // vice versa, we need to adjust by an hour forward or back, |
1900 // respectively. For such fields we set keepHourInvariant to TRUE. | 2036 // respectively. For such fields we set keepWallTimeInvariant to TRUE. |
1901 | 2037 |
1902 // We only adjust the DST for fields larger than an hour. For | 2038 // We only adjust the DST for fields larger than an hour. For |
1903 // fields smaller than an hour, we cannot adjust for DST without | 2039 // fields smaller than an hour, we cannot adjust for DST without |
1904 // causing problems. for instance, if you add one hour to April 5, | 2040 // causing problems. for instance, if you add one hour to April 5, |
1905 // 1998, 1:00 AM, in PST, the time becomes "2:00 AM PDT" (an | 2041 // 1998, 1:00 AM, in PST, the time becomes "2:00 AM PDT" (an |
1906 // illegal value), but then the adjustment sees the change and | 2042 // illegal value), but then the adjustment sees the change and |
1907 // compensates by subtracting an hour. As a result the time | 2043 // compensates by subtracting an hour. As a result the time |
1908 // doesn't advance at all. | 2044 // doesn't advance at all. |
1909 | 2045 |
1910 // For some fields larger than a day, such as a UCAL_MONTH, we pin the | 2046 // For some fields larger than a day, such as a UCAL_MONTH, we pin the |
1911 // UCAL_DAY_OF_MONTH. This allows <March 31>.add(UCAL_MONTH, 1) to be | 2047 // UCAL_DAY_OF_MONTH. This allows <March 31>.add(UCAL_MONTH, 1) to be |
1912 // <April 30>, rather than <April 31> => <May 1>. | 2048 // <April 30>, rather than <April 31> => <May 1>. |
1913 | 2049 |
1914 double delta = amount; // delta in ms | 2050 double delta = amount; // delta in ms |
1915 UBool keepHourInvariant = TRUE; | 2051 UBool keepWallTimeInvariant = TRUE; |
1916 | 2052 |
1917 switch (field) { | 2053 switch (field) { |
1918 case UCAL_ERA: | 2054 case UCAL_ERA: |
1919 set(field, get(field, status) + amount); | 2055 set(field, get(field, status) + amount); |
1920 pinField(UCAL_ERA, status); | 2056 pinField(UCAL_ERA, status); |
1921 return; | 2057 return; |
1922 | 2058 |
1923 case UCAL_YEAR: | 2059 case UCAL_YEAR: |
1924 case UCAL_YEAR_WOY: | 2060 case UCAL_YEAR_WOY: |
1925 { | 2061 { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1967 case UCAL_DAY_OF_YEAR: | 2103 case UCAL_DAY_OF_YEAR: |
1968 case UCAL_DAY_OF_WEEK: | 2104 case UCAL_DAY_OF_WEEK: |
1969 case UCAL_DOW_LOCAL: | 2105 case UCAL_DOW_LOCAL: |
1970 case UCAL_JULIAN_DAY: | 2106 case UCAL_JULIAN_DAY: |
1971 delta *= kOneDay; | 2107 delta *= kOneDay; |
1972 break; | 2108 break; |
1973 | 2109 |
1974 case UCAL_HOUR_OF_DAY: | 2110 case UCAL_HOUR_OF_DAY: |
1975 case UCAL_HOUR: | 2111 case UCAL_HOUR: |
1976 delta *= kOneHour; | 2112 delta *= kOneHour; |
1977 keepHourInvariant = FALSE; | 2113 keepWallTimeInvariant = FALSE; |
1978 break; | 2114 break; |
1979 | 2115 |
1980 case UCAL_MINUTE: | 2116 case UCAL_MINUTE: |
1981 delta *= kOneMinute; | 2117 delta *= kOneMinute; |
1982 keepHourInvariant = FALSE; | 2118 keepWallTimeInvariant = FALSE; |
1983 break; | 2119 break; |
1984 | 2120 |
1985 case UCAL_SECOND: | 2121 case UCAL_SECOND: |
1986 delta *= kOneSecond; | 2122 delta *= kOneSecond; |
1987 keepHourInvariant = FALSE; | 2123 keepWallTimeInvariant = FALSE; |
1988 break; | 2124 break; |
1989 | 2125 |
1990 case UCAL_MILLISECOND: | 2126 case UCAL_MILLISECOND: |
1991 case UCAL_MILLISECONDS_IN_DAY: | 2127 case UCAL_MILLISECONDS_IN_DAY: |
1992 keepHourInvariant = FALSE; | 2128 keepWallTimeInvariant = FALSE; |
1993 break; | 2129 break; |
1994 | 2130 |
1995 default: | 2131 default: |
1996 #if defined (U_DEBUG_CAL) | 2132 #if defined (U_DEBUG_CAL) |
1997 fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s not addable", | 2133 fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s not addable", |
1998 __FILE__, __LINE__, fldName(field)); | 2134 __FILE__, __LINE__, fldName(field)); |
1999 #endif | 2135 #endif |
2000 status = U_ILLEGAL_ARGUMENT_ERROR; | 2136 status = U_ILLEGAL_ARGUMENT_ERROR; |
2001 return; | 2137 return; |
2002 // throw new IllegalArgumentException("Calendar.add(" + fieldName(field
) + | 2138 // throw new IllegalArgumentException("Calendar.add(" + fieldName(field
) + |
2003 // ") not supported"); | 2139 // ") not supported"); |
2004 } | 2140 } |
2005 | 2141 |
2006 // In order to keep the hour invariant (for fields where this is | 2142 // In order to keep the wall time invariant (for fields where this is |
2007 // appropriate), check the combined DST & ZONE offset before and | 2143 // appropriate), check the combined DST & ZONE offset before and |
2008 // after the add() operation. If it changes, then adjust the millis | 2144 // after the add() operation. If it changes, then adjust the millis |
2009 // to compensate. | 2145 // to compensate. |
2010 int32_t prevOffset = 0; | 2146 int32_t prevOffset = 0; |
2011 int32_t hour = 0; | 2147 int32_t prevWallTime = 0; |
2012 if (keepHourInvariant) { | 2148 if (keepWallTimeInvariant) { |
2013 prevOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status
); | 2149 prevOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status
); |
2014 hour = internalGet(UCAL_HOUR_OF_DAY); | 2150 prevWallTime = get(UCAL_MILLISECONDS_IN_DAY, status); |
2015 } | 2151 } |
2016 | 2152 |
2017 setTimeInMillis(getTimeInMillis(status) + delta, status); | 2153 setTimeInMillis(getTimeInMillis(status) + delta, status); |
2018 | 2154 |
2019 if (keepHourInvariant) { | 2155 if (keepWallTimeInvariant) { |
2020 int32_t newOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET,
status); | 2156 int32_t newWallTime = get(UCAL_MILLISECONDS_IN_DAY, status); |
2021 if (newOffset != prevOffset) { | 2157 if (newWallTime != prevWallTime) { |
2022 // We have done an hour-invariant adjustment but the | 2158 // There is at least one zone transition between the base |
2023 // combined offset has changed. We adjust millis to keep | 2159 // time and the result time. As the result, wall time has |
2024 // the hour constant. In cases such as midnight after | 2160 // changed. |
2025 // a DST change which occurs at midnight, there is the | 2161 UDate t = internalGetTime(); |
2026 // danger of adjusting into a different day. To avoid | 2162 int32_t newOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFF
SET, status); |
2027 // this we make the adjustment only if it actually | 2163 if (newOffset != prevOffset) { |
2028 // maintains the hour. | 2164 // When the difference of the previous UTC offset and |
2029 | 2165 // the new UTC offset exceeds 1 full day, we do not want |
2030 // When the difference of the previous UTC offset and | 2166 // to roll over/back the date. For now, this only happens |
2031 // the new UTC offset exceeds 1 full day, we do not want | 2167 // in Samoa (Pacific/Apia) on Dec 30, 2011. See ticket:9452. |
2032 // to roll over/back the date. For now, this only happens | 2168 int32_t adjAmount = prevOffset - newOffset; |
2033 // in Samoa (Pacific/Apia) on Dec 30, 2011. See ticket:9452. | 2169 adjAmount = adjAmount >= 0 ? adjAmount % (int32_t)kOneDay : -(-a
djAmount % (int32_t)kOneDay); |
2034 int32_t adjAmount = prevOffset - newOffset; | 2170 if (adjAmount != 0) { |
2035 adjAmount = adjAmount >= 0 ? adjAmount % (int32_t)kOneDay : -(-adjAm
ount % (int32_t)kOneDay); | 2171 setTimeInMillis(t + adjAmount, status); |
2036 if (adjAmount != 0) { | 2172 newWallTime = get(UCAL_MILLISECONDS_IN_DAY, status); |
2037 double t = internalGetTime(); | 2173 } |
2038 setTimeInMillis(t + adjAmount, status); | 2174 if (newWallTime != prevWallTime) { |
2039 if (get(UCAL_HOUR_OF_DAY, status) != hour) { | 2175 // The result wall time or adjusted wall time was shifted be
cause |
2040 setTimeInMillis(t, status); | 2176 // the target wall time does not exist on the result date. |
| 2177 switch (fSkippedWallTime) { |
| 2178 case UCAL_WALLTIME_FIRST: |
| 2179 if (adjAmount > 0) { |
| 2180 setTimeInMillis(t, status); |
| 2181 } |
| 2182 break; |
| 2183 case UCAL_WALLTIME_LAST: |
| 2184 if (adjAmount < 0) { |
| 2185 setTimeInMillis(t, status); |
| 2186 } |
| 2187 break; |
| 2188 case UCAL_WALLTIME_NEXT_VALID: |
| 2189 UDate tmpT = adjAmount > 0 ? internalGetTime() : t; |
| 2190 UDate immediatePrevTrans; |
| 2191 UBool hasTransition = getImmediatePreviousZoneTransition
(tmpT, &immediatePrevTrans, status); |
| 2192 if (U_SUCCESS(status) && hasTransition) { |
| 2193 setTimeInMillis(immediatePrevTrans, status); |
| 2194 } |
| 2195 break; |
| 2196 } |
2041 } | 2197 } |
2042 } | 2198 } |
2043 } | 2199 } |
2044 } | 2200 } |
2045 } | 2201 } |
2046 | 2202 |
2047 // ------------------------------------- | 2203 // ------------------------------------- |
2048 int32_t Calendar::fieldDifference(UDate when, EDateFields field, UErrorCode& sta
tus) { | 2204 int32_t Calendar::fieldDifference(UDate when, EDateFields field, UErrorCode& sta
tus) { |
2049 return fieldDifference(when, (UCalendarDateFields) field, status); | 2205 return fieldDifference(when, (UCalendarDateFields) field, status); |
2050 } | 2206 } |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2151 | 2307 |
2152 // ------------------------------------- | 2308 // ------------------------------------- |
2153 | 2309 |
2154 void | 2310 void |
2155 Calendar::adoptTimeZone(TimeZone* zone) | 2311 Calendar::adoptTimeZone(TimeZone* zone) |
2156 { | 2312 { |
2157 // Do nothing if passed-in zone is NULL | 2313 // Do nothing if passed-in zone is NULL |
2158 if (zone == NULL) return; | 2314 if (zone == NULL) return; |
2159 | 2315 |
2160 // fZone should always be non-null | 2316 // fZone should always be non-null |
2161 if (fZone != NULL) delete fZone; | 2317 delete fZone; |
2162 fZone = zone; | 2318 fZone = zone; |
2163 | 2319 |
2164 // if the zone changes, we need to recompute the time fields | 2320 // if the zone changes, we need to recompute the time fields |
2165 fAreFieldsSet = FALSE; | 2321 fAreFieldsSet = FALSE; |
2166 } | 2322 } |
2167 | 2323 |
2168 // ------------------------------------- | 2324 // ------------------------------------- |
2169 void | 2325 void |
2170 Calendar::setTimeZone(const TimeZone& zone) | 2326 Calendar::setTimeZone(const TimeZone& zone) |
2171 { | 2327 { |
2172 adoptTimeZone(zone.clone()); | 2328 adoptTimeZone(zone.clone()); |
2173 } | 2329 } |
2174 | 2330 |
2175 // ------------------------------------- | 2331 // ------------------------------------- |
2176 | 2332 |
2177 const TimeZone& | 2333 const TimeZone& |
2178 Calendar::getTimeZone() const | 2334 Calendar::getTimeZone() const |
2179 { | 2335 { |
| 2336 U_ASSERT(fZone != NULL); |
2180 return *fZone; | 2337 return *fZone; |
2181 } | 2338 } |
2182 | 2339 |
2183 // ------------------------------------- | 2340 // ------------------------------------- |
2184 | 2341 |
2185 TimeZone* | 2342 TimeZone* |
2186 Calendar::orphanTimeZone() | 2343 Calendar::orphanTimeZone() |
2187 { | 2344 { |
| 2345 // we let go of the time zone; the new time zone is the system default time
zone |
| 2346 TimeZone *defaultZone = TimeZone::createDefault(); |
| 2347 if (defaultZone == NULL) { |
| 2348 // No error handling available. Must keep fZone non-NULL, there are many
unchecked uses. |
| 2349 return NULL; |
| 2350 } |
2188 TimeZone *z = fZone; | 2351 TimeZone *z = fZone; |
2189 // we let go of the time zone; the new time zone is the system default time
zone | 2352 fZone = defaultZone; |
2190 fZone = TimeZone::createDefault(); | |
2191 return z; | 2353 return z; |
2192 } | 2354 } |
2193 | 2355 |
2194 // ------------------------------------- | 2356 // ------------------------------------- |
2195 | 2357 |
2196 void | 2358 void |
2197 Calendar::setLenient(UBool lenient) | 2359 Calendar::setLenient(UBool lenient) |
2198 { | 2360 { |
2199 fLenient = lenient; | 2361 fLenient = lenient; |
2200 } | 2362 } |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2299 UCalendarWeekdayType | 2461 UCalendarWeekdayType |
2300 Calendar::getDayOfWeekType(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) co
nst | 2462 Calendar::getDayOfWeekType(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) co
nst |
2301 { | 2463 { |
2302 if (U_FAILURE(status)) { | 2464 if (U_FAILURE(status)) { |
2303 return UCAL_WEEKDAY; | 2465 return UCAL_WEEKDAY; |
2304 } | 2466 } |
2305 if (dayOfWeek < UCAL_SUNDAY || dayOfWeek > UCAL_SATURDAY) { | 2467 if (dayOfWeek < UCAL_SUNDAY || dayOfWeek > UCAL_SATURDAY) { |
2306 status = U_ILLEGAL_ARGUMENT_ERROR; | 2468 status = U_ILLEGAL_ARGUMENT_ERROR; |
2307 return UCAL_WEEKDAY; | 2469 return UCAL_WEEKDAY; |
2308 } | 2470 } |
2309 » if (fWeekendOnset == fWeekendCease) { | 2471 if (fWeekendOnset == fWeekendCease) { |
2310 » » if (dayOfWeek != fWeekendOnset) | 2472 if (dayOfWeek != fWeekendOnset) |
2311 » » » return UCAL_WEEKDAY; | 2473 return UCAL_WEEKDAY; |
2312 » » return (fWeekendOnsetMillis == 0) ? UCAL_WEEKEND : UCAL_WEEKEND_
ONSET; | 2474 return (fWeekendOnsetMillis == 0) ? UCAL_WEEKEND : UCAL_WEEKEND_ONSET; |
2313 » } | 2475 } |
2314 if (fWeekendOnset < fWeekendCease) { | 2476 if (fWeekendOnset < fWeekendCease) { |
2315 if (dayOfWeek < fWeekendOnset || dayOfWeek > fWeekendCease) { | 2477 if (dayOfWeek < fWeekendOnset || dayOfWeek > fWeekendCease) { |
2316 return UCAL_WEEKDAY; | 2478 return UCAL_WEEKDAY; |
2317 } | 2479 } |
2318 } else { | 2480 } else { |
2319 if (dayOfWeek > fWeekendCease && dayOfWeek < fWeekendOnset) { | 2481 if (dayOfWeek > fWeekendCease && dayOfWeek < fWeekendOnset) { |
2320 return UCAL_WEEKDAY; | 2482 return UCAL_WEEKDAY; |
2321 } | 2483 } |
2322 } | 2484 } |
2323 if (dayOfWeek == fWeekendOnset) { | 2485 if (dayOfWeek == fWeekendOnset) { |
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2811 // zoneOffset != (raw + dst) only when the given wall time fall
into | 2973 // zoneOffset != (raw + dst) only when the given wall time fall
into |
2812 // a skipped wall time range caused by positive zone offset tran
sition. | 2974 // a skipped wall time range caused by positive zone offset tran
sition. |
2813 if (zoneOffset != (raw + dst)) { | 2975 if (zoneOffset != (raw + dst)) { |
2814 if (!isLenient()) { | 2976 if (!isLenient()) { |
2815 status = U_ILLEGAL_ARGUMENT_ERROR; | 2977 status = U_ILLEGAL_ARGUMENT_ERROR; |
2816 } else { | 2978 } else { |
2817 U_ASSERT(fSkippedWallTime == UCAL_WALLTIME_NEXT_VALID); | 2979 U_ASSERT(fSkippedWallTime == UCAL_WALLTIME_NEXT_VALID); |
2818 // Adjust time to the next valid wall clock time. | 2980 // Adjust time to the next valid wall clock time. |
2819 // At this point, tmpTime is on or after the zone offset
transition causing | 2981 // At this point, tmpTime is on or after the zone offset
transition causing |
2820 // the skipped time range. | 2982 // the skipped time range. |
2821 | 2983 UDate immediatePrevTransition; |
2822 BasicTimeZone *btz = getBasicTimeZone(); | 2984 UBool hasTransition = getImmediatePreviousZoneTransition
(tmpTime, &immediatePrevTransition, status); |
2823 if (btz) { | 2985 if (U_SUCCESS(status) && hasTransition) { |
2824 TimeZoneTransition transition; | 2986 t = immediatePrevTransition; |
2825 UBool hasTransition = btz->getPreviousTransition(tmp
Time, TRUE, transition); | |
2826 if (hasTransition) { | |
2827 t = transition.getTime(); | |
2828 } else { | |
2829 // Could not find any transitions. | |
2830 // Note: This should never happen. | |
2831 status = U_INTERNAL_PROGRAM_ERROR; | |
2832 } | |
2833 } else { | |
2834 // If not BasicTimeZone, return unsupported error fo
r now. | |
2835 // TODO: We may support non-BasicTimeZone in future. | |
2836 status = U_UNSUPPORTED_ERROR; | |
2837 } | 2987 } |
2838 } | 2988 } |
2839 } else { | 2989 } else { |
2840 t = tmpTime; | 2990 t = tmpTime; |
2841 } | 2991 } |
2842 } | 2992 } |
2843 } else { | 2993 } else { |
2844 t = millis + millisInDay - computeZoneOffset(millis, millisInDay, st
atus); | 2994 t = millis + millisInDay - computeZoneOffset(millis, millisInDay, st
atus); |
2845 } | 2995 } |
2846 } | 2996 } |
2847 if (U_SUCCESS(status)) { | 2997 if (U_SUCCESS(status)) { |
2848 internalSetTime(t); | 2998 internalSetTime(t); |
2849 } | 2999 } |
2850 } | 3000 } |
2851 | 3001 |
2852 /** | 3002 /** |
| 3003 * Find the previous zone transtion near the given time. |
| 3004 */ |
| 3005 UBool Calendar::getImmediatePreviousZoneTransition(UDate base, UDate *transition
Time, UErrorCode& status) const { |
| 3006 BasicTimeZone *btz = getBasicTimeZone(); |
| 3007 if (btz) { |
| 3008 TimeZoneTransition trans; |
| 3009 UBool hasTransition = btz->getPreviousTransition(base, TRUE, trans); |
| 3010 if (hasTransition) { |
| 3011 *transitionTime = trans.getTime(); |
| 3012 return TRUE; |
| 3013 } else { |
| 3014 // Could not find any transitions. |
| 3015 // Note: This should never happen. |
| 3016 status = U_INTERNAL_PROGRAM_ERROR; |
| 3017 } |
| 3018 } else { |
| 3019 // If not BasicTimeZone, return unsupported error for now. |
| 3020 // TODO: We may support non-BasicTimeZone in future. |
| 3021 status = U_UNSUPPORTED_ERROR; |
| 3022 } |
| 3023 return FALSE; |
| 3024 } |
| 3025 |
| 3026 /** |
2853 * Compute the milliseconds in the day from the fields. This is a | 3027 * Compute the milliseconds in the day from the fields. This is a |
2854 * value from 0 to 23:59:59.999 inclusive, unless fields are out of | 3028 * value from 0 to 23:59:59.999 inclusive, unless fields are out of |
2855 * range, in which case it can be an arbitrary value. This value | 3029 * range, in which case it can be an arbitrary value. This value |
2856 * reflects local zone wall time. | 3030 * reflects local zone wall time. |
2857 * @stable ICU 2.0 | 3031 * @stable ICU 2.0 |
2858 */ | 3032 */ |
2859 int32_t Calendar::computeMillisInDay() { | 3033 int32_t Calendar::computeMillisInDay() { |
2860 // Do the time portion of the conversion. | 3034 // Do the time portion of the conversion. |
2861 | 3035 |
2862 int32_t millisInDay = 0; | 3036 int32_t millisInDay = 0; |
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3229 // WEEK_OF_YEAR, which are similar, or the DAY_OF_WEEK_IN_MONTH. | 3403 // WEEK_OF_YEAR, which are similar, or the DAY_OF_WEEK_IN_MONTH. |
3230 // First, perform initial shared computations. These locate the | 3404 // First, perform initial shared computations. These locate the |
3231 // first week of the period. | 3405 // first week of the period. |
3232 | 3406 |
3233 // Get the 0-based localized DOW of day one of the month or year. | 3407 // Get the 0-based localized DOW of day one of the month or year. |
3234 // Valid range 0..6. | 3408 // Valid range 0..6. |
3235 int32_t first = julianDayToDayOfWeek(jan1Start + 1) - firstDayOfWeek; | 3409 int32_t first = julianDayToDayOfWeek(jan1Start + 1) - firstDayOfWeek; |
3236 if (first < 0) { | 3410 if (first < 0) { |
3237 first += 7; | 3411 first += 7; |
3238 } | 3412 } |
3239 int32_t nextFirst = julianDayToDayOfWeek(nextJan1Start + 1) - firstDayOfWeek
; | 3413 |
3240 if (nextFirst < 0) { | 3414 //// (nextFirst was not used below) |
3241 nextFirst += 7; | 3415 // int32_t nextFirst = julianDayToDayOfWeek(nextJan1Start + 1) - firstDayOfW
eek; |
3242 } | 3416 // if (nextFirst < 0) { |
| 3417 // nextFirst += 7; |
| 3418 //} |
3243 | 3419 |
3244 int32_t minDays = getMinimalDaysInFirstWeek(); | 3420 int32_t minDays = getMinimalDaysInFirstWeek(); |
3245 UBool jan1InPrevYear = FALSE; // January 1st in the year of WOY is the 1st
week? (i.e. first week is < minimal ) | 3421 UBool jan1InPrevYear = FALSE; // January 1st in the year of WOY is the 1st
week? (i.e. first week is < minimal ) |
3246 //UBool nextJan1InPrevYear = FALSE; // January 1st of Year of WOY + 1 is in
the first week? | 3422 //UBool nextJan1InPrevYear = FALSE; // January 1st of Year of WOY + 1 is in
the first week? |
3247 | 3423 |
3248 if((7 - first) < minDays) { | 3424 if((7 - first) < minDays) { |
3249 jan1InPrevYear = TRUE; | 3425 jan1InPrevYear = TRUE; |
3250 } | 3426 } |
3251 | 3427 |
3252 // if((7 - nextFirst) < minDays) { | 3428 // if((7 - nextFirst) < minDays) { |
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3690 return NULL; | 3866 return NULL; |
3691 } | 3867 } |
3692 | 3868 |
3693 U_NAMESPACE_END | 3869 U_NAMESPACE_END |
3694 | 3870 |
3695 #endif /* #if !UCONFIG_NO_FORMATTING */ | 3871 #endif /* #if !UCONFIG_NO_FORMATTING */ |
3696 | 3872 |
3697 | 3873 |
3698 //eof | 3874 //eof |
3699 | 3875 |
OLD | NEW |