Bug Summary

File:root/firefox-clang/intl/icu/source/i18n/hebrwcal.cpp
Warning:line 448, column 13
Value stored to 'wd' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name hebrwcal.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-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -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 UCONFIG_NO_NORMALIZATION -D UCONFIG_NO_COLLATION -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/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -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-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-character-conversion -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 -std=gnu++20 -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 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ /root/firefox-clang/intl/icu/source/i18n/hebrwcal.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-2016, International Business Machines Corporation
6* and others. All Rights Reserved.
7******************************************************************************
8*
9* File HEBRWCAL.CPP
10*
11* Modification History:
12*
13* Date Name Description
14* 12/03/2003 srl ported from java HebrewCalendar
15*****************************************************************************
16*/
17
18#include "hebrwcal.h"
19
20#if !UCONFIG_NO_FORMATTING0
21
22#include "cmemory.h"
23#include "cstring.h"
24#include "umutex.h"
25#include <float.h>
26#include "gregoimp.h" // ClockMath
27#include "astro.h" // CalendarCache
28#include "uhash.h"
29#include "ucln_in.h"
30
31// Hebrew Calendar implementation
32
33/**
34* The absolute date, in milliseconds since 1/1/1970 AD, Gregorian,
35* of the start of the Hebrew calendar. In order to keep this calendar's
36* time of day in sync with that of the Gregorian calendar, we use
37* midnight, rather than sunset the day before.
38*/
39//static const double EPOCH_MILLIS = -180799862400000.; // 1/1/1 HY
40
41static const int32_t LIMITS[UCAL_FIELD_COUNT][4] = {
42 // Minimum Greatest Least Maximum
43 // Minimum Maximum
44 { 0, 0, 0, 0}, // ERA
45 { -5000000, -5000000, 5000000, 5000000}, // YEAR
46 { 0, 0, 12, 12}, // MONTH
47 { 1, 1, 51, 56}, // WEEK_OF_YEAR
48 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // WEEK_OF_MONTH
49 { 1, 1, 29, 30}, // DAY_OF_MONTH
50 { 1, 1, 353, 385}, // DAY_OF_YEAR
51 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DAY_OF_WEEK
52 { -1, -1, 5, 5}, // DAY_OF_WEEK_IN_MONTH
53 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // AM_PM
54 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR
55 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // HOUR_OF_DAY
56 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MINUTE
57 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // SECOND
58 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECOND
59 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // ZONE_OFFSET
60 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DST_OFFSET
61 { -5000000, -5000000, 5000000, 5000000}, // YEAR_WOY
62 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // DOW_LOCAL
63 { -5000000, -5000000, 5000000, 5000000}, // EXTENDED_YEAR
64 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // JULIAN_DAY
65 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // MILLISECONDS_IN_DAY
66 {/*N/A*/-1,/*N/A*/-1,/*N/A*/-1,/*N/A*/-1}, // IS_LEAP_MONTH
67 { 0, 0, 11, 12}, // ORDINAL_MONTH
68};
69
70/**
71* The lengths of the Hebrew months. This is complicated, because there
72* are three different types of years, or six if you count leap years.
73* Due to the rules for postponing the start of the year to avoid having
74* certain holidays fall on the sabbath, the year can end up being three
75* different lengths, called "deficient", "normal", and "complete".
76*/
77static const int8_t MONTH_LENGTH[][3] = {
78 // Deficient Normal Complete
79 { 30, 30, 30 }, //Tishri
80 { 29, 29, 30 }, //Heshvan
81 { 29, 30, 30 }, //Kislev
82 { 29, 29, 29 }, //Tevet
83 { 30, 30, 30 }, //Shevat
84 { 30, 30, 30 }, //Adar I (leap years only)
85 { 29, 29, 29 }, //Adar
86 { 30, 30, 30 }, //Nisan
87 { 29, 29, 29 }, //Iyar
88 { 30, 30, 30 }, //Sivan
89 { 29, 29, 29 }, //Tammuz
90 { 30, 30, 30 }, //Av
91 { 29, 29, 29 }, //Elul
92};
93
94/**
95* The cumulative # of days to the end of each month in a non-leap year
96* Although this can be calculated from the MONTH_LENGTH table,
97* keeping it around separately makes some calculations a lot faster
98*/
99
100static const int16_t MONTH_START[][3] = {
101 // Deficient Normal Complete
102 { 0, 0, 0 }, // (placeholder)
103 { 30, 30, 30 }, // Tishri
104 { 59, 59, 60 }, // Heshvan
105 { 88, 89, 90 }, // Kislev
106 { 117, 118, 119 }, // Tevet
107 { 147, 148, 149 }, // Shevat
108 { 147, 148, 149 }, // (Adar I placeholder)
109 { 176, 177, 178 }, // Adar
110 { 206, 207, 208 }, // Nisan
111 { 235, 236, 237 }, // Iyar
112 { 265, 266, 267 }, // Sivan
113 { 294, 295, 296 }, // Tammuz
114 { 324, 325, 326 }, // Av
115 { 353, 354, 355 }, // Elul
116};
117
118/**
119* The cumulative # of days to the end of each month in a leap year
120*/
121static const int16_t LEAP_MONTH_START[][3] = {
122 // Deficient Normal Complete
123 { 0, 0, 0 }, // (placeholder)
124 { 30, 30, 30 }, // Tishri
125 { 59, 59, 60 }, // Heshvan
126 { 88, 89, 90 }, // Kislev
127 { 117, 118, 119 }, // Tevet
128 { 147, 148, 149 }, // Shevat
129 { 177, 178, 179 }, // Adar I
130 { 206, 207, 208 }, // Adar II
131 { 236, 237, 238 }, // Nisan
132 { 265, 266, 267 }, // Iyar
133 { 295, 296, 297 }, // Sivan
134 { 324, 325, 326 }, // Tammuz
135 { 354, 355, 356 }, // Av
136 { 383, 384, 385 }, // Elul
137};
138
139// There are 235 months in 19 years cycle.
140static const int32_t MONTHS_IN_CYCLE = 235;
141static const int32_t YEARS_IN_CYCLE = 19;
142
143static icu::CalendarCache *gCache = nullptr;
144
145U_CDECL_BEGINextern "C" {
146static UBool calendar_hebrew_cleanup() {
147 delete gCache;
148 gCache = nullptr;
149 return true;
150}
151U_CDECL_END}
152
153U_NAMESPACE_BEGINnamespace icu_78 {
154//-------------------------------------------------------------------------
155// Constructors...
156//-------------------------------------------------------------------------
157
158/**
159* Constructs a default <code>HebrewCalendar</code> using the current time
160* in the default time zone with the default locale.
161* @internal
162*/
163HebrewCalendar::HebrewCalendar(const Locale& aLocale, UErrorCode& success)
164: Calendar(TimeZone::forLocaleOrDefault(aLocale), aLocale, success)
165
166{
167}
168
169
170HebrewCalendar::~HebrewCalendar() {
171}
172
173const char *HebrewCalendar::getType() const {
174 return "hebrew";
175}
176
177HebrewCalendar* HebrewCalendar::clone() const {
178 return new HebrewCalendar(*this);
179}
180
181HebrewCalendar::HebrewCalendar(const HebrewCalendar& other) : Calendar(other) {
182}
183
184
185//-------------------------------------------------------------------------
186// Rolling and adding functions overridden from Calendar
187//
188// These methods call through to the default implementation in IBMCalendar
189// for most of the fields and only handle the unusual ones themselves.
190//-------------------------------------------------------------------------
191
192/**
193* Add a signed amount to a specified field, using this calendar's rules.
194* For example, to add three days to the current date, you can call
195* <code>add(Calendar.DATE, 3)</code>.
196* <p>
197* When adding to certain fields, the values of other fields may conflict and
198* need to be changed. For example, when adding one to the {@link #MONTH MONTH} field
199* for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
200* must be adjusted so that the result is "29 Elul 5758" rather than the invalid
201* "30 Elul 5758".
202* <p>
203* This method is able to add to
204* all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
205* and {@link #ZONE_OFFSET ZONE_OFFSET}.
206* <p>
207* <b>Note:</b> You should always use {@link #roll roll} and add rather
208* than attempting to perform arithmetic operations directly on the fields
209* of a <tt>HebrewCalendar</tt>. Since the {@link #MONTH MONTH} field behaves
210* discontinuously in non-leap years, simple arithmetic can give invalid results.
211* <p>
212* @param field the time field.
213* @param amount the amount to add to the field.
214*
215* @exception IllegalArgumentException if the field is invalid or refers
216* to a field that cannot be handled by this method.
217* @internal
218*/
219void HebrewCalendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status)
220{
221 if(U_FAILURE(status)) {
222 return;
223 }
224 switch (field) {
225 case UCAL_MONTH:
226 case UCAL_ORDINAL_MONTH:
227 {
228 // We can't just do a set(MONTH, get(MONTH) + amount). The
229 // reason is ADAR_1. Suppose amount is +2 and we land in
230 // ADAR_1 -- then we have to bump to ADAR_2 aka ADAR. But
231 // if amount is -2 and we land in ADAR_1, then we have to
232 // bump the other way -- down to SHEVAT. - Alan 11/00
233 int64_t month = get(UCAL_MONTH, status);
234 int32_t year = get(UCAL_YEAR, status);
235 UBool acrossAdar1;
236 if (amount > 0) {
237 acrossAdar1 = (month < ADAR_1); // started before ADAR_1?
238 month += amount;
239 // We know there are total 235 months in every 19 years. To speed
240 // up the iteration, we first fast forward in the multiple of 235
241 // months for 19 years before the iteration which check the leap year.
242 if (month >= MONTHS_IN_CYCLE) {
243 if (uprv_add32_overflow(year, (month / MONTHS_IN_CYCLE) * YEARS_IN_CYCLE, &year)) {
244 status = U_ILLEGAL_ARGUMENT_ERROR;
245 return;
246 }
247 month %= MONTHS_IN_CYCLE;
248 }
249
250 for (;;) {
251 if (acrossAdar1 && month>=ADAR_1 && !isLeapYear(year)) {
252 ++month;
253 }
254 if (month <= ELUL) {
255 break;
256 }
257 month -= ELUL+1;
258 ++year;
259 acrossAdar1 = true;
260 }
261 } else {
262 acrossAdar1 = (month > ADAR_1); // started after ADAR_1?
263 month += amount;
264 // We know there are total 235 months in every 19 years. To speed
265 // up the iteration, we first fast forward in the multiple of 235
266 // months for 19 years before the iteration which check the leap year.
267 if (month <= -MONTHS_IN_CYCLE) {
268 if (uprv_add32_overflow(year, (month / MONTHS_IN_CYCLE) * YEARS_IN_CYCLE, &year)) {
269 status = U_ILLEGAL_ARGUMENT_ERROR;
270 return;
271 }
272 month %= MONTHS_IN_CYCLE;
273 }
274 for (;;) {
275 if (acrossAdar1 && month<=ADAR_1 && !isLeapYear(year)) {
276 --month;
277 }
278 if (month >= 0) {
279 break;
280 }
281 month += ELUL+1;
282 --year;
283 acrossAdar1 = true;
284 }
285 }
286 set(UCAL_MONTH, month);
287 set(UCAL_YEAR, year);
288 pinField(UCAL_DAY_OF_MONTH, status);
289 break;
290 }
291
292 default:
293 Calendar::add(field, amount, status);
294 break;
295 }
296}
297
298/**
299* @deprecated ICU 2.6 use UCalendarDateFields instead of EDateFields
300*/
301void HebrewCalendar::add(EDateFields field, int32_t amount, UErrorCode& status)
302{
303 add(static_cast<UCalendarDateFields>(field), amount, status);
304}
305
306namespace {
307
308int32_t monthsInYear(int32_t year);
309
310} // namespace
311
312/**
313* Rolls (up/down) a specified amount time on the given field. For
314* example, to roll the current date up by three days, you can call
315* <code>roll(Calendar.DATE, 3)</code>. If the
316* field is rolled past its maximum allowable value, it will "wrap" back
317* to its minimum and continue rolling.
318* For example, calling <code>roll(Calendar.DATE, 10)</code>
319* on a Hebrew calendar set to "25 Av 5758" will result in the date "5 Av 5758".
320* <p>
321* When rolling certain fields, the values of other fields may conflict and
322* need to be changed. For example, when rolling the {@link #MONTH MONTH} field
323* upward by one for the date "30 Av 5758", the {@link #DAY_OF_MONTH DAY_OF_MONTH} field
324* must be adjusted so that the result is "29 Elul 5758" rather than the invalid
325* "30 Elul".
326* <p>
327* This method is able to roll
328* all fields except for {@link #ERA ERA}, {@link #DST_OFFSET DST_OFFSET},
329* and {@link #ZONE_OFFSET ZONE_OFFSET}. Subclasses may, of course, add support for
330* additional fields in their overrides of <code>roll</code>.
331* <p>
332* <b>Note:</b> You should always use roll and {@link #add add} rather
333* than attempting to perform arithmetic operations directly on the fields
334* of a <tt>HebrewCalendar</tt>. Since the {@link #MONTH MONTH} field behaves
335* discontinuously in non-leap years, simple arithmetic can give invalid results.
336* <p>
337* @param field the time field.
338* @param amount the amount by which the field should be rolled.
339*
340* @exception IllegalArgumentException if the field is invalid or refers
341* to a field that cannot be handled by this method.
342* @internal
343*/
344void HebrewCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status)
345{
346 if(U_FAILURE(status)) {
347 return;
348 }
349 switch (field) {
350 case UCAL_MONTH:
351 case UCAL_ORDINAL_MONTH:
352 {
353 int32_t month = get(UCAL_MONTH, status);
354 int32_t year = get(UCAL_YEAR, status);
355
356 UBool leapYear = isLeapYear(year);
357 int32_t yearLength = monthsInYear(year);
358 int32_t newMonth = month + (amount % yearLength);
359 //
360 // If it's not a leap year and we're rolling past the missing month
361 // of ADAR_1, we need to roll an extra month to make up for it.
362 //
363 if (!leapYear) {
364 if (amount > 0 && month < ADAR_1 && newMonth >= ADAR_1) {
365 newMonth++;
366 } else if (amount < 0 && month > ADAR_1 && newMonth <= ADAR_1) {
367 newMonth--;
368 }
369 }
370 set(UCAL_MONTH, (newMonth + 13) % 13);
371 pinField(UCAL_DAY_OF_MONTH, status);
372 return;
373 }
374 default:
375 Calendar::roll(field, amount, status);
376 }
377}
378
379void HebrewCalendar::roll(EDateFields field, int32_t amount, UErrorCode& status) {
380 roll(static_cast<UCalendarDateFields>(field), amount, status);
381}
382
383//-------------------------------------------------------------------------
384// Support methods
385//-------------------------------------------------------------------------
386
387// Hebrew date calculations are performed in terms of days, hours, and
388// "parts" (or halakim), which are 1/1080 of an hour, or 3 1/3 seconds.
389static const int32_t HOUR_PARTS = 1080;
390static const int32_t DAY_PARTS = 24*HOUR_PARTS;
391
392// An approximate value for the length of a lunar month.
393// It is used to calculate the approximate year and month of a given
394// absolute date.
395static const int32_t MONTH_DAYS = 29;
396static const int32_t MONTH_FRACT = 12*HOUR_PARTS + 793;
397static const int32_t MONTH_PARTS = MONTH_DAYS*DAY_PARTS + MONTH_FRACT;
398
399// The time of the new moon (in parts) on 1 Tishri, year 1 (the epoch)
400// counting from noon on the day before. BAHARAD is an abbreviation of
401// Bet (Monday), Hey (5 hours from sunset), Resh-Daled (204).
402static const int32_t BAHARAD = 11*HOUR_PARTS + 204;
403
404namespace {
405
406/**
407* Finds the day # of the first day in the given Hebrew year.
408* To do this, we want to calculate the time of the Tishri 1 new moon
409* in that year.
410* <p>
411* The algorithm here is similar to ones described in a number of
412* references, including:
413* <ul>
414* <li>"Calendrical Calculations", by Nachum Dershowitz & Edward Reingold,
415* Cambridge University Press, 1997, pages 85-91.
416*
417* <li>Hebrew Calendar Science and Myths,
418* <a href="http://www.geocities.com/Athens/1584/">
419* http://www.geocities.com/Athens/1584/</a>
420*
421* <li>The Calendar FAQ,
422* <a href="http://www.faqs.org/faqs/calendars/faq/">
423* http://www.faqs.org/faqs/calendars/faq/</a>
424* </ul>
425*/
426int32_t startOfYear(int32_t year, UErrorCode &status)
427{
428 ucln_i18n_registerCleanup(UCLN_I18N_HEBREW_CALENDAR, calendar_hebrew_cleanup);
429 int64_t day = CalendarCache::get(&gCache, year, status);
430 if(U_FAILURE(status)) {
431 return 0;
432 }
433
434 if (day == 0) {
435 // # of months before year
436 int64_t months = ClockMath::floorDivideInt64(
437 (235LL * static_cast<int64_t>(year) - 234LL), 19LL);
438
439 int64_t frac = months * MONTH_FRACT + BAHARAD; // Fractional part of day #
440 day = months * 29LL + frac / DAY_PARTS; // Whole # part of calculation
441 frac = frac % DAY_PARTS; // Time of day
442
443 int32_t wd = (day % 7); // Day of week (0 == Monday)
444
445 if (wd == 2 || wd == 4 || wd == 6) {
446 // If the 1st is on Sun, Wed, or Fri, postpone to the next day
447 day += 1;
448 wd = (day % 7);
Value stored to 'wd' is never read
449 } else if (wd == 1 && frac > 15*HOUR_PARTS+204 && !HebrewCalendar::isLeapYear(year) ) {
450 // If the new moon falls after 3:11:20am (15h204p from the previous noon)
451 // on a Tuesday and it is not a leap year, postpone by 2 days.
452 // This prevents 356-day years.
453 day += 2;
454 }
455 else if (wd == 0 && frac > 21*HOUR_PARTS+589 && HebrewCalendar::isLeapYear(year-1) ) {
456 // If the new moon falls after 9:32:43 1/3am (21h589p from yesterday noon)
457 // on a Monday and *last* year was a leap year, postpone by 1 day.
458 // Prevents 382-day years.
459 day += 1;
460 }
461 if (day > INT32_MAX(2147483647) || day < INT32_MIN(-2147483647-1)) {
462 status = U_ILLEGAL_ARGUMENT_ERROR;
463 return 0;
464 }
465 CalendarCache::put(&gCache, year, static_cast<int32_t>(day), status);
466 }
467 // Out of range value is alread rejected before putting into cache.
468 U_ASSERT(INT32_MIN <= day && day <= INT32_MAX)(static_cast <bool> ((-2147483647-1) <= day &&
day <= (2147483647)) ? void (0) : __assert_fail ("(-2147483647-1) <= day && day <= (2147483647)"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
469 return day;
470}
471
472int32_t daysInYear(int32_t eyear, UErrorCode& status) {
473 if (U_FAILURE(status)) {
474 return 0;
475 }
476 return startOfYear(eyear+1, status) - startOfYear(eyear, status);
477}
478
479/**
480* Returns the type of a given year.
481* 0 "Deficient" year with 353 or 383 days
482* 1 "Normal" year with 354 or 384 days
483* 2 "Complete" year with 355 or 385 days
484*/
485int32_t yearType(int32_t year, UErrorCode& status)
486{
487 if (U_FAILURE(status)) {
488 return 0;
489 }
490 int32_t yearLength = daysInYear(year, status);
491 if (U_FAILURE(status)) {
492 return 0;
493 }
494
495 if (yearLength > 380) {
496 yearLength -= 30; // Subtract length of leap month.
497 }
498
499 int type = 0;
500
501 switch (yearLength) {
502 case 353:
503 type = 0; break;
504 case 354:
505 type = 1; break;
506 case 355:
507 type = 2; break;
508 default:
509 //throw new RuntimeException("Illegal year length " + yearLength + " in year " + year);
510 type = 1;
511 }
512 return type;
513}
514
515} // namespace
516 //
517/**
518* Determine whether a given Hebrew year is a leap year
519*
520* The rule here is that if (year % 19) == 0, 3, 6, 8, 11, 14, or 17.
521* The formula below performs the same test, believe it or not.
522*/
523UBool HebrewCalendar::isLeapYear(int32_t year) {
524 //return (year * 12 + 17) % 19 >= 12;
525 int64_t x = (year*12LL + 17) % YEARS_IN_CYCLE;
526 return x >= ((x < 0) ? -7 : 12);
527}
528
529namespace{
530
531int32_t monthsInYear(int32_t year) {
532 return HebrewCalendar::isLeapYear(year) ? 13 : 12;
533}
534
535} // namespace
536
537//-------------------------------------------------------------------------
538// Calendar framework
539//-------------------------------------------------------------------------
540
541/**
542* @internal
543*/
544int32_t HebrewCalendar::handleGetLimit(UCalendarDateFields field, ELimitType limitType) const {
545 return LIMITS[field][limitType];
546}
547
548/**
549* Returns the length of the given month in the given year
550* @internal
551*/
552int32_t HebrewCalendar::handleGetMonthLength(int32_t extendedYear, int32_t month, UErrorCode& status) const {
553 if(U_FAILURE(status)) {
554 return 0;
555 }
556 // Resolve out-of-range months. This is necessary in order to
557 // obtain the correct year. We correct to
558 // a 12- or 13-month year (add/subtract 12 or 13, depending
559 // on the year) but since we _always_ number from 0..12, and
560 // the leap year determines whether or not month 5 (Adar 1)
561 // is present, we allow 0..12 in any given year.
562 while (month < 0) {
563 month += monthsInYear(--extendedYear);
564 }
565 // Careful: allow 0..12 in all years
566 while (month > 12) {
567 month -= monthsInYear(extendedYear++);
568 }
569
570 switch (month) {
571 case HESHVAN:
572 case KISLEV:
573 {
574 // These two month lengths can vary
575 int32_t type = yearType(extendedYear, status);
576 if(U_FAILURE(status)) {
577 return 0;
578 }
579 return MONTH_LENGTH[month][type];
580 }
581
582 default:
583 // The rest are a fixed length
584 return MONTH_LENGTH[month][0];
585 }
586}
587
588/**
589* Returns the number of days in the given Hebrew year
590* @internal
591*/
592int32_t HebrewCalendar::handleGetYearLength(int32_t eyear, UErrorCode& status) const {
593 return daysInYear(eyear, status);
594}
595
596void HebrewCalendar::validateField(UCalendarDateFields field, UErrorCode &status) {
597 if ((field == UCAL_MONTH || field == UCAL_ORDINAL_MONTH)
598 && !isLeapYear(handleGetExtendedYear(status)) && internalGetMonth(status) == ADAR_1) {
599 if (U_FAILURE(status)) {
600 return;
601 }
602 status = U_ILLEGAL_ARGUMENT_ERROR;
603 return;
604 }
605 Calendar::validateField(field, status);
606}
607//-------------------------------------------------------------------------
608// Functions for converting from milliseconds to field values
609//-------------------------------------------------------------------------
610
611/**
612* Subclasses may override this method to compute several fields
613* specific to each calendar system. These are:
614*
615* <ul><li>ERA
616* <li>YEAR
617* <li>MONTH
618* <li>DAY_OF_MONTH
619* <li>DAY_OF_YEAR
620* <li>EXTENDED_YEAR</ul>
621*
622* Subclasses can refer to the DAY_OF_WEEK and DOW_LOCAL fields,
623* which will be set when this method is called. Subclasses can
624* also call the getGregorianXxx() methods to obtain Gregorian
625* calendar equivalents for the given Julian day.
626*
627* <p>In addition, subclasses should compute any subclass-specific
628* fields, that is, fields from BASE_FIELD_COUNT to
629* getFieldCount() - 1.
630* @internal
631*/
632void HebrewCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
633 if (U_FAILURE(status)) {
634 return;
635 }
636 int32_t d = julianDay - 347997;
637 double m = ClockMath::floorDivide((d * static_cast<double>(DAY_PARTS)), static_cast<double>(MONTH_PARTS)); // Months (approx)
638 int32_t year = static_cast<int32_t>(ClockMath::floorDivide((19. * m + 234.), 235.) + 1.); // Years (approx)
639 int32_t ys = startOfYear(year, status); // 1st day of year
640 if (U_FAILURE(status)) {
641 return;
642 }
643 int32_t dayOfYear = (d - ys);
644
645 // Because of the postponement rules, it's possible to guess wrong. Fix it.
646 while (dayOfYear < 1) {
647 year--;
648 ys = startOfYear(year, status);
649 if (U_FAILURE(status)) {
650 return;
651 }
652 dayOfYear = (d - ys);
653 }
654
655 // Now figure out which month we're in, and the date within that month
656 int32_t type = yearType(year, status);
657 if (U_FAILURE(status)) {
658 return;
659 }
660 UBool isLeap = isLeapYear(year);
661
662 int32_t month = 0;
663 int32_t momax = UPRV_LENGTHOF(MONTH_START)(int32_t)(sizeof(MONTH_START)/sizeof((MONTH_START)[0]));
664 while (month < momax &&
665 dayOfYear > ( isLeap ? LEAP_MONTH_START[month][type] : MONTH_START[month][type] ) ) {
666 month++;
667 }
668 if (month >= momax || month<=0) {
669 // TODO: I found dayOfYear could be out of range when
670 // a large value is set to julianDay. I patched startOfYear
671 // to reduce the chace, but it could be still reproduced either
672 // by startOfYear or other places. For now, we check
673 // the month is in valid range to avoid out of array index
674 // access problem here. However, we need to carefully review
675 // the calendar implementation to check the extreme limit of
676 // each calendar field and the code works well for any values
677 // in the valid value range. -yoshito
678 status = U_ILLEGAL_ARGUMENT_ERROR;
679 return;
680 }
681 month--;
682 int dayOfMonth = dayOfYear - (isLeap ? LEAP_MONTH_START[month][type] : MONTH_START[month][type]);
683
684 internalSet(UCAL_ERA, 0);
685 // Check out of bound year
686 int32_t min_year = handleGetLimit(UCAL_EXTENDED_YEAR, UCAL_LIMIT_MINIMUM);
687 if (year < min_year) {
688 if (!isLenient()) {
689 status = U_ILLEGAL_ARGUMENT_ERROR;
690 return;
691 }
692 year = min_year;
693 }
694 int32_t max_year = handleGetLimit(UCAL_EXTENDED_YEAR, UCAL_LIMIT_MAXIMUM);
695 if (max_year < year) {
696 if (!isLenient()) {
697 status = U_ILLEGAL_ARGUMENT_ERROR;
698 return;
699 }
700 year = max_year;
701 }
702 internalSet(UCAL_YEAR, year);
703 internalSet(UCAL_EXTENDED_YEAR, year);
704 int32_t ordinal_month = month;
705 if (!isLeap && ordinal_month > ADAR_1) {
706 ordinal_month--;
707 }
708 internalSet(UCAL_ORDINAL_MONTH, ordinal_month);
709 internalSet(UCAL_MONTH, month);
710 internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
711 internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
712}
713
714//-------------------------------------------------------------------------
715// Functions for converting from field values to milliseconds
716//-------------------------------------------------------------------------
717
718/**
719* @internal
720*/
721int32_t HebrewCalendar::handleGetExtendedYear(UErrorCode& status ) {
722 if (U_FAILURE(status)) {
723 return 0;
724 }
725 if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
726 return internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
727 }
728 return internalGet(UCAL_YEAR, 1); // Default to year 1
729}
730
731/**
732* Return JD of start of given month/year.
733* @internal
734*/
735int64_t HebrewCalendar::handleComputeMonthStart(
736 int32_t eyear, int32_t month, UBool /*useMonth*/, UErrorCode& status) const {
737 if (U_FAILURE(status)) {
738 return 0;
739 }
740 // Resolve out-of-range months. This is necessary in order to
741 // obtain the correct year. We correct to
742 // a 12- or 13-month year (add/subtract 12 or 13, depending
743 // on the year) but since we _always_ number from 0..12, and
744 // the leap year determines whether or not month 5 (Adar 1)
745 // is present, we allow 0..12 in any given year.
746
747 // The month could be in large value, we first roll 235 months to 19 years
748 // before the while loop.
749 if (month <= -MONTHS_IN_CYCLE || month >= MONTHS_IN_CYCLE) {
750 if (uprv_add32_overflow(eyear, (month / MONTHS_IN_CYCLE) * YEARS_IN_CYCLE, &eyear)) {
751 status = U_ILLEGAL_ARGUMENT_ERROR;
752 return 0;
753 }
754 month %= MONTHS_IN_CYCLE;
755 }
756 while (month < 0) {
757 if (uprv_add32_overflow(eyear, -1, &eyear) ||
758 uprv_add32_overflow(month, monthsInYear(eyear), &month)) {
759 status = U_ILLEGAL_ARGUMENT_ERROR;
760 return 0;
761 }
762 }
763 // Careful: allow 0..12 in all years
764 while (month > 12) {
765 if (uprv_add32_overflow(month, -monthsInYear(eyear), &month) ||
766 uprv_add32_overflow(eyear, 1, &eyear)) {
767 status = U_ILLEGAL_ARGUMENT_ERROR;
768 return 0;
769 }
770 }
771
772 int64_t day = startOfYear(eyear, status);
773
774 if(U_FAILURE(status)) {
775 return 0;
776 }
777
778 if (month != 0) {
779 int32_t type = yearType(eyear, status);
780 if (U_FAILURE(status)) {
781 return 0;
782 }
783 if (isLeapYear(eyear)) {
784 day += LEAP_MONTH_START[month][type];
785 } else {
786 day += MONTH_START[month][type];
787 }
788 }
789
790 return day + 347997LL;
791}
792
793IMPL_SYSTEM_DEFAULT_CENTURY(HebrewCalendar, "@calendar=hebrew")namespace { static UDate gSystemDefaultCenturyStart = 2.2250738585072014e-308
; static int32_t gSystemDefaultCenturyStartYear = -1; static icu
::UInitOnce gSystemDefaultCenturyInit {}; static void initializeSystemDefaultCentury
() { UErrorCode status = U_ZERO_ERROR; HebrewCalendar calendar
("@calendar=hebrew", 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 HebrewCalendar::defaultCenturyStart
() const { umtx_initOnce(gSystemDefaultCenturyInit, &initializeSystemDefaultCentury
); return gSystemDefaultCenturyStart; } int32_t HebrewCalendar
::defaultCenturyStartYear() const { umtx_initOnce(gSystemDefaultCenturyInit
, &initializeSystemDefaultCentury); return gSystemDefaultCenturyStartYear
; } UBool HebrewCalendar::haveDefaultCentury() const { return
true; }
794
795bool HebrewCalendar::inTemporalLeapYear(UErrorCode& status) const {
796 if (U_FAILURE(status)) {
797 return false;
798 }
799 int32_t eyear = get(UCAL_EXTENDED_YEAR, status);
800 if (U_FAILURE(status)) {
801 return false;
802 }
803 return isLeapYear(eyear);
804}
805
806static const char * const gTemporalMonthCodesForHebrew[] = {
807 "M01", "M02", "M03", "M04", "M05", "M05L", "M06",
808 "M07", "M08", "M09", "M10", "M11", "M12", nullptr
809};
810
811const char* HebrewCalendar::getTemporalMonthCode(UErrorCode& status) const {
812 int32_t month = get(UCAL_MONTH, status);
813 if (U_FAILURE(status)) {
814 return nullptr;
815 }
816 return gTemporalMonthCodesForHebrew[month];
817}
818
819void HebrewCalendar::setTemporalMonthCode(const char* code, UErrorCode& status )
820{
821 if (U_FAILURE(status)) {
822 return;
823 }
824 int32_t len = static_cast<int32_t>(uprv_strlen(code):: strlen(code));
825 if (len == 3 || len == 4) {
826 for (int m = 0; gTemporalMonthCodesForHebrew[m] != nullptr; m++) {
827 if (uprv_strcmp(code, gTemporalMonthCodesForHebrew[m]):: strcmp(code, gTemporalMonthCodesForHebrew[m]) == 0) {
828 set(UCAL_MONTH, m);
829 return;
830 }
831 }
832 }
833 status = U_ILLEGAL_ARGUMENT_ERROR;
834}
835
836int32_t HebrewCalendar::internalGetMonth(UErrorCode& status) const {
837 if (U_FAILURE(status)) {
838 return 0;
839 }
840 if (resolveFields(kMonthPrecedence) == UCAL_ORDINAL_MONTH) {
841 int32_t ordinalMonth = internalGet(UCAL_ORDINAL_MONTH);
842 HebrewCalendar* nonConstThis = const_cast<HebrewCalendar*>(this); // cast away const
843
844 int32_t year = nonConstThis->handleGetExtendedYear(status);
845 if (U_FAILURE(status)) {
846 return 0;
847 }
848 if (isLeapYear(year) || ordinalMonth <= ADAR_1) {
849 return ordinalMonth;
850 }
851 if (!uprv_add32_overflow(ordinalMonth, 1, &ordinalMonth)) {
852 return ordinalMonth;
853 }
854 }
855 return Calendar::internalGetMonth(status);
856}
857
858int32_t HebrewCalendar::getRelatedYearDifference() const {
859 constexpr int32_t kHebrewCalendarRelatedYearDifference = -3760;
860 return kHebrewCalendarRelatedYearDifference;
861}
862
863UOBJECT_DEFINE_RTTI_IMPLEMENTATION(HebrewCalendar)UClassID HebrewCalendar::getStaticClassID() { static char classID
= 0; return (UClassID)&classID; } UClassID HebrewCalendar
::getDynamicClassID() const { return HebrewCalendar::getStaticClassID
(); }
864
865U_NAMESPACE_END}
866
867#endif // UCONFIG_NO_FORMATTING
868