Bug Summary

File:root/firefox-clang/intl/icu/source/i18n/islamcal.cpp
Warning:line 536, column 13
Although the value stored to 'startDate' is used in the enclosing expression, the value is never actually read from 'startDate'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name islamcal.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/icu/i18n -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/icu/i18n -resource-dir /usr/lib/llvm-21/lib/clang/21 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D U_I18N_IMPLEMENTATION -D _LIBCPP_DISABLE_DEPRECATION_WARNINGS -D U_USING_ICU_NAMESPACE=0 -D U_NO_DEFAULT_INCLUDE_UTF_HEADERS=1 -D U_HIDE_OBSOLETE_UTF_OLD_H=1 -D UCONFIG_NO_LEGACY_CONVERSION -D UCONFIG_NO_TRANSLITERATION -D UCONFIG_NO_REGULAR_EXPRESSIONS -D UCONFIG_NO_BREAK_ITERATION -D UCONFIG_NO_IDNA -D UCONFIG_NO_MF2 -D U_CHARSET_IS_UTF8 -D UNISTR_FROM_CHAR_EXPLICIT=explicit -D UNISTR_FROM_STRING_EXPLICIT=explicit -D U_ENABLE_DYLOAD=0 -D U_DEBUG=1 -I /root/firefox-clang/config/external/icu/i18n -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/config/external/icu/i18n -I /root/firefox-clang/intl/icu/source/common -I /root/firefox-clang/mfbt/double-conversion -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-comma -Wno-implicit-const-int-float-conversion -Wno-macro-redefined -Wno-microsoft-include -Wno-tautological-unsigned-enum-zero-compare -Wno-unreachable-code-loop-increment -Wno-unreachable-code-return -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-06-27-100320-3286336-1 -x c++ /root/firefox-clang/intl/icu/source/i18n/islamcal.cpp
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4******************************************************************************
5* Copyright (C) 2003-2015, International Business Machines Corporation
6* and others. All Rights Reserved.
7******************************************************************************
8*
9* File ISLAMCAL.H
10*
11* Modification History:
12*
13* Date Name Description
14* 10/14/2003 srl ported from java IslamicCalendar
15*****************************************************************************
16*/
17
18#include "islamcal.h"
19
20#if !UCONFIG_NO_FORMATTING0
21
22#include "umutex.h"
23#include <float.h>
24#include "gregoimp.h" // Math
25#include "astro.h" // CalendarAstronomer
26#include "uhash.h"
27#include "ucln_in.h"
28#include "uassert.h"
29
30static const UDate HIJRA_MILLIS = -42521587200000.0; // 7/16/622 AD 00:00
31
32// Debugging
33#ifdef U_DEBUG_ISLAMCAL
34# include <stdio.h>
35# include <stdarg.h>
36static void debug_islamcal_loc(const char *f, int32_t l)
37{
38 fprintf(stderrstderr, "%s:%d: ", f, l);
39}
40
41static void debug_islamcal_msg(const char *pat, ...)
42{
43 va_list ap;
44 va_start(ap, pat);
45 vfprintf(stderrstderr, pat, ap);
46 fflush(stderrstderr);
47}
48// must use double parens, i.e.: U_DEBUG_ISLAMCAL_MSG(("four is: %d",4));
49#define U_DEBUG_ISLAMCAL_MSG(x) {debug_islamcal_loc(__FILE__"/root/firefox-clang/intl/icu/source/i18n/islamcal.cpp",__LINE__49);debug_islamcal_msg x;}
50#else
51#define U_DEBUG_ISLAMCAL_MSG(x)
52#endif
53
54
55// --- The cache --
56// cache of months
57static icu::CalendarCache *gMonthCache = nullptr;
58
59U_CDECL_BEGINextern "C" {
60static UBool calendar_islamic_cleanup() {
61 if (gMonthCache) {
62 delete gMonthCache;
63 gMonthCache = nullptr;
64 }
65 return true;
66}
67U_CDECL_END}
68
69U_NAMESPACE_BEGINnamespace icu_77 {
70
71// Implementation of the IslamicCalendar class
72
73/**
74 * Friday EPOC
75 */
76static const int32_t CIVIL_EPOC = 1948440; // CE 622 July 16 Friday (Julian calendar) / CE 622 July 19 (Gregorian calendar)
77
78/**
79 * Thursday EPOC
80 */
81static const int32_t ASTRONOMICAL_EPOC = 1948439; // CE 622 July 15 Thursday (Julian calendar)
82
83
84static const int32_t UMALQURA_YEAR_START = 1300;
85static const int32_t UMALQURA_YEAR_END = 1600;
86
87static const int UMALQURA_MONTHLENGTH[] = {
88 //* 1300 -1302 */ "1010 1010 1010", "1101 0101 0100", "1110 1100 1001",
89 0x0AAA, 0x0D54, 0x0EC9,
90 //* 1303 -1307 */ "0110 1101 0100", "0110 1110 1010", "0011 0110 1100", "1010 1010 1101", "0101 0101 0101",
91 0x06D4, 0x06EA, 0x036C, 0x0AAD, 0x0555,
92 //* 1308 -1312 */ "0110 1010 1001", "0111 1001 0010", "1011 1010 1001", "0101 1101 0100", "1010 1101 1010",
93 0x06A9, 0x0792, 0x0BA9, 0x05D4, 0x0ADA,
94 //* 1313 -1317 */ "0101 0101 1100", "1101 0010 1101", "0110 1001 0101", "0111 0100 1010", "1011 0101 0100",
95 0x055C, 0x0D2D, 0x0695, 0x074A, 0x0B54,
96 //* 1318 -1322 */ "1011 0110 1010", "0101 1010 1101", "0100 1010 1110", "1010 0100 1111", "0101 0001 0111",
97 0x0B6A, 0x05AD, 0x04AE, 0x0A4F, 0x0517,
98 //* 1323 -1327 */ "0110 1000 1011", "0110 1010 0101", "1010 1101 0101", "0010 1101 0110", "1001 0101 1011",
99 0x068B, 0x06A5, 0x0AD5, 0x02D6, 0x095B,
100 //* 1328 -1332 */ "0100 1001 1101", "1010 0100 1101", "1101 0010 0110", "1101 1001 0101", "0101 1010 1100",
101 0x049D, 0x0A4D, 0x0D26, 0x0D95, 0x05AC,
102 //* 1333 -1337 */ "1001 1011 0110", "0010 1011 1010", "1010 0101 1011", "0101 0010 1011", "1010 1001 0101",
103 0x09B6, 0x02BA, 0x0A5B, 0x052B, 0x0A95,
104 //* 1338 -1342 */ "0110 1100 1010", "1010 1110 1001", "0010 1111 0100", "1001 0111 0110", "0010 1011 0110",
105 0x06CA, 0x0AE9, 0x02F4, 0x0976, 0x02B6,
106 //* 1343 -1347 */ "1001 0101 0110", "1010 1100 1010", "1011 1010 0100", "1011 1101 0010", "0101 1101 1001",
107 0x0956, 0x0ACA, 0x0BA4, 0x0BD2, 0x05D9,
108 //* 1348 -1352 */ "0010 1101 1100", "1001 0110 1101", "0101 0100 1101", "1010 1010 0101", "1011 0101 0010",
109 0x02DC, 0x096D, 0x054D, 0x0AA5, 0x0B52,
110 //* 1353 -1357 */ "1011 1010 0101", "0101 1011 0100", "1001 1011 0110", "0101 0101 0111", "0010 1001 0111",
111 0x0BA5, 0x05B4, 0x09B6, 0x0557, 0x0297,
112 //* 1358 -1362 */ "0101 0100 1011", "0110 1010 0011", "0111 0101 0010", "1011 0110 0101", "0101 0110 1010",
113 0x054B, 0x06A3, 0x0752, 0x0B65, 0x056A,
114 //* 1363 -1367 */ "1010 1010 1011", "0101 0010 1011", "1100 1001 0101", "1101 0100 1010", "1101 1010 0101",
115 0x0AAB, 0x052B, 0x0C95, 0x0D4A, 0x0DA5,
116 //* 1368 -1372 */ "0101 1100 1010", "1010 1101 0110", "1001 0101 0111", "0100 1010 1011", "1001 0100 1011",
117 0x05CA, 0x0AD6, 0x0957, 0x04AB, 0x094B,
118 //* 1373 -1377 */ "1010 1010 0101", "1011 0101 0010", "1011 0110 1010", "0101 0111 0101", "0010 0111 0110",
119 0x0AA5, 0x0B52, 0x0B6A, 0x0575, 0x0276,
120 //* 1378 -1382 */ "1000 1011 0111", "0100 0101 1011", "0101 0101 0101", "0101 1010 1001", "0101 1011 0100",
121 0x08B7, 0x045B, 0x0555, 0x05A9, 0x05B4,
122 //* 1383 -1387 */ "1001 1101 1010", "0100 1101 1101", "0010 0110 1110", "1001 0011 0110", "1010 1010 1010",
123 0x09DA, 0x04DD, 0x026E, 0x0936, 0x0AAA,
124 //* 1388 -1392 */ "1101 0101 0100", "1101 1011 0010", "0101 1101 0101", "0010 1101 1010", "1001 0101 1011",
125 0x0D54, 0x0DB2, 0x05D5, 0x02DA, 0x095B,
126 //* 1393 -1397 */ "0100 1010 1011", "1010 0101 0101", "1011 0100 1001", "1011 0110 0100", "1011 0111 0001",
127 0x04AB, 0x0A55, 0x0B49, 0x0B64, 0x0B71,
128 //* 1398 -1402 */ "0101 1011 0100", "1010 1011 0101", "1010 0101 0101", "1101 0010 0101", "1110 1001 0010",
129 0x05B4, 0x0AB5, 0x0A55, 0x0D25, 0x0E92,
130 //* 1403 -1407 */ "1110 1100 1001", "0110 1101 0100", "1010 1110 1001", "1001 0110 1011", "0100 1010 1011",
131 0x0EC9, 0x06D4, 0x0AE9, 0x096B, 0x04AB,
132 //* 1408 -1412 */ "1010 1001 0011", "1101 0100 1001", "1101 1010 0100", "1101 1011 0010", "1010 1011 1001",
133 0x0A93, 0x0D49, 0x0DA4, 0x0DB2, 0x0AB9,
134 //* 1413 -1417 */ "0100 1011 1010", "1010 0101 1011", "0101 0010 1011", "1010 1001 0101", "1011 0010 1010",
135 0x04BA, 0x0A5B, 0x052B, 0x0A95, 0x0B2A,
136 //* 1418 -1422 */ "1011 0101 0101", "0101 0101 1100", "0100 1011 1101", "0010 0011 1101", "1001 0001 1101",
137 0x0B55, 0x055C, 0x04BD, 0x023D, 0x091D,
138 //* 1423 -1427 */ "1010 1001 0101", "1011 0100 1010", "1011 0101 1010", "0101 0110 1101", "0010 1011 0110",
139 0x0A95, 0x0B4A, 0x0B5A, 0x056D, 0x02B6,
140 //* 1428 -1432 */ "1001 0011 1011", "0100 1001 1011", "0110 0101 0101", "0110 1010 1001", "0111 0101 0100",
141 0x093B, 0x049B, 0x0655, 0x06A9, 0x0754,
142 //* 1433 -1437 */ "1011 0110 1010", "0101 0110 1100", "1010 1010 1101", "0101 0101 0101", "1011 0010 1001",
143 0x0B6A, 0x056C, 0x0AAD, 0x0555, 0x0B29,
144 //* 1438 -1442 */ "1011 1001 0010", "1011 1010 1001", "0101 1101 0100", "1010 1101 1010", "0101 0101 1010",
145 0x0B92, 0x0BA9, 0x05D4, 0x0ADA, 0x055A,
146 //* 1443 -1447 */ "1010 1010 1011", "0101 1001 0101", "0111 0100 1001", "0111 0110 0100", "1011 1010 1010",
147 0x0AAB, 0x0595, 0x0749, 0x0764, 0x0BAA,
148 //* 1448 -1452 */ "0101 1011 0101", "0010 1011 0110", "1010 0101 0110", "1110 0100 1101", "1011 0010 0101",
149 0x05B5, 0x02B6, 0x0A56, 0x0E4D, 0x0B25,
150 //* 1453 -1457 */ "1011 0101 0010", "1011 0110 1010", "0101 1010 1101", "0010 1010 1110", "1001 0010 1111",
151 0x0B52, 0x0B6A, 0x05AD, 0x02AE, 0x092F,
152 //* 1458 -1462 */ "0100 1001 0111", "0110 0100 1011", "0110 1010 0101", "0110 1010 1100", "1010 1101 0110",
153 0x0497, 0x064B, 0x06A5, 0x06AC, 0x0AD6,
154 //* 1463 -1467 */ "0101 0101 1101", "0100 1001 1101", "1010 0100 1101", "1101 0001 0110", "1101 1001 0101",
155 0x055D, 0x049D, 0x0A4D, 0x0D16, 0x0D95,
156 //* 1468 -1472 */ "0101 1010 1010", "0101 1011 0101", "0010 1101 1010", "1001 0101 1011", "0100 1010 1101",
157 0x05AA, 0x05B5, 0x02DA, 0x095B, 0x04AD,
158 //* 1473 -1477 */ "0101 1001 0101", "0110 1100 1010", "0110 1110 0100", "1010 1110 1010", "0100 1111 0101",
159 0x0595, 0x06CA, 0x06E4, 0x0AEA, 0x04F5,
160 //* 1478 -1482 */ "0010 1011 0110", "1001 0101 0110", "1010 1010 1010", "1011 0101 0100", "1011 1101 0010",
161 0x02B6, 0x0956, 0x0AAA, 0x0B54, 0x0BD2,
162 //* 1483 -1487 */ "0101 1101 1001", "0010 1110 1010", "1001 0110 1101", "0100 1010 1101", "1010 1001 0101",
163 0x05D9, 0x02EA, 0x096D, 0x04AD, 0x0A95,
164 //* 1488 -1492 */ "1011 0100 1010", "1011 1010 0101", "0101 1011 0010", "1001 1011 0101", "0100 1101 0110",
165 0x0B4A, 0x0BA5, 0x05B2, 0x09B5, 0x04D6,
166 //* 1493 -1497 */ "1010 1001 0111", "0101 0100 0111", "0110 1001 0011", "0111 0100 1001", "1011 0101 0101",
167 0x0A97, 0x0547, 0x0693, 0x0749, 0x0B55,
168 //* 1498 -1508 */ "0101 0110 1010", "1010 0110 1011", "0101 0010 1011", "1010 1000 1011", "1101 0100 0110", "1101 1010 0011", "0101 1100 1010", "1010 1101 0110", "0100 1101 1011", "0010 0110 1011", "1001 0100 1011",
169 0x056A, 0x0A6B, 0x052B, 0x0A8B, 0x0D46, 0x0DA3, 0x05CA, 0x0AD6, 0x04DB, 0x026B, 0x094B,
170 //* 1509 -1519 */ "1010 1010 0101", "1011 0101 0010", "1011 0110 1001", "0101 0111 0101", "0001 0111 0110", "1000 1011 0111", "0010 0101 1011", "0101 0010 1011", "0101 0110 0101", "0101 1011 0100", "1001 1101 1010",
171 0x0AA5, 0x0B52, 0x0B69, 0x0575, 0x0176, 0x08B7, 0x025B, 0x052B, 0x0565, 0x05B4, 0x09DA,
172 //* 1520 -1530 */ "0100 1110 1101", "0001 0110 1101", "1000 1011 0110", "1010 1010 0110", "1101 0101 0010", "1101 1010 1001", "0101 1101 0100", "1010 1101 1010", "1001 0101 1011", "0100 1010 1011", "0110 0101 0011",
173 0x04ED, 0x016D, 0x08B6, 0x0AA6, 0x0D52, 0x0DA9, 0x05D4, 0x0ADA, 0x095B, 0x04AB, 0x0653,
174 //* 1531 -1541 */ "0111 0010 1001", "0111 0110 0010", "1011 1010 1001", "0101 1011 0010", "1010 1011 0101", "0101 0101 0101", "1011 0010 0101", "1101 1001 0010", "1110 1100 1001", "0110 1101 0010", "1010 1110 1001",
175 0x0729, 0x0762, 0x0BA9, 0x05B2, 0x0AB5, 0x0555, 0x0B25, 0x0D92, 0x0EC9, 0x06D2, 0x0AE9,
176 //* 1542 -1552 */ "0101 0110 1011", "0100 1010 1011", "1010 0101 0101", "1101 0010 1001", "1101 0101 0100", "1101 1010 1010", "1001 1011 0101", "0100 1011 1010", "1010 0011 1011", "0100 1001 1011", "1010 0100 1101",
177 0x056B, 0x04AB, 0x0A55, 0x0D29, 0x0D54, 0x0DAA, 0x09B5, 0x04BA, 0x0A3B, 0x049B, 0x0A4D,
178 //* 1553 -1563 */ "1010 1010 1010", "1010 1101 0101", "0010 1101 1010", "1001 0101 1101", "0100 0101 1110", "1010 0010 1110", "1100 1001 1010", "1101 0101 0101", "0110 1011 0010", "0110 1011 1001", "0100 1011 1010",
179 0x0AAA, 0x0AD5, 0x02DA, 0x095D, 0x045E, 0x0A2E, 0x0C9A, 0x0D55, 0x06B2, 0x06B9, 0x04BA,
180 //* 1564 -1574 */ "1010 0101 1101", "0101 0010 1101", "1010 1001 0101", "1011 0101 0010", "1011 1010 1000", "1011 1011 0100", "0101 1011 1001", "0010 1101 1010", "1001 0101 1010", "1011 0100 1010", "1101 1010 0100",
181 0x0A5D, 0x052D, 0x0A95, 0x0B52, 0x0BA8, 0x0BB4, 0x05B9, 0x02DA, 0x095A, 0x0B4A, 0x0DA4,
182 //* 1575 -1585 */ "1110 1101 0001", "0110 1110 1000", "1011 0110 1010", "0101 0110 1101", "0101 0011 0101", "0110 1001 0101", "1101 0100 1010", "1101 1010 1000", "1101 1101 0100", "0110 1101 1010", "0101 0101 1011",
183 0x0ED1, 0x06E8, 0x0B6A, 0x056D, 0x0535, 0x0695, 0x0D4A, 0x0DA8, 0x0DD4, 0x06DA, 0x055B,
184 //* 1586 -1596 */ "0010 1001 1101", "0110 0010 1011", "1011 0001 0101", "1011 0100 1010", "1011 1001 0101", "0101 1010 1010", "1010 1010 1110", "1001 0010 1110", "1100 1000 1111", "0101 0010 0111", "0110 1001 0101",
185 0x029D, 0x062B, 0x0B15, 0x0B4A, 0x0B95, 0x05AA, 0x0AAE, 0x092E, 0x0C8F, 0x0527, 0x0695,
186 //* 1597 -1600 */ "0110 1010 1010", "1010 1101 0110", "0101 0101 1101", "0010 1001 1101", };
187 0x06AA, 0x0AD6, 0x055D, 0x029D
188};
189
190//-------------------------------------------------------------------------
191// Constructors...
192//-------------------------------------------------------------------------
193
194const char *IslamicCalendar::getType() const {
195 return "islamic";
196}
197
198IslamicCalendar* IslamicCalendar::clone() const {
199 return new IslamicCalendar(*this);
200}
201
202IslamicCalendar::IslamicCalendar(const Locale& aLocale, UErrorCode& success)
203: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
204{
205}
206
207IslamicCalendar::~IslamicCalendar()
208{
209}
210//-------------------------------------------------------------------------
211// Minimum / Maximum access functions
212//-------------------------------------------------------------------------
213
214// Note: Current IslamicCalendar implementation does not work
215// well with negative years.
216
217// TODO: In some cases the current ICU Islamic calendar implementation shows
218// a month as having 31 days. Since date parsing now uses range checks based
219// on the table below, we need to change the range for last day of month to
220// include 31 as a workaround until the implementation is fixed.
221static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
222 // Minimum Greatest Least Maximum
223 // Minimum Maximum
224 { 0, 0, 0, 0}, // ERA
225 { 1, 1, 5000000, 5000000}, // YEAR
226 { 0, 0, 11, 11}, // MONTH
227 { 1, 1, 50, 51}, // WEEK_OF_YEAR
228 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
229 { 1, 1, 29, 31}, // DAY_OF_MONTH - 31 to workaround for cal implementation bug, should be 30
230 { 1, 1, 354, 355}, // DAY_OF_YEAR
231 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
232 { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH
233 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
234 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
235 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
236 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
237 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
238 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
239 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
240 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
241 { 1, 1, 5000000, 5000000}, // YEAR_WOY
242 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
243 { 1, 1, 5000000, 5000000}, // EXTENDED_YEAR
244 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
245 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
246 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
247 { 0, 0, 11, 11}, // ORDINAL_MONTH
248};
249
250/**
251* @draft ICU 2.4
252*/
253int32_t IslamicCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
254 return LIMITS[field][limitType];
255}
256
257//-------------------------------------------------------------------------
258// Assorted calculation utilities
259//
260
261namespace {
262
263// we could compress this down more if we need to
264static const int8_t umAlQuraYrStartEstimateFix[] = {
265 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, // 1300..
266 -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, // 1310..
267 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, // 1320..
268 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 1330..
269 0, 0, 1, 0, 0, -1, -1, 0, 0, 0, // 1340..
270 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, // 1350..
271 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, // 1360..
272 0, 1, 1, 0, 0, -1, 0, 1, 0, 1, // 1370..
273 1, 0, 0, -1, 0, 1, 0, 0, 0, -1, // 1380..
274 0, 1, 0, 1, 0, 0, 0, -1, 0, 0, // 1390..
275 0, 0, -1, -1, 0, -1, 0, 1, 0, 0, // 1400..
276 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, // 1410..
277 0, 1, 0, 0, -1, -1, 0, 0, 0, 1, // 1420..
278 0, 0, -1, -1, 0, -1, 0, 0, -1, -1, // 1430..
279 0, -1, 0, -1, 0, 0, -1, -1, 0, 0, // 1440..
280 0, 0, 0, 0, -1, 0, 1, 0, 1, 1, // 1450..
281 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, // 1460..
282 1, 0, 1, 0, 0, 0, -1, 0, 1, 0, // 1470..
283 0, -1, -1, 0, 0, 0, 1, 0, 0, 0, // 1480..
284 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // 1490..
285 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, // 1500..
286 0, -1, 0, 1, 0, 1, 1, 0, 0, 0, // 1510..
287 0, 1, 0, 0, 0, -1, 0, 0, 0, 1, // 1520..
288 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, // 1530..
289 0, -1, 0, 1, 0, 0, 0, -1, 0, 1, // 1540..
290 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, // 1550..
291 -1, 0, 0, 0, 0, 1, 0, 0, 0, -1, // 1560..
292 0, 0, 0, 0, -1, -1, 0, -1, 0, 1, // 1570..
293 0, 0, -1, -1, 0, 0, 1, 1, 0, 0, // 1580..
294 -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, // 1590..
295 1 // 1600
296};
297
298/**
299* Determine whether a year is a leap year in the Islamic civil calendar
300*/
301inline bool civilLeapYear(int32_t year) {
302 return (14 + 11 * year) % 30 < 11;
303}
304
305int32_t trueMonthStart(int32_t month, UErrorCode& status);
306
307} // namespace
308
309/**
310* Return the day # on which the given year starts. Days are counted
311* from the Hijri epoch, origin 0.
312*/
313int64_t IslamicCalendar::yearStart(int32_t year, UErrorCode& status) const {
314 return trueMonthStart(12*(year-1), status);
315}
316
317/**
318* Return the day # on which the given month starts. Days are counted
319* from the Hijri epoch, origin 0.
320*
321* @param year The hijri year
322* @param month The hijri month, 0-based (assumed to be in range 0..11)
323*/
324int64_t IslamicCalendar::monthStart(int32_t year, int32_t month, UErrorCode& status) const {
325 if (U_FAILURE(status)) {
326 return 0;
327 }
328 int32_t temp;
329 if (uprv_add32_overflowuprv_add32_overflow_77(year, -1, &temp) ||
330 uprv_mul32_overflowuprv_mul32_overflow_77(temp, 12, &temp) ||
331 uprv_add32_overflowuprv_add32_overflow_77(temp, month, &month)) {
332 status = U_ILLEGAL_ARGUMENT_ERROR;
333 return 0;
334 }
335
336 return trueMonthStart(month, status);
337}
338
339namespace {
340/**
341 * Return the "age" of the moon at the given time; this is the difference
342 * in ecliptic latitude between the moon and the sun. This method simply
343 * calls CalendarAstronomer.moonAge, converts to degrees,
344 * and adjusts the resultto be in the range [-180, 180].
345 *
346 * @param time The time at which the moon's age is desired,
347 * in millis since 1/1/1970.
348 */
349double moonAge(UDate time);
350
351/**
352* Find the day number on which a particular month of the true/lunar
353* Islamic calendar starts.
354*
355* @param month The month in question, origin 0 from the Hijri epoch
356*
357* @return The day number on which the given month starts.
358*/
359int32_t trueMonthStart(int32_t month, UErrorCode& status) {
360 if (U_FAILURE(status)) {
361 return 0;
362 }
363 ucln_i18n_registerCleanupucln_i18n_registerCleanup_77(UCLN_I18N_ISLAMIC_CALENDAR, calendar_islamic_cleanup);
364 int64_t start = CalendarCache::get(&gMonthCache, month, status);
365
366 if (U_SUCCESS(status) && start==0) {
367 // Make a guess at when the month started, using the average length
368 UDate origin = HIJRA_MILLIS
369 + uprv_flooruprv_floor_77(month * CalendarAstronomer::SYNODIC_MONTH) * kOneDay(1.0 * (86400000));
370
371 // moonAge will fail due to memory allocation error
372 double age = moonAge(origin);
373
374 if (age >= 0) {
375 // The month has already started
376 do {
377 origin -= kOneDay(1.0 * (86400000));
378 age = moonAge(origin);
379 } while (age >= 0);
380 }
381 else {
382 // Preceding month has not ended yet.
383 do {
384 origin += kOneDay(1.0 * (86400000));
385 age = moonAge(origin);
386 } while (age < 0);
387 }
388 start = ClockMath::floorDivideInt64(
389 static_cast<int64_t>(static_cast<int64_t>(origin) - HIJRA_MILLIS), static_cast<int64_t>(kOneDay(1.0 * (86400000)))) + 1;
390 CalendarCache::put(&gMonthCache, month, start, status);
391 }
392 if(U_FAILURE(status)) {
393 start = 0;
394 }
395 return start;
396}
397
398double moonAge(UDate time) {
399 // Convert to degrees and normalize...
400 double age = CalendarAstronomer(time).getMoonAge() * 180 / CalendarAstronomer::PI;
401 if (age > 180) {
402 age = age - 360;
403 }
404
405 return age;
406}
407
408} // namespace
409//----------------------------------------------------------------------
410// Calendar framework
411//----------------------------------------------------------------------
412
413/**
414* Return the length (in days) of the given month.
415*
416* @param year The hijri year
417* @param year The hijri month, 0-based
418* @draft ICU 2.4
419*/
420int32_t IslamicCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month,
421 UErrorCode& status) const {
422 month = 12*(extendedYear-1) + month;
423 int32_t len = trueMonthStart(month+1, status) - trueMonthStart(month, status) ;
424 if (U_FAILURE(status)) {
425 return 0;
426 }
427 return len;
428}
429
430namespace {
431
432int32_t yearLength(int32_t extendedYear, UErrorCode& status) {
433 int32_t month = 12*(extendedYear-1);
434 int32_t length = trueMonthStart(month + 12, status) - trueMonthStart(month, status);
435 if (U_FAILURE(status)) {
436 return 0;
437 }
438 return length;
439}
440
441} // namepsace
442/**
443* Return the number of days in the given Islamic year
444* @draft ICU 2.4
445*/
446int32_t IslamicCalendar::handleGetYearLength(int32_t extendedYear, UErrorCode& status) const {
447 return yearLength(extendedYear, status);
448}
449
450//-------------------------------------------------------------------------
451// Functions for converting from field values to milliseconds....
452//-------------------------------------------------------------------------
453
454// Return JD of start of given month/year
455// Calendar says:
456// Get the Julian day of the day BEFORE the start of this year.
457// If useMonth is true, get the day before the start of the month.
458// Hence the -1
459/**
460* @draft ICU 2.4
461*/
462int64_t IslamicCalendar::handleComputeMonthStart(int32_t eyear, int32_t month,
463 UBool /* useMonth */,
464 UErrorCode& status) const {
465 if (U_FAILURE(status)) {
466 return 0;
467 }
468 // This may be called by Calendar::handleComputeJulianDay with months out of the range
469 // 0..11. Need to handle that here since monthStart requires months in the range 0.11.
470 if (month > 11) {
471 if (uprv_add32_overflowuprv_add32_overflow_77(eyear, (month / 12), &eyear)) {
472 status = U_ILLEGAL_ARGUMENT_ERROR;
473 return 0;
474 }
475 month %= 12;
476 } else if (month < 0) {
477 month++;
478 if (uprv_add32_overflowuprv_add32_overflow_77(eyear, (month / 12) - 1, &eyear)) {
479 status = U_ILLEGAL_ARGUMENT_ERROR;
480 return 0;
481 }
482 month = (month % 12) + 11;
483 }
484 return monthStart(eyear, month, status) + getEpoc() - 1;
485}
486
487//-------------------------------------------------------------------------
488// Functions for converting from milliseconds to field values
489//-------------------------------------------------------------------------
490
491/**
492* @draft ICU 2.4
493*/
494int32_t IslamicCalendar::handleGetExtendedYear(UErrorCode& /* status */) {
495 if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
496 return internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
497 }
498 return internalGet(UCAL_YEAR, 1); // Default to year 1
499}
500
501/**
502* Override Calendar to compute several fields specific to the Islamic
503* calendar system. These are:
504*
505* <ul><li>ERA
506* <li>YEAR
507* <li>MONTH
508* <li>DAY_OF_MONTH
509* <li>DAY_OF_YEAR
510* <li>EXTENDED_YEAR</ul>
511*
512* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
513* method is called. The getGregorianXxx() methods return Gregorian
514* calendar equivalents for the given Julian day.
515* @draft ICU 2.4
516*/
517void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
518 if (U_FAILURE(status)) {
519 return;
520 }
521 int32_t days = julianDay - getEpoc();
522
523 // Guess at the number of elapsed full months since the epoch
524 int32_t month = static_cast<int32_t>(uprv_flooruprv_floor_77(static_cast<double>(days) / CalendarAstronomer::SYNODIC_MONTH));
525
526 int32_t startDate = static_cast<int32_t>(uprv_flooruprv_floor_77(month * CalendarAstronomer::SYNODIC_MONTH));
527
528 double age = moonAge(internalGetTime());
529 if ( days - startDate >= 25 && age > 0) {
530 // If we're near the end of the month, assume next month and search backwards
531 month++;
532 }
533
534 // Find out the last time that the new moon was actually visible at this longitude
535 // This returns midnight the night that the moon was visible at sunset.
536 while ((startDate = trueMonthStart(month, status)) > days) {
Although the value stored to 'startDate' is used in the enclosing expression, the value is never actually read from 'startDate'
537 if (U_FAILURE(status)) {
538 return;
539 }
540 // If it was after the date in question, back up a month and try again
541 month--;
542 }
543 if (U_FAILURE(status)) {
544 return;
545 }
546
547 int32_t year = month >= 0 ? ((month / 12) + 1) : ((month + 1 ) / 12);
548 month = ((month % 12) + 12 ) % 12;
549 int64_t dayOfMonth = (days - monthStart(year, month, status)) + 1;
550 if (U_FAILURE(status)) {
551 return;
552 }
553 if (dayOfMonth > INT32_MAX(2147483647) || dayOfMonth < INT32_MIN(-2147483647-1)) {
554 status = U_ILLEGAL_ARGUMENT_ERROR;
555 return;
556 }
557
558 // Now figure out the day of the year.
559 int64_t dayOfYear = (days - monthStart(year, 0, status)) + 1;
560 if (U_FAILURE(status)) {
561 return;
562 }
563 if (dayOfYear > INT32_MAX(2147483647) || dayOfYear < INT32_MIN(-2147483647-1)) {
564 status = U_ILLEGAL_ARGUMENT_ERROR;
565 return;
566 }
567
568 internalSet(UCAL_ERA, 0);
569 internalSet(UCAL_YEAR, year);
570 internalSet(UCAL_EXTENDED_YEAR, year);
571 internalSet(UCAL_MONTH, month);
572 internalSet(UCAL_ORDINAL_MONTH, month);
573 internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
574 internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
575}
576
577int32_t IslamicCalendar::getEpoc() const {
578 return CIVIL_EPOC;
579}
580
581static int32_t gregoYearFromIslamicStart(int32_t year) {
582 // ad hoc conversion, improve under #10752
583 // rough est for now, ok for grego 1846-2138,
584 // otherwise occasionally wrong (for 3% of years)
585 int cycle, offset, shift = 0;
586 if (year >= 1397) {
587 cycle = (year - 1397) / 67;
588 offset = (year - 1397) % 67;
589 shift = 2*cycle + ((offset >= 33)? 1: 0);
590 } else {
591 cycle = (year - 1396) / 67 - 1;
592 offset = -(year - 1396) % 67;
593 shift = 2*cycle + ((offset <= 33)? 1: 0);
594 }
595 return year + 579 - shift;
596}
597
598int32_t IslamicCalendar::getRelatedYear(UErrorCode &status) const
599{
600 int32_t year = get(UCAL_EXTENDED_YEAR, status);
601 if (U_FAILURE(status)) {
602 return 0;
603 }
604 return gregoYearFromIslamicStart(year);
605}
606
607void IslamicCalendar::setRelatedYear(int32_t year)
608{
609 // ad hoc conversion, improve under #10752
610 // rough est for now, ok for grego 1846-2138,
611 // otherwise occasionally wrong (for 3% of years)
612 int cycle, offset, shift = 0;
613 if (year >= 1977) {
614 cycle = (year - 1977) / 65;
615 offset = (year - 1977) % 65;
616 shift = 2*cycle + ((offset >= 32)? 1: 0);
617 } else {
618 cycle = (year - 1976) / 65 - 1;
619 offset = -(year - 1976) % 65;
620 shift = 2*cycle + ((offset <= 32)? 1: 0);
621 }
622 year = year - 579 + shift;
623 set(UCAL_EXTENDED_YEAR, year);
624}
625
626IMPL_SYSTEM_DEFAULT_CENTURY(IslamicCalendar, "@calendar=islamic-civil")namespace { static UDate gSystemDefaultCenturyStart = 2.2250738585072014e-308
; static int32_t gSystemDefaultCenturyStartYear = -1; static icu
::UInitOnce gSystemDefaultCenturyInit {}; static void initializeSystemDefaultCentury
() { UErrorCode status = U_ZERO_ERROR; IslamicCalendar calendar
("@calendar=islamic-civil", status); if (U_FAILURE(status)) {
return; } calendar.setTime(Calendar::getNow(), status); calendar
.add(UCAL_YEAR, -80, status); gSystemDefaultCenturyStart = calendar
.getTime(status); gSystemDefaultCenturyStartYear = calendar.get
(UCAL_YEAR, status); } } UDate IslamicCalendar::defaultCenturyStart
() const { umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury
); return gSystemDefaultCenturyStart; } int32_t IslamicCalendar
::defaultCenturyStartYear() const { umtx_initOnce(gSystemDefaultCenturyInit
, &initializeSystemDefaultCentury); return gSystemDefaultCenturyStartYear
; } UBool IslamicCalendar::haveDefaultCentury() const { return
true; }
627
628bool
629IslamicCalendar::inTemporalLeapYear(UErrorCode &status) const
630{
631 int32_t days = getActualMaximum(UCAL_DAY_OF_YEAR, status);
632 if (U_FAILURE(status)) {
633 return false;
634 }
635 return days == 355;
636}
637
638/*****************************************************************************
639 * IslamicCivilCalendar
640 *****************************************************************************/
641IslamicCivilCalendar::IslamicCivilCalendar(const Locale& aLocale, UErrorCode& success)
642 : IslamicCalendar(aLocale, success)
643{
644}
645
646IslamicCivilCalendar::~IslamicCivilCalendar()
647{
648}
649
650const char *IslamicCivilCalendar::getType() const {
651 return "islamic-civil";
652}
653
654IslamicCivilCalendar* IslamicCivilCalendar::clone() const {
655 return new IslamicCivilCalendar(*this);
656}
657
658/**
659* Return the day # on which the given year starts. Days are counted
660* from the Hijri epoch, origin 0.
661*/
662int64_t IslamicCivilCalendar::yearStart(int32_t year, UErrorCode& /* status */) const {
663 return 354LL * (year-1LL) + ClockMath::floorDivideInt64(3 + 11LL * year, 30LL);
664}
665
666/**
667* Return the day # on which the given month starts. Days are counted
668* from the Hijri epoch, origin 0.
669*
670* @param year The hijri year
671* @param month The hijri month, 0-based (assumed to be in range 0..11)
672*/
673int64_t IslamicCivilCalendar::monthStart(int32_t year, int32_t month, UErrorCode& /*status*/) const {
674 // This does not handle months out of the range 0..11
675 return static_cast<int64_t>(
676 uprv_ceiluprv_ceil_77(29.5*month) + 354LL*(year-1LL) +
677 ClockMath::floorDivideInt64(
678 11LL*static_cast<int64_t>(year) + 3LL, 30LL));
679}
680
681/**
682* Return the length (in days) of the given month.
683*
684* @param year The hijri year
685* @param year The hijri month, 0-based
686* @draft ICU 2.4
687*/
688int32_t IslamicCivilCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month,
689 UErrorCode& /* status */) const {
690 int32_t length = 29 + (month+1) % 2;
691 if (month == DHU_AL_HIJJAH && civilLeapYear(extendedYear)) {
692 length++;
693 }
694 return length;
695}
696
697/**
698* Return the number of days in the given Islamic year
699* @draft ICU 2.4
700*/
701int32_t IslamicCivilCalendar::handleGetYearLength(int32_t extendedYear, UErrorCode& status) const {
702 if (U_FAILURE(status)) return 0;
703 return 354 + (civilLeapYear(extendedYear) ? 1 : 0);
704}
705
706/**
707* Override Calendar to compute several fields specific to the Islamic
708* calendar system. These are:
709*
710* <ul><li>ERA
711* <li>YEAR
712* <li>MONTH
713* <li>DAY_OF_MONTH
714* <li>DAY_OF_YEAR
715* <li>EXTENDED_YEAR</ul>
716*
717* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
718* method is called. The getGregorianXxx() methods return Gregorian
719* calendar equivalents for the given Julian day.
720* @draft ICU 2.4
721*/
722void IslamicCivilCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
723 if (U_FAILURE(status)) {
724 return;
725 }
726 int32_t days = julianDay - getEpoc();
727
728 // Use the civil calendar approximation, which is just arithmetic
729 int64_t year =
730 ClockMath::floorDivideInt64(30LL * days + 10646LL, 10631LL);
731 int32_t month = static_cast<int32_t>(
732 uprv_ceiluprv_ceil_77((days - 29 - yearStart(year, status)) / 29.5 ));
733 if (U_FAILURE(status)) {
734 return;
735 }
736 month = month<11?month:11;
737
738 int64_t dayOfMonth = (days - monthStart(year, month, status)) + 1;
739 if (U_FAILURE(status)) {
740 return;
741 }
742 if (dayOfMonth > INT32_MAX(2147483647) || dayOfMonth < INT32_MIN(-2147483647-1)) {
743 status = U_ILLEGAL_ARGUMENT_ERROR;
744 return;
745 }
746
747 // Now figure out the day of the year.
748 int64_t dayOfYear = (days - monthStart(year, 0, status)) + 1;
749 if (U_FAILURE(status)) {
750 return;
751 }
752 if (dayOfYear > INT32_MAX(2147483647) || dayOfYear < INT32_MIN(-2147483647-1)) {
753 status = U_ILLEGAL_ARGUMENT_ERROR;
754 return;
755 }
756
757 internalSet(UCAL_ERA, 0);
758 internalSet(UCAL_YEAR, year);
759 internalSet(UCAL_EXTENDED_YEAR, year);
760 internalSet(UCAL_MONTH, month);
761 internalSet(UCAL_ORDINAL_MONTH, month);
762 internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
763 internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
764}
765/*****************************************************************************
766 * IslamicTBLACalendar
767 *****************************************************************************/
768IslamicTBLACalendar::IslamicTBLACalendar(const Locale& aLocale, UErrorCode& success)
769 : IslamicCivilCalendar(aLocale, success)
770{
771}
772
773IslamicTBLACalendar::~IslamicTBLACalendar()
774{
775}
776
777const char *IslamicTBLACalendar::getType() const {
778 return "islamic-tbla";
779}
780
781IslamicTBLACalendar* IslamicTBLACalendar::clone() const {
782 return new IslamicTBLACalendar(*this);
783}
784
785int32_t IslamicTBLACalendar::getEpoc() const {
786 return ASTRONOMICAL_EPOC;
787}
788
789/*****************************************************************************
790 * IslamicUmalquraCalendar
791 *****************************************************************************/
792IslamicUmalquraCalendar::IslamicUmalquraCalendar(const Locale& aLocale, UErrorCode& success)
793 : IslamicCivilCalendar(aLocale, success)
794{
795}
796
797IslamicUmalquraCalendar::~IslamicUmalquraCalendar()
798{
799}
800
801const char *IslamicUmalquraCalendar::getType() const {
802 return "islamic-umalqura";
803}
804
805IslamicUmalquraCalendar* IslamicUmalquraCalendar::clone() const {
806 return new IslamicUmalquraCalendar(*this);
807}
808
809/**
810* Return the day # on which the given year starts. Days are counted
811* from the Hijri epoch, origin 0.
812*/
813int64_t IslamicUmalquraCalendar::yearStart(int32_t year, UErrorCode& status) const {
814 if (year < UMALQURA_YEAR_START || year > UMALQURA_YEAR_END) {
815 return IslamicCivilCalendar::yearStart(year, status);
816 }
817 year -= UMALQURA_YEAR_START;
818 // rounded least-squares fit of the dates previously calculated from UMALQURA_MONTHLENGTH iteration
819 int64_t yrStartLinearEstimate = static_cast<int64_t>(
820 (354.36720 * static_cast<double>(year)) + 460322.05 + 0.5);
821 // need a slight correction to some
822 return yrStartLinearEstimate + umAlQuraYrStartEstimateFix[year];
823}
824
825/**
826* Return the day # on which the given month starts. Days are counted
827* from the Hijri epoch, origin 0.
828*
829* @param year The hijri year
830* @param month The hijri month, 0-based (assumed to be in range 0..11)
831*/
832int64_t IslamicUmalquraCalendar::monthStart(int32_t year, int32_t month, UErrorCode& status) const {
833 int64_t ms = yearStart(year, status);
834 if (U_FAILURE(status)) {
835 return 0;
836 }
837 for(int i=0; i< month; i++){
838 ms+= handleGetMonthLength(year, i, status);
839 if (U_FAILURE(status)) {
840 return 0;
841 }
842 }
843 return ms;
844}
845
846/**
847* Return the length (in days) of the given month.
848*
849* @param year The hijri year
850* @param year The hijri month, 0-based
851*/
852int32_t IslamicUmalquraCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month,
853 UErrorCode& status) const {
854 if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
855 return IslamicCivilCalendar::handleGetMonthLength(extendedYear, month, status);
856 }
857 int32_t length = 29;
858 int32_t mask = static_cast<int32_t>(0x01 << (11 - month)); // set mask for bit corresponding to month
859 int32_t index = extendedYear - UMALQURA_YEAR_START;
860 if ((UMALQURA_MONTHLENGTH[index] & mask) != 0) {
861 length++;
862 }
863 return length;
864}
865
866int32_t IslamicUmalquraCalendar::yearLength(int32_t extendedYear, UErrorCode& status) const {
867 if (extendedYear<UMALQURA_YEAR_START || extendedYear>UMALQURA_YEAR_END) {
868 return IslamicCivilCalendar::handleGetYearLength(extendedYear, status);
869 }
870 int length = 0;
871 for(int i=0; i<12; i++) {
872 length += handleGetMonthLength(extendedYear, i, status);
873 if (U_FAILURE(status)) {
874 return 0;
875 }
876 }
877 return length;
878}
879
880/**
881* Return the number of days in the given Islamic year
882* @draft ICU 2.4
883*/
884int32_t IslamicUmalquraCalendar::handleGetYearLength(int32_t extendedYear, UErrorCode& status) const {
885 return yearLength(extendedYear, status);
886}
887
888/**
889* Override Calendar to compute several fields specific to the Islamic
890* calendar system. These are:
891*
892* <ul><li>ERA
893* <li>YEAR
894* <li>MONTH
895* <li>DAY_OF_MONTH
896* <li>DAY_OF_YEAR
897* <li>EXTENDED_YEAR</ul>
898*
899* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
900* method is called. The getGregorianXxx() methods return Gregorian
901* calendar equivalents for the given Julian day.
902* @draft ICU 2.4
903*/
904void IslamicUmalquraCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
905 if (U_FAILURE(status)) {
906 return;
907 }
908 int64_t year;
909 int32_t month;
910 int32_t days = julianDay - getEpoc();
911
912 static int64_t kUmalquraStart = yearStart(UMALQURA_YEAR_START, status);
913 if (U_FAILURE(status)) {
914 return;
915 }
916 if (days < kUmalquraStart) {
917 IslamicCivilCalendar::handleComputeFields(julianDay, status);
918 return;
919 }
920 // Estimate a value y which is closer to but not greater than the year.
921 // It is the inverse function of the logic inside
922 // IslamicUmalquraCalendar::yearStart().
923 year = ((static_cast<double>(days) - (460322.05 + 0.5)) / 354.36720) + UMALQURA_YEAR_START - 1;
924 month = 0;
925 int32_t d = 1;
926 // need a slight correction to some
927 while (d > 0) {
928 d = days - yearStart(++year, status) + 1;
929 int32_t length = yearLength(year, status);
930 if (U_FAILURE(status)) {
931 return;
932 }
933 if (d == length) {
934 month = 11;
935 break;
936 }
937 if (d < length){
938 int32_t monthLen = handleGetMonthLength(year, month, status);
939 for (month = 0;
940 d > monthLen;
941 monthLen = handleGetMonthLength(year, ++month, status)) {
942 if (U_FAILURE(status)) {
943 return;
944 }
945 d -= monthLen;
946 }
947 break;
948 }
949 }
950
951 int32_t dayOfMonth = monthStart(year, month, status);
952 int32_t dayOfYear = monthStart(year, 0, status);
953 if (U_FAILURE(status)) {
954 return;
955 }
956 if (uprv_mul32_overflowuprv_mul32_overflow_77(dayOfMonth, -1, &dayOfMonth) ||
957 uprv_add32_overflowuprv_add32_overflow_77(dayOfMonth, days, &dayOfMonth) ||
958 uprv_add32_overflowuprv_add32_overflow_77(dayOfMonth, 1, &dayOfMonth) ||
959 // Now figure out the day of the year.
960 uprv_mul32_overflowuprv_mul32_overflow_77(dayOfYear, -1, &dayOfYear) ||
961 uprv_add32_overflowuprv_add32_overflow_77(dayOfYear, days, &dayOfYear) ||
962 uprv_add32_overflowuprv_add32_overflow_77(dayOfYear, 1, &dayOfYear)) {
963 status = U_ILLEGAL_ARGUMENT_ERROR;
964 return;
965 }
966
967 internalSet(UCAL_ERA, 0);
968 internalSet(UCAL_YEAR, year);
969 internalSet(UCAL_EXTENDED_YEAR, year);
970 internalSet(UCAL_MONTH, month);
971 internalSet(UCAL_ORDINAL_MONTH, month);
972 internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
973 internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
974}
975/*****************************************************************************
976 * IslamicRGSACalendar
977 *****************************************************************************/
978IslamicRGSACalendar::IslamicRGSACalendar(const Locale& aLocale, UErrorCode& success)
979 : IslamicCalendar(aLocale, success)
980{
981}
982
983IslamicRGSACalendar::~IslamicRGSACalendar()
984{
985}
986
987const char *IslamicRGSACalendar::getType() const {
988 return "islamic-rgsa";
989}
990
991IslamicRGSACalendar* IslamicRGSACalendar::clone() const {
992 return new IslamicRGSACalendar(*this);
993}
994
995UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCalendar)UClassID IslamicCalendar::getStaticClassID() { static char classID
= 0; return (UClassID)&classID; } UClassID IslamicCalendar
::getDynamicClassID() const { return IslamicCalendar::getStaticClassID
(); }
996UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicCivilCalendar)UClassID IslamicCivilCalendar::getStaticClassID() { static char
classID = 0; return (UClassID)&classID; } UClassID IslamicCivilCalendar
::getDynamicClassID() const { return IslamicCivilCalendar::getStaticClassID
(); }
997UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicUmalquraCalendar)UClassID IslamicUmalquraCalendar::getStaticClassID() { static
char classID = 0; return (UClassID)&classID; } UClassID IslamicUmalquraCalendar
::getDynamicClassID() const { return IslamicUmalquraCalendar::
getStaticClassID(); }
998UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicTBLACalendar)UClassID IslamicTBLACalendar::getStaticClassID() { static char
classID = 0; return (UClassID)&classID; } UClassID IslamicTBLACalendar
::getDynamicClassID() const { return IslamicTBLACalendar::getStaticClassID
(); }
999UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IslamicRGSACalendar)UClassID IslamicRGSACalendar::getStaticClassID() { static char
classID = 0; return (UClassID)&classID; } UClassID IslamicRGSACalendar
::getDynamicClassID() const { return IslamicRGSACalendar::getStaticClassID
(); }
1000
1001U_NAMESPACE_END}
1002
1003#endif
1004