mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-10 07:39:16 +00:00
ICU-2966 clean up and consolidate duplicated code
X-SVN-Rev: 13007
This commit is contained in:
parent
5de7294cfb
commit
61b5fddec2
7 changed files with 269 additions and 341 deletions
|
@ -44,6 +44,7 @@
|
|||
|
||||
#include "unicode/gregocal.h"
|
||||
#include "unicode/smpdtfmt.h" /* for the public field (!) SimpleDateFormat::fgSystemDefaultCentury */
|
||||
#include "gregoimp.h"
|
||||
#include "mutex.h"
|
||||
#include "uassert.h"
|
||||
|
||||
|
@ -317,7 +318,7 @@ GregorianCalendar::setGregorianChange(UDate date, UErrorCode& status)
|
|||
// normalized cutover is in pure date milliseconds; it contains no time
|
||||
// of day or timezone component, and it used to compare against other
|
||||
// pure date values.
|
||||
UDate cutoverDay = floorDivide(fGregorianCutover, kOneDay);
|
||||
UDate cutoverDay = Math::floorDivide(fGregorianCutover, kOneDay);
|
||||
fNormalizedGregorianCutover = cutoverDay * kOneDay;
|
||||
|
||||
// Handle the rare case of numeric overflow. If the user specifies a
|
||||
|
@ -395,10 +396,10 @@ GregorianCalendar::timeToFields(UDate theTime, UBool quick, UErrorCode& status)
|
|||
// For example, the 4-year cycle has 4 years + 1 leap day; giving
|
||||
// 1461 == 365*4 + 1 days.
|
||||
int32_t rem;
|
||||
int32_t n400 = floorDivide(gregorianEpochDay, 146097, rem); // 400-year cycle length
|
||||
int32_t n100 = floorDivide(rem, 36524, rem); // 100-year cycle length
|
||||
int32_t n4 = floorDivide(rem, 1461, rem); // 4-year cycle length
|
||||
int32_t n1 = floorDivide(rem, 365, rem);
|
||||
int32_t n400 = Math::floorDivide(gregorianEpochDay, 146097, rem); // 400-year cycle length
|
||||
int32_t n100 = Math::floorDivide(rem, 36524, rem); // 100-year cycle length
|
||||
int32_t n4 = Math::floorDivide(rem, 1461, rem); // 4-year cycle length
|
||||
int32_t n1 = Math::floorDivide(rem, 365, rem);
|
||||
rawYear = 400*n400 + 100*n100 + 4*n4 + n1;
|
||||
dayOfYear = rem; // zero-based day of year
|
||||
if (n100 == 4 || n1 == 4)
|
||||
|
@ -416,10 +417,10 @@ GregorianCalendar::timeToFields(UDate theTime, UBool quick, UErrorCode& status)
|
|||
// The Julian epoch day (not the same as Julian Day)
|
||||
// is zero on Saturday December 30, 0 (Gregorian).
|
||||
double julianEpochDay = millisToJulianDay(theTime) - (kJan1_1JulianDay - 2);
|
||||
rawYear = (int32_t) floorDivide(4*julianEpochDay + 1464, 1461.0);
|
||||
rawYear = (int32_t) Math::floorDivide(4*julianEpochDay + 1464, 1461.0);
|
||||
|
||||
// Compute the Julian calendar day number for January 1, rawYear
|
||||
double january1 = 365.0 * (rawYear - 1) + floorDivide((double)(rawYear - 1), 4.0);
|
||||
double january1 = 365.0 * (rawYear - 1) + Math::floorDivide((double)(rawYear - 1), 4.0);
|
||||
dayOfYear = (int32_t)(julianEpochDay - january1); // 0-based
|
||||
|
||||
// Julian leap years occurred historically every 4 years starting
|
||||
|
@ -725,9 +726,7 @@ GregorianCalendar::getEpochDay(UErrorCode& status)
|
|||
// dealing with UDate(Long.MIN_VALUE) and UDate(Long.MAX_VALUE).
|
||||
double wallSec = internalGetTime()/1000 + (internalGet(UCAL_ZONE_OFFSET) + internalGet(UCAL_DST_OFFSET))/1000;
|
||||
|
||||
// {sfb} force conversion to double
|
||||
return uprv_trunc(wallSec / (kOneDay/1000.0));
|
||||
//return floorDivide(wallSec, kOneDay/1000.0);
|
||||
return Math::floorDivide(wallSec, kOneDay/1000.0);
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
@ -879,12 +878,12 @@ double GregorianCalendar::computeJulianDayOfYear(UBool isGregorian,
|
|||
int32_t year, UBool& isLeap) {
|
||||
isLeap = year%4 == 0;
|
||||
int32_t y = year - 1;
|
||||
double julianDay = 365.0*y + floorDivide(y, 4) + (kJan1_1JulianDay - 3);
|
||||
double julianDay = 365.0*y + Math::floorDivide(y, 4) + (kJan1_1JulianDay - 3);
|
||||
|
||||
if (isGregorian) {
|
||||
isLeap = isLeap && ((year%100 != 0) || (year%400 == 0));
|
||||
// Add 2 because Gregorian calendar starts 2 days after Julian calendar
|
||||
julianDay += floorDivide(y, 400) - floorDivide(y, 100) + 2;
|
||||
julianDay += Math::floorDivide(y, 400) - Math::floorDivide(y, 100) + 2;
|
||||
}
|
||||
|
||||
return julianDay;
|
||||
|
@ -1094,7 +1093,7 @@ GregorianCalendar::computeJulianDay(UBool isGregorian, int32_t year)
|
|||
// If the month is out of range, adjust it into range
|
||||
if (month < 0 || month > 11) {
|
||||
int32_t rem;
|
||||
year += floorDivide(month, 12, rem);
|
||||
year += Math::floorDivide(month, 12, rem);
|
||||
month = rem;
|
||||
}
|
||||
}
|
||||
|
@ -1206,8 +1205,7 @@ GregorianCalendar::computeJulianDay(UBool isGregorian, int32_t year)
|
|||
double
|
||||
GregorianCalendar::millisToJulianDay(UDate millis)
|
||||
{
|
||||
return (double)kEpochStartAsJulianDay + floorDivide(millis, kOneDay);
|
||||
//return kEpochStartAsJulianDay + uprv_trunc(millis / kOneDay);
|
||||
return (double)kEpochStartAsJulianDay + Math::floorDivide(millis, kOneDay);
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
@ -1218,63 +1216,6 @@ GregorianCalendar::julianDayToMillis(double julian)
|
|||
return (UDate) ((julian - kEpochStartAsJulianDay) * (double) kOneDay);
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
double
|
||||
GregorianCalendar::floorDivide(double numerator, double denominator)
|
||||
{
|
||||
return uprv_floor(numerator / denominator);
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
int32_t
|
||||
GregorianCalendar::floorDivide(int32_t numerator, int32_t denominator)
|
||||
{
|
||||
// We do this computation in order to handle
|
||||
// a numerator of Long.MIN_VALUE correctly
|
||||
return (numerator >= 0) ?
|
||||
numerator / denominator :
|
||||
((numerator + 1) / denominator) - 1;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
int32_t
|
||||
GregorianCalendar::floorDivide(int32_t numerator, int32_t denominator, int32_t& remainder)
|
||||
{
|
||||
if (numerator >= 0) {
|
||||
remainder = numerator % denominator;
|
||||
return numerator / denominator;
|
||||
}
|
||||
int32_t quotient = ((numerator + 1) / denominator) - 1;
|
||||
remainder = numerator - (quotient * denominator);
|
||||
return quotient;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
int32_t
|
||||
GregorianCalendar::floorDivide(double numerator, int32_t denominator, int32_t& remainder)
|
||||
{
|
||||
double quotient;
|
||||
if (numerator >= 0) {
|
||||
quotient = uprv_trunc(numerator / denominator);
|
||||
remainder = (int32_t)uprv_fmod(numerator, denominator);
|
||||
} else {
|
||||
quotient = uprv_trunc((numerator + 1) / denominator) - 1;
|
||||
remainder = (int32_t)(numerator - (quotient * denominator));
|
||||
}
|
||||
if (quotient < INT32_MIN || quotient > INT32_MAX) {
|
||||
// Normalize out of range values. It doesn't matter what
|
||||
// we return for these cases; the data is wrong anyway. This
|
||||
// only occurs for years near 2,000,000,000 CE/BCE.
|
||||
quotient = 0.0; // Or whatever
|
||||
}
|
||||
return (int32_t)quotient;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
int32_t
|
||||
|
|
106
icu4c/source/i18n/gregoimp.cpp
Normal file
106
icu4c/source/i18n/gregoimp.cpp
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
**********************************************************************
|
||||
* Copyright (c) 2003, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
* Author: Alan Liu
|
||||
* Created: September 2 2003
|
||||
* Since: ICU 2.8
|
||||
**********************************************************************
|
||||
*/
|
||||
#include "gregoimp.h"
|
||||
#include "unicode/ucal.h"
|
||||
|
||||
int32_t Math::floorDivide(int32_t numerator, int32_t denominator) {
|
||||
return (numerator >= 0) ?
|
||||
numerator / denominator : ((numerator + 1) / denominator) - 1;
|
||||
}
|
||||
|
||||
double Math::floorDivide(double numerator, double denominator,
|
||||
double& remainder) {
|
||||
double quotient = uprv_floor(numerator / denominator);
|
||||
remainder = numerator - (quotient * denominator);
|
||||
return quotient;
|
||||
}
|
||||
|
||||
int32_t Math::floorDivide(double numerator, int32_t denominator,
|
||||
int32_t& remainder) {
|
||||
double quotient;
|
||||
quotient = uprv_floor(numerator / denominator);
|
||||
remainder = (int32_t) (numerator - (quotient * denominator));
|
||||
return (int32_t) quotient;
|
||||
}
|
||||
|
||||
const int32_t JULIAN_1_CE = 1721426; // January 1, 1 CE Gregorian
|
||||
const int32_t JULIAN_1970_CE = 2440588; // January 1, 1970 CE Gregorian
|
||||
|
||||
const int16_t Grego::DAYS_BEFORE[24] =
|
||||
{0,31,59,90,120,151,181,212,243,273,304,334,
|
||||
0,31,60,91,121,152,182,213,244,274,305,335};
|
||||
|
||||
const int8_t Grego::MONTH_LENGTH[24] =
|
||||
{31,28,31,30,31,30,31,31,30,31,30,31,
|
||||
31,29,31,30,31,30,31,31,30,31,30,31};
|
||||
|
||||
/**
|
||||
* Convert a year, month, and day-of-month, given in the proleptic Gregorian
|
||||
* calendar, to 1970 epoch days.
|
||||
* @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
|
||||
* @param month 0-based month, with 0==Jan
|
||||
* @param dom 1-based day of month
|
||||
*/
|
||||
double Grego::fieldsToDay(int32_t year, int32_t month, int32_t dom) {
|
||||
|
||||
int32_t y = year - 1;
|
||||
|
||||
double julian = 365 * y + Math::floorDivide(y, 4) + (JULIAN_1_CE - 3) + // Julian cal
|
||||
Math::floorDivide(y, 400) - Math::floorDivide(y, 100) + 2 + // => Gregorian cal
|
||||
DAYS_BEFORE[month + (isLeapYear(year) ? 12 : 0)] + dom; // => month/dom
|
||||
|
||||
return julian - JULIAN_1970_CE; // JD => epoch day
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a 1970-epoch day number to proleptic Gregorian year, month,
|
||||
* day-of-month, and day-of-week.
|
||||
* @param day 1970-epoch day (integral value)
|
||||
* @param year output parameter to receive year
|
||||
* @param month output parameter to receive month (0-based, 0==Jan)
|
||||
* @param dom output parameter to receive day-of-month (1-based)
|
||||
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
|
||||
*/
|
||||
void Grego::dayToFields(double day, int32_t& year, int32_t& month,
|
||||
int32_t& dom, int32_t& dow) {
|
||||
int32_t doy;
|
||||
|
||||
// Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
|
||||
day += JULIAN_1970_CE - JULIAN_1_CE;
|
||||
|
||||
int32_t n400 = Math::floorDivide(day, 146097, doy); // 400-year cycle length
|
||||
int32_t n100 = Math::floorDivide(doy, 36524, doy); // 100-year cycle length
|
||||
int32_t n4 = Math::floorDivide(doy, 1461, doy); // 4-year cycle length
|
||||
int32_t n1 = Math::floorDivide(doy, 365, doy);
|
||||
year = 400*n400 + 100*n100 + 4*n4 + n1;
|
||||
if (n100 == 4 || n1 == 4) {
|
||||
doy = 365; // Dec 31 at end of 4- or 400-year cycle
|
||||
} else {
|
||||
++year;
|
||||
}
|
||||
|
||||
UBool isLeap = isLeapYear(year);
|
||||
|
||||
// Gregorian day zero is a Monday.
|
||||
dow = (int32_t) uprv_fmod(day + 1, 7);
|
||||
dow += (dow < 0) ? (UCAL_SUNDAY + 7) : UCAL_SUNDAY;
|
||||
|
||||
// Common Julian/Gregorian calculation
|
||||
int32_t correction = 0;
|
||||
int32_t march1 = isLeap ? 60 : 59; // zero-based DOY for March 1
|
||||
if (doy >= march1) {
|
||||
correction = isLeap ? 1 : 2;
|
||||
}
|
||||
month = (12 * (doy + correction) + 6) / 367; // zero-based month
|
||||
dom = doy - DAYS_BEFORE[month + (isLeap ? 12 : 0)] + 1; // one-based DOM
|
||||
}
|
||||
|
||||
//eof
|
128
icu4c/source/i18n/gregoimp.h
Normal file
128
icu4c/source/i18n/gregoimp.h
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
**********************************************************************
|
||||
* Copyright (c) 2003, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
* Author: Alan Liu
|
||||
* Created: September 2 2003
|
||||
* Since: ICU 2.8
|
||||
**********************************************************************
|
||||
*/
|
||||
#ifndef GREGOIMP_H
|
||||
#define GREGOIMP_H
|
||||
#if !UCONFIG_NO_FORMATTING
|
||||
|
||||
#include "unicode/utypes.h"
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
class U_I18N_API Math {
|
||||
public:
|
||||
/**
|
||||
* 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 int32_t floorDivide(int32_t numerator, int32_t denominator);
|
||||
|
||||
/**
|
||||
* Divide two numbers, 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 inline double floorDivide(double numerator, double denominator);
|
||||
|
||||
private:
|
||||
static double floorDivide(double numerator, double denominator,
|
||||
double& remainder);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Divide two numbers, returning the floor of the quotient and
|
||||
* the modulus remainder. Unlike the built-in division, this is
|
||||
* mathematically well-behaved. E.g., <code>-1/4</code> => 0 and
|
||||
* <code>-1%4</code> => -1, but <code>floorDivide(-1,4)</code> =>
|
||||
* -1 with <code>remainder</code> => 3.
|
||||
* @param numerator the numerator
|
||||
* @param denominator a divisor which must be != 0
|
||||
* @param remainder output parameter to receive the
|
||||
* remainder. Unlike <code>numerator % denominator</code>, this
|
||||
* will always be non-negative, in the half-open range <code>[0,
|
||||
* |denominator|)</code>.
|
||||
* @return the floor of the quotient
|
||||
*/
|
||||
static int32_t floorDivide(double numerator, int32_t denominator,
|
||||
int32_t& remainder);
|
||||
};
|
||||
|
||||
class U_I18N_API Grego {
|
||||
public:
|
||||
/**
|
||||
* Return TRUE if the given year is a leap year.
|
||||
* @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
|
||||
* @return TRUE if the year is a leap year
|
||||
*/
|
||||
static inline UBool isLeapYear(int32_t year);
|
||||
|
||||
/**
|
||||
* Return the number of days in the given month.
|
||||
* @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
|
||||
* @param month 0-based month, with 0==Jan
|
||||
* @return the number of days in the given month
|
||||
*/
|
||||
static inline int8_t monthLength(int32_t year, int32_t month);
|
||||
|
||||
/**
|
||||
* Convert a year, month, and day-of-month, given in the proleptic
|
||||
* Gregorian calendar, to 1970 epoch days.
|
||||
* @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
|
||||
* @param month 0-based month, with 0==Jan
|
||||
* @param dom 1-based day of month
|
||||
* @return the day number, with day 0 == Jan 1 1970
|
||||
*/
|
||||
static double fieldsToDay(int32_t year, int32_t month, int32_t dom);
|
||||
|
||||
/**
|
||||
* Convert a 1970-epoch day number to proleptic Gregorian year,
|
||||
* month, day-of-month, and day-of-week.
|
||||
* @param day 1970-epoch day (integral value)
|
||||
* @param year output parameter to receive year
|
||||
* @param month output parameter to receive month (0-based, 0==Jan)
|
||||
* @param dom output parameter to receive day-of-month (1-based)
|
||||
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
|
||||
*/
|
||||
static void dayToFields(double day, int32_t& year, int32_t& month,
|
||||
int32_t& dom, int32_t& dow);
|
||||
|
||||
private:
|
||||
static const int16_t Grego::DAYS_BEFORE[24];
|
||||
static const int8_t Grego::MONTH_LENGTH[24];
|
||||
};
|
||||
|
||||
inline double Math::floorDivide(double numerator, double denominator) {
|
||||
return uprv_floor(numerator / denominator);
|
||||
}
|
||||
|
||||
inline UBool Grego::isLeapYear(int32_t year) {
|
||||
return (year%4 == 0) && ((year%100 != 0) || (year%400 == 0));
|
||||
}
|
||||
|
||||
inline int8_t
|
||||
Grego::monthLength(int32_t year, int32_t month) {
|
||||
return MONTH_LENGTH[month + isLeapYear(year)?12:0];
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
||||
#endif // !UCONFIG_NO_FORMATTING
|
||||
#endif // GREGOIMP_H
|
||||
|
||||
//eof
|
|
@ -1184,6 +1184,14 @@ InputPath=.\unicode\gregocal.h
|
|||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\gregoimp.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\gregoimp.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\japancal.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "unicode/ures.h"
|
||||
#include "unicode/simpletz.h"
|
||||
#include "unicode/gregocal.h"
|
||||
#include "gregoimp.h"
|
||||
#include "cmemory.h"
|
||||
#include "uassert.h"
|
||||
#include <float.h> // DBL_MAX
|
||||
|
@ -27,109 +28,6 @@ static const int32_t ZEROS[] = {0,0};
|
|||
|
||||
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OlsonTimeZone)
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Support methods
|
||||
|
||||
// TODO clean up; consolidate with GregorianCalendar, TimeZone, StandarTimeZone
|
||||
|
||||
static int32_t floorDivide(int32_t numerator, int32_t denominator) {
|
||||
return (numerator >= 0) ?
|
||||
numerator / denominator : ((numerator + 1) / denominator) - 1;
|
||||
}
|
||||
|
||||
static double floorDivide(double numerator, double denominator,
|
||||
double& remainder) {
|
||||
double quotient = uprv_floor(numerator / denominator);
|
||||
remainder = numerator - (quotient * denominator);
|
||||
return quotient;
|
||||
}
|
||||
|
||||
static int32_t floorDivide(double numerator, int32_t denominator,
|
||||
int32_t& remainder) {
|
||||
double quotient, rem;
|
||||
quotient = floorDivide(numerator, (double)denominator, rem);
|
||||
remainder = (int32_t) rem;
|
||||
return (int32_t) quotient;
|
||||
}
|
||||
|
||||
static const int32_t JULIAN_1_CE = 1721426; // January 1, 1 CE Gregorian
|
||||
static const int32_t JULIAN_1970_CE = 2440588; // January 1, 1970 CE Gregorian
|
||||
|
||||
static const int16_t DAYS_BEFORE[] =
|
||||
{0,31,59,90,120,151,181,212,243,273,304,334,
|
||||
0,31,60,91,121,152,182,213,244,274,305,335};
|
||||
|
||||
static const int8_t MONTH_LENGTH[] =
|
||||
{31,28,31,30,31,30,31,31,30,31,30,31,
|
||||
31,29,31,30,31,30,31,31,30,31,30,31};
|
||||
|
||||
static UBool isLeapYear(int year) {
|
||||
return (year%4 == 0) && ((year%100 != 0) || (year%400 == 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a year, month, and day-of-month, given in the proleptic Gregorian
|
||||
* calendar, to 1970 epoch days.
|
||||
* @param year Gregorian year, with 0 == 1 BCE, -1 == 2 BCE, etc.
|
||||
* @param month 0-based month, with 0==Jan
|
||||
* @param dom 1-based day of month
|
||||
*/
|
||||
static double fieldsToDay(int32_t year, int32_t month, int32_t dom) {
|
||||
|
||||
int32_t y = year - 1;
|
||||
|
||||
double julian = 365 * y + floorDivide(y, 4) + (JULIAN_1_CE - 3) + // Julian cal
|
||||
floorDivide(y, 400) - floorDivide(y, 100) + 2 + // => Gregorian cal
|
||||
DAYS_BEFORE[month + (isLeapYear(year) ? 12 : 0)] + dom; // => month/dom
|
||||
|
||||
return julian - JULIAN_1970_CE; // JD => epoch day
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a 1970-epoch day number to proleptic Gregorian year, month,
|
||||
* day-of-month, and day-of-week.
|
||||
* @param day 1970-epoch day (integral value)
|
||||
* @param year output parameter to receive year
|
||||
* @param month output parameter to receive month (0-based, 0==Jan)
|
||||
* @param dom output parameter to receive day-of-month (1-based)
|
||||
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
|
||||
*/
|
||||
static void dayToFields(double day, int32_t& year, int32_t& month,
|
||||
int32_t& dom, int32_t& dow) {
|
||||
int32_t doy;
|
||||
|
||||
// Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
|
||||
day += JULIAN_1970_CE - JULIAN_1_CE;
|
||||
|
||||
int32_t n400 = floorDivide(day, 146097, doy); // 400-year cycle length
|
||||
int32_t n100 = floorDivide(doy, 36524, doy); // 100-year cycle length
|
||||
int32_t n4 = floorDivide(doy, 1461, doy); // 4-year cycle length
|
||||
int32_t n1 = floorDivide(doy, 365, doy);
|
||||
year = 400*n400 + 100*n100 + 4*n4 + n1;
|
||||
if (n100 == 4 || n1 == 4) {
|
||||
doy = 365; // Dec 31 at end of 4- or 400-year cycle
|
||||
} else {
|
||||
++year;
|
||||
}
|
||||
|
||||
UBool isLeap = isLeapYear(year);
|
||||
|
||||
// Gregorian day zero is a Monday.
|
||||
dow = (int32_t) uprv_fmod(day + 1, 7);
|
||||
dow += (dow < 0) ? (UCAL_SUNDAY + 7) : UCAL_SUNDAY;
|
||||
|
||||
// Common Julian/Gregorian calculation
|
||||
int32_t correction = 0;
|
||||
int32_t march1 = isLeap ? 60 : 59; // zero-based DOY for March 1
|
||||
if (doy >= march1) {
|
||||
correction = isLeap ? 1 : 2;
|
||||
}
|
||||
month = (12 * (doy + correction) + 6) / 367; // zero-based month
|
||||
dom = doy - DAYS_BEFORE[month + (isLeap ? 12 : 0)] + 1; // one-based DOM
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Default constructor. Creates a time zone with an empty ID and
|
||||
* a fixed GMT offset of zero.
|
||||
|
@ -226,7 +124,7 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
|
|||
finalYear = data[1] - 1;
|
||||
// Also compute the millis for Jan 1, 0:00 GMT of the
|
||||
// finalYear. This reduces runtime computations.
|
||||
finalMillis = fieldsToDay(data[1], 0, 1) * U_MILLIS_PER_DAY;
|
||||
finalMillis = Grego::fieldsToDay(data[1], 0, 1) * U_MILLIS_PER_DAY;
|
||||
char key[64];
|
||||
key[0] = '_';
|
||||
ruleid.extract(0, sizeof(key)-2, key+1, sizeof(key)-1, "");
|
||||
|
@ -341,7 +239,7 @@ int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month,
|
|||
return 0;
|
||||
} else {
|
||||
return getOffset(era, year, month, dom, dow, millis,
|
||||
MONTH_LENGTH[month + isLeapYear(year)?12:0],
|
||||
Grego::monthLength(year, month),
|
||||
ec);
|
||||
}
|
||||
}
|
||||
|
@ -383,7 +281,7 @@ int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month,
|
|||
}
|
||||
|
||||
// Compute local epoch seconds from input fields
|
||||
double time = fieldsToDay(year, month, dom) * SECONDS_PER_DAY +
|
||||
double time = Grego::fieldsToDay(year, month, dom) * SECONDS_PER_DAY +
|
||||
uprv_floor(millis / (double) U_MILLIS_PER_SECOND);
|
||||
|
||||
return zoneOffset(findTransition(time, TRUE)) * U_MILLIS_PER_SECOND;
|
||||
|
@ -405,7 +303,7 @@ void OlsonTimeZone::getOffset(UDate date, UBool local, int32_t& rawoff,
|
|||
int32_t year, month, dom, dow;
|
||||
double days = uprv_floor(date / U_MILLIS_PER_DAY);
|
||||
|
||||
dayToFields(days, year, month, dom, dow);
|
||||
Grego::dayToFields(days, year, month, dom, dow);
|
||||
|
||||
int32_t millis = (int32_t) (date - days * U_MILLIS_PER_DAY);
|
||||
rawoff = finalZone->getRawOffset();
|
||||
|
@ -416,7 +314,7 @@ void OlsonTimeZone::getOffset(UDate date, UBool local, int32_t& rawoff,
|
|||
double days2 = uprv_floor(date / U_MILLIS_PER_DAY);
|
||||
millis = (int32_t) (date - days2 * U_MILLIS_PER_DAY);
|
||||
if (days2 != days) {
|
||||
dayToFields(days2, year, month, dom, dow);
|
||||
Grego::dayToFields(days2, year, month, dom, dow);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -505,11 +403,11 @@ UBool OlsonTimeZone::useDaylightTime() const {
|
|||
// DST is in use in the current year (at any point in the year)
|
||||
// and returns TRUE if so.
|
||||
|
||||
int32_t days = floorDivide(uprv_getUTCtime(), SECONDS_PER_DAY); // epoch days
|
||||
int32_t days = Math::floorDivide(uprv_getUTCtime(), SECONDS_PER_DAY); // epoch days
|
||||
|
||||
int32_t year, month, dom, dow;
|
||||
|
||||
dayToFields(days, year, month, dom, dow);
|
||||
Grego::dayToFields(days, year, month, dom, dow);
|
||||
|
||||
if (year > finalYear) { // [sic] >, not >=; see above
|
||||
U_ASSERT(finalZone != 0 && finalZone->useDaylightTime());
|
||||
|
@ -517,8 +415,8 @@ UBool OlsonTimeZone::useDaylightTime() const {
|
|||
}
|
||||
|
||||
// Find start of this year, and start of next year
|
||||
int32_t start = (int32_t) fieldsToDay(year, 0, 1) * SECONDS_PER_DAY;
|
||||
int32_t limit = (int32_t) fieldsToDay(year+1, 0, 1) * SECONDS_PER_DAY;
|
||||
int32_t start = (int32_t) Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY;
|
||||
int32_t limit = (int32_t) Grego::fieldsToDay(year+1, 0, 1) * SECONDS_PER_DAY;
|
||||
|
||||
// Return TRUE if DST is observed at any time during the current
|
||||
// year.
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "unicode/calendar.h"
|
||||
#include "unicode/gregocal.h"
|
||||
#include "unicode/ures.h"
|
||||
#include "gregoimp.h"
|
||||
#include "uresimp.h" // struct UResourceBundle
|
||||
#include "olsontz.h"
|
||||
#include "mutex.h"
|
||||
|
@ -357,7 +358,7 @@ TimeZone::createSystemTimeZone(const UnicodeString& id) {
|
|||
UResourceBundle *top = openOlsonResource(id, res, ec);
|
||||
if (U_SUCCESS(ec)) {
|
||||
z = new OlsonTimeZone(top, &res, ec);
|
||||
if (z) z->setID(id); // Hmm. cleanup? TODO
|
||||
if (z) z->setID(id);
|
||||
}
|
||||
ures_close(&res);
|
||||
ures_close(top);
|
||||
|
@ -517,104 +518,6 @@ TimeZone::setDefault(const TimeZone& zone)
|
|||
adoptDefault(zone.clone());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Support methods for getOffset(millis...)
|
||||
|
||||
// TODO clean up; consolidate with GregorianCalendar, TimeZone, StandarTimeZone
|
||||
|
||||
/**
|
||||
* Return floor(numerator/denominator); handles extreme values correctly.
|
||||
*/
|
||||
static int32_t floorDivide(int32_t numerator, int32_t denominator) {
|
||||
return (numerator >= 0) ?
|
||||
numerator / denominator : ((numerator + 1) / denominator) - 1;
|
||||
}
|
||||
|
||||
static int32_t floorDivide(int32_t numerator, int32_t denominator,
|
||||
int32_t& remainder) {
|
||||
int32_t quotient = floorDivide(numerator, denominator);
|
||||
remainder = numerator - (quotient * denominator);
|
||||
return quotient;
|
||||
}
|
||||
|
||||
static double floorDivide(double numerator, double denominator,
|
||||
double& remainder) {
|
||||
double quotient = uprv_floor(numerator / denominator);
|
||||
remainder = numerator - (quotient * denominator);
|
||||
return quotient;
|
||||
}
|
||||
|
||||
static int32_t floorDivide(double numerator, int32_t denominator,
|
||||
int32_t& remainder) {
|
||||
double quotient, rem;
|
||||
quotient = floorDivide(numerator, (double)denominator, rem);
|
||||
remainder = (int32_t) rem;
|
||||
return (int32_t) quotient;
|
||||
}
|
||||
|
||||
static const int32_t JULIAN_1_CE = 1721426; // January 1, 1 CE Gregorian
|
||||
static const int32_t JULIAN_1970_CE = 2440588; // January 1, 1970 CE Gregorian
|
||||
|
||||
/**
|
||||
* The number of days before the given month. There are two sets of
|
||||
* values for Jan..Dec; one set for non-leap years followed by another
|
||||
* set for leap years.
|
||||
*/
|
||||
static const int16_t DAYS_BEFORE[] =
|
||||
{0,31,59,90,120,151,181,212,243,273,304,334,
|
||||
0,31,60,91,121,152,182,213,244,274,305,335};
|
||||
|
||||
static const int8_t MONTH_LENGTH[] =
|
||||
{31,28,31,30,31,30,31,31,30,31,30,31,
|
||||
31,29,31,30,31,30,31,31,30,31,30,31};
|
||||
|
||||
static UBool isLeapYear(int year) {
|
||||
return (year%4 == 0) && ((year%100 != 0) || (year%400 == 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a 1970-epoch day number to proleptic Gregorian year, month,
|
||||
* day-of-month, and day-of-week.
|
||||
* @param day 1970-epoch day (integral value)
|
||||
* @param year output parameter to receive year
|
||||
* @param month output parameter to receive month (0-based, 0==Jan)
|
||||
* @param dom output parameter to receive day-of-month (1-based)
|
||||
* @param dow output parameter to receive day-of-week (1-based, 1==Sun)
|
||||
*/
|
||||
static void dayToFields(double day, int32_t& year, int32_t& month,
|
||||
int32_t& dom, int32_t& dow) {
|
||||
int32_t doy;
|
||||
|
||||
// Convert from 1970 CE epoch to 1 CE epoch (Gregorian calendar)
|
||||
day += JULIAN_1970_CE - JULIAN_1_CE;
|
||||
|
||||
int32_t n400 = floorDivide(day, 146097, doy); // 400-year cycle length
|
||||
int32_t n100 = floorDivide(doy, 36524, doy); // 100-year cycle length
|
||||
int32_t n4 = floorDivide(doy, 1461, doy); // 4-year cycle length
|
||||
int32_t n1 = floorDivide(doy, 365, doy);
|
||||
year = 400*n400 + 100*n100 + 4*n4 + n1;
|
||||
if (n100 == 4 || n1 == 4) {
|
||||
doy = 365; // Dec 31 at end of 4- or 400-year cycle
|
||||
} else {
|
||||
++year;
|
||||
}
|
||||
|
||||
UBool isLeap = isLeapYear(year);
|
||||
|
||||
// Gregorian day zero is a Monday.
|
||||
dow = (int32_t) uprv_fmod(day + 1, 7);
|
||||
dow += (dow < 0) ? (UCAL_SUNDAY + 7) : UCAL_SUNDAY;
|
||||
|
||||
// Common Julian/Gregorian calculation
|
||||
int32_t correction = 0;
|
||||
int32_t march1 = isLeap ? 60 : 59; // zero-based DOY for March 1
|
||||
if (doy >= march1) {
|
||||
correction = isLeap ? 1 : 2;
|
||||
}
|
||||
month = (12 * (doy + correction) + 6) / 367; // zero-based month
|
||||
dom = doy - DAYS_BEFORE[month + (isLeap ? 12 : 0)] + 1; // one-based DOM
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
@ -644,11 +547,11 @@ void TimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
|
|||
double day = uprv_floor(date / U_MILLIS_PER_DAY);
|
||||
int32_t millis = (int32_t) (date - day * U_MILLIS_PER_DAY);
|
||||
|
||||
dayToFields(day, year, month, dom, dow);
|
||||
Grego::dayToFields(day, year, month, dom, dow);
|
||||
|
||||
dstOffset = getOffset(GregorianCalendar::AD, year, month, dom,
|
||||
(uint8_t) dow, millis,
|
||||
MONTH_LENGTH[month + isLeapYear(year)?12:0],
|
||||
Grego::monthLength(year, month),
|
||||
ec) - rawOffset;
|
||||
|
||||
// Recompute if local==FALSE, dstOffset!=0, and addition of
|
||||
|
|
|
@ -810,62 +810,6 @@ protected:
|
|||
*/
|
||||
static uint8_t julianDayToDayOfWeek(double julian);
|
||||
|
||||
/**
|
||||
* Divide two long integers, returning the floor of the quotient.
|
||||
* <p>
|
||||
* 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 double floorDivide(double numerator, double denominator);
|
||||
|
||||
/**
|
||||
* Divide two integers, returning the floor of the quotient.
|
||||
* <p>
|
||||
* 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 int32_t floorDivide(int32_t numerator, int32_t denominator);
|
||||
|
||||
/**
|
||||
* Divide two integers, returning the floor of the quotient, and
|
||||
* the modulus remainder.
|
||||
* <p>
|
||||
* Unlike the built-in division, this is mathematically well-behaved.
|
||||
* E.g., <code>-1/4</code> => 0 and <code>-1%4</code> => -1,
|
||||
* but <code>floorDivide(-1,4)</code> => -1 with <code>remainder</code> => 3.
|
||||
* @param numerator the numerator
|
||||
* @param denominator a divisor which must be > 0
|
||||
* @param remainder an array of at least one element in which the value
|
||||
* <code>numerator mod denominator</code> is returned. Unlike <code>numerator
|
||||
* % denominator</code>, this will always be non-negative.
|
||||
* @return the floor of the quotient.
|
||||
*/
|
||||
static int32_t floorDivide(int32_t numerator, int32_t denominator, int32_t& remainder);
|
||||
|
||||
/**
|
||||
* Divide two integers, returning the floor of the quotient, and
|
||||
* the modulus remainder.
|
||||
* <p>
|
||||
* Unlike the built-in division, this is mathematically well-behaved.
|
||||
* E.g., <code>-1/4</code> => 0 and <code>-1%4</code> => -1,
|
||||
* but <code>floorDivide(-1,4)</code> => -1 with <code>remainder</code> => 3.
|
||||
* @param numerator the numerator
|
||||
* @param denominator a divisor which must be > 0
|
||||
* @param remainder an array of at least one element in which the value
|
||||
* <code>numerator mod denominator</code> is returned. Unlike <code>numerator
|
||||
* % denominator</code>, this will always be non-negative.
|
||||
* @return the floor of the quotient.
|
||||
*/
|
||||
static int32_t floorDivide(double numerator, int32_t denominator, int32_t& remainder);
|
||||
|
||||
public: // internal implementation
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue