--- /dev/null
+Index: source/i18n/gregoimp.cpp
+===================================================================
+--- source/i18n/gregoimp.cpp (revision 40653)
++++ source/i18n/gregoimp.cpp (revision 40654)
+@@ -24,4 +24,9 @@
+
+ int32_t ClockMath::floorDivide(int32_t numerator, int32_t denominator) {
++ return (numerator >= 0) ?
++ numerator / denominator : ((numerator + 1) / denominator) - 1;
++}
++
++int64_t ClockMath::floorDivide(int64_t numerator, int64_t denominator) {
+ return (numerator >= 0) ?
+ numerator / denominator : ((numerator + 1) / denominator) - 1;
+Index: source/i18n/gregoimp.h
+===================================================================
+--- source/i18n/gregoimp.h (revision 40653)
++++ source/i18n/gregoimp.h (revision 40654)
+@@ -40,4 +40,15 @@
+ */
+ static int32_t floorDivide(int32_t numerator, int32_t denominator);
++
++ /**
++ * Divide two integers, returning the floor of the quotient.
++ * Unlike the built-in division, this is mathematically
++ * well-behaved. E.g., <code>-1/4</code> => 0 but
++ * <code>floorDivide(-1,4)</code> => -1.
++ * @param numerator the numerator
++ * @param denominator a divisor which must be != 0
++ * @return the floor of the quotient
++ */
++ static int64_t floorDivide(int64_t numerator, int64_t denominator);
+
+ /**
+Index: source/i18n/persncal.cpp
+===================================================================
+--- source/i18n/persncal.cpp (revision 40653)
++++ source/i18n/persncal.cpp (revision 40654)
+@@ -214,5 +214,5 @@
+
+ int32_t daysSinceEpoch = julianDay - PERSIAN_EPOCH;
+- year = 1 + ClockMath::floorDivide(33 * daysSinceEpoch + 3, 12053);
++ year = 1 + (int32_t)ClockMath::floorDivide(33 * (int64_t)daysSinceEpoch + 3, (int64_t)12053);
+
+ int32_t farvardin1 = 365 * (year - 1) + ClockMath::floorDivide(8 * year + 21, 33);
+Index: source/test/intltest/calregts.cpp
+===================================================================
+--- source/test/intltest/calregts.cpp (revision 40653)
++++ source/test/intltest/calregts.cpp (revision 40654)
+@@ -13,4 +13,5 @@
+ #include "calregts.h"
+
++#include "unicode/calendar.h"
+ #include "unicode/gregocal.h"
+ #include "unicode/simpletz.h"
+@@ -91,4 +92,5 @@
+ CASE(49,Test9019);
+ CASE(50,TestT9452);
++ CASE(51,TestPersianCalOverflow);
+ default: name = ""; break;
+ }
+@@ -2946,4 +2948,34 @@
+ }
+ }
++
++/**
++ * @bug ticket 13454
++ */
++void CalendarRegressionTest::TestPersianCalOverflow(void) {
++ const char* localeID = "bs_Cyrl@calendar=persian";
++ UErrorCode status = U_ZERO_ERROR;
++ Calendar* cal = Calendar::createInstance(Locale(localeID), status);
++ if(U_FAILURE(status)) {
++ dataerrln("FAIL: Calendar::createInstance for localeID %s: %s", localeID, u_errorName(status));
++ } else {
++ int32_t maxMonth = cal->getMaximum(UCAL_MONTH);
++ int32_t maxDayOfMonth = cal->getMaximum(UCAL_DATE);
++ int32_t jd, month, dayOfMonth;
++ for (jd = 67023580; jd <= 67023584; jd++) { // year 178171, int32_t overflow if jd >= 67023582
++ status = U_ZERO_ERROR;
++ cal->clear();
++ cal->set(UCAL_JULIAN_DAY, jd);
++ month = cal->get(UCAL_MONTH, status);
++ dayOfMonth = cal->get(UCAL_DATE, status);
++ if ( U_FAILURE(status) ) {
++ errln("FAIL: Calendar->get MONTH/DATE for localeID %s, julianDay %d, status %s\n", localeID, jd, u_errorName(status));
++ } else if (month > maxMonth || dayOfMonth > maxDayOfMonth) {
++ errln("FAIL: localeID %s, julianDay %d; maxMonth %d, got month %d; maxDayOfMonth %d, got dayOfMonth %d\n",
++ localeID, jd, maxMonth, month, maxDayOfMonth, dayOfMonth);
++ }
++ }
++ delete cal;
++ }
++}
+
+ #endif /* #if !UCONFIG_NO_FORMATTING */
+Index: source/test/intltest/calregts.h
+===================================================================
+--- source/test/intltest/calregts.h (revision 40653)
++++ source/test/intltest/calregts.h (revision 40654)
+@@ -78,4 +78,5 @@
+ void Test9019(void);
+ void TestT9452(void);
++ void TestPersianCalOverflow(void);
+
+ void printdate(GregorianCalendar *cal, const char *string);