Esempio n. 1
0
/**
* Override Calendar to compute several fields specific to the Islamic
* calendar system.  These are:
*
* <ul><li>ERA
* <li>YEAR
* <li>MONTH
* <li>DAY_OF_MONTH
* <li>DAY_OF_YEAR
* <li>EXTENDED_YEAR</ul>
*
* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
* method is called. The getGregorianXxx() methods return Gregorian
* calendar equivalents for the given Julian day.
* @draft ICU 2.4
*/
void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode & status)
{
	int32_t year, month, dayOfMonth, dayOfYear;
	UDate startDate;
	int32_t days = julianDay - 1948440;

	if (civil == CIVIL)
	{
		// Use the civil calendar approximation, which is just arithmetic
		year  = (int)ClockMath::floorDivide((double)(30 * days + 10646) , 10631.0);
		month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5);
		month = month < 11 ? month : 11;
		startDate = monthStart(year, month);
	}
	else
	{
		// Guess at the number of elapsed full months since the epoch
		int32_t months = (int32_t)uprv_floor((double)days / CalendarAstronomer::SYNODIC_MONTH);

		startDate = uprv_floor(months * CalendarAstronomer::SYNODIC_MONTH);

		double age = moonAge(internalGetTime(), status);
		if (U_FAILURE(status))
		{
			status = U_MEMORY_ALLOCATION_ERROR;
			return;
		}
		if (days - startDate >= 25 && age > 0)
		{
			// If we're near the end of the month, assume next month and search backwards
			months++;
		}

		// Find out the last time that the new moon was actually visible at this longitude
		// This returns midnight the night that the moon was visible at sunset.
		while ((startDate = trueMonthStart(months)) > days)
		{
			// If it was after the date in question, back up a month and try again
			months--;
		}

		year = months / 12 + 1;
		month = months % 12;
	}

	dayOfMonth = (days - monthStart(year, month)) + 1;

	// Now figure out the day of the year.
	dayOfYear = (days - monthStart(year, 0) + 1);

	internalSet(UCAL_ERA, 0);
	internalSet(UCAL_YEAR, year);
	internalSet(UCAL_EXTENDED_YEAR, year);
	internalSet(UCAL_MONTH, month);
	internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
	internalSet(UCAL_DAY_OF_YEAR, dayOfYear);
}
Esempio n. 2
0
UDate 
GregorianCalendar::getEpochDay(UErrorCode& status) 
{
    complete(status);
    // Divide by 1000 (convert to seconds) in order to prevent overflow when
    // dealing with UDate(Long.MIN_VALUE) and UDate(Long.MAX_VALUE).
    double wallSec = internalGetTime()/1000 + (internalGet(UCAL_ZONE_OFFSET) + internalGet(UCAL_DST_OFFSET))/1000;

    return ClockMath::floorDivide(wallSec, kOneDay/1000.0);
}
Esempio n. 3
0
void
GregorianCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status)
{
    if((amount == 0) || U_FAILURE(status)) {
        return;
    }

    // J81 processing. (gregorian cutover)
    UBool inCutoverMonth = FALSE;
    int32_t cMonthLen=0; // 'c' for cutover; in days
    int32_t cDayOfMonth=0; // no discontinuity: [0, cMonthLen)
    double cMonthStart=0.0; // in ms

    // Common code - see if we're in the cutover month of the cutover year
    if(get(UCAL_EXTENDED_YEAR, status) == fGregorianCutoverYear) {
        switch (field) {
        case UCAL_DAY_OF_MONTH:
        case UCAL_WEEK_OF_MONTH:
            {
                int32_t max = monthLength(internalGet(UCAL_MONTH));
                UDate t = internalGetTime();
                // We subtract 1 from the DAY_OF_MONTH to make it zero-based, and an
                // additional 10 if we are after the cutover. Thus the monthStart
                // value will be correct iff we actually are in the cutover month.
                cDayOfMonth = internalGet(UCAL_DAY_OF_MONTH) - ((t >= fGregorianCutover) ? 10 : 0);
                cMonthStart = t - ((cDayOfMonth - 1) * kOneDay);
                // A month containing the cutover is 10 days shorter.
                if ((cMonthStart < fGregorianCutover) &&
                    (cMonthStart + (cMonthLen=(max-10))*kOneDay >= fGregorianCutover)) {
                        inCutoverMonth = TRUE;
                    }
            }
        default:
            ;
        }
    }

    switch (field) {
    case UCAL_WEEK_OF_YEAR: {
        // Unlike WEEK_OF_MONTH, WEEK_OF_YEAR never shifts the day of the
        // week.  Also, rolling the week of the year can have seemingly
        // strange effects simply because the year of the week of year
        // may be different from the calendar year.  For example, the
        // date Dec 28, 1997 is the first day of week 1 of 1998 (if
        // weeks start on Sunday and the minimal days in first week is
        // <= 3).
        int32_t woy = get(UCAL_WEEK_OF_YEAR, status);
        // Get the ISO year, which matches the week of year.  This
        // may be one year before or after the calendar year.
        int32_t isoYear = get(UCAL_YEAR_WOY, status);
        int32_t isoDoy = internalGet(UCAL_DAY_OF_YEAR);
        if (internalGet(UCAL_MONTH) == UCAL_JANUARY) {
            if (woy >= 52) {
                isoDoy += handleGetYearLength(isoYear);
            }
        } else {
            if (woy == 1) {
                isoDoy -= handleGetYearLength(isoYear - 1);
            }
        }
        woy += amount;
        // Do fast checks to avoid unnecessary computation:
        if (woy < 1 || woy > 52) {
            // Determine the last week of the ISO year.
            // We do this using the standard formula we use
            // everywhere in this file.  If we can see that the
            // days at the end of the year are going to fall into
            // week 1 of the next year, we drop the last week by
            // subtracting 7 from the last day of the year.
            int32_t lastDoy = handleGetYearLength(isoYear);
            int32_t lastRelDow = (lastDoy - isoDoy + internalGet(UCAL_DAY_OF_WEEK) -
                getFirstDayOfWeek()) % 7;
            if (lastRelDow < 0) lastRelDow += 7;
            if ((6 - lastRelDow) >= getMinimalDaysInFirstWeek()) lastDoy -= 7;
            int32_t lastWoy = weekNumber(lastDoy, lastRelDow + 1);
            woy = ((woy + lastWoy - 1) % lastWoy) + 1;
        }
        set(UCAL_WEEK_OF_YEAR, woy);
        set(UCAL_YEAR_WOY,isoYear);
        return;
                            }

    case UCAL_DAY_OF_MONTH:
        if( !inCutoverMonth ) { 
            Calendar::roll(field, amount, status);
            return;
        } else {
            // [j81] 1582 special case for DOM
            // The default computation works except when the current month
            // contains the Gregorian cutover.  We handle this special case
            // here.  [j81 - aliu]
            double monthLen = cMonthLen * kOneDay;
            double msIntoMonth = uprv_fmod(internalGetTime() - cMonthStart +
                amount * kOneDay, monthLen);
            if (msIntoMonth < 0) {
                msIntoMonth += monthLen;
            }
#if defined (U_DEBUG_CAL)
            fprintf(stderr, "%s:%d: roll DOM %d  -> %.0lf ms  \n", 
                __FILE__, __LINE__,amount, cMonthLen, cMonthStart+msIntoMonth);
#endif
            setTimeInMillis(cMonthStart + msIntoMonth, status);
            return;
        }

    case UCAL_WEEK_OF_MONTH:
        if( !inCutoverMonth ) { 
            Calendar::roll(field, amount, status);
            return;
        } else {
#if defined (U_DEBUG_CAL)
            fprintf(stderr, "%s:%d: roll WOM %d ??????????????????? \n", 
                __FILE__, __LINE__,amount);
#endif
            // NOTE: following copied from  the old
            //     GregorianCalendar::roll( WEEK_OF_MONTH )  code 

            // This is tricky, because during the roll we may have to shift
            // to a different day of the week.  For example:

            //    s  m  t  w  r  f  s
            //          1  2  3  4  5
            //    6  7  8  9 10 11 12

            // When rolling from the 6th or 7th back one week, we go to the
            // 1st (assuming that the first partial week counts).  The same
            // thing happens at the end of the month.

            // The other tricky thing is that we have to figure out whether
            // the first partial week actually counts or not, based on the
            // minimal first days in the week.  And we have to use the
            // correct first day of the week to delineate the week
            // boundaries.

            // Here's our algorithm.  First, we find the real boundaries of
            // the month.  Then we discard the first partial week if it
            // doesn't count in this locale.  Then we fill in the ends with
            // phantom days, so that the first partial week and the last
            // partial week are full weeks.  We then have a nice square
            // block of weeks.  We do the usual rolling within this block,
            // as is done elsewhere in this method.  If we wind up on one of
            // the phantom days that we added, we recognize this and pin to
            // the first or the last day of the month.  Easy, eh?

            // Another wrinkle: To fix jitterbug 81, we have to make all this
            // work in the oddball month containing the Gregorian cutover.
            // This month is 10 days shorter than usual, and also contains
            // a discontinuity in the days; e.g., the default cutover month
            // is Oct 1582, and goes from day of month 4 to day of month 15.

            // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
            // in this locale.  We have dow in 0..6.
            int32_t dow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();
            if (dow < 0) 
                dow += 7;

            // Find the day of month, compensating for cutover discontinuity.
            int32_t dom = cDayOfMonth;

            // Find the day of the week (normalized for locale) for the first
            // of the month.
            int32_t fdm = (dow - dom + 1) % 7;
            if (fdm < 0) 
                fdm += 7;

            // Get the first day of the first full week of the month,
            // including phantom days, if any.  Figure out if the first week
            // counts or not; if it counts, then fill in phantom days.  If
            // not, advance to the first real full week (skip the partial week).
            int32_t start;
            if ((7 - fdm) < getMinimalDaysInFirstWeek())
                start = 8 - fdm; // Skip the first partial week
            else
                start = 1 - fdm; // This may be zero or negative

            // Get the day of the week (normalized for locale) for the last
            // day of the month.
            int32_t monthLen = cMonthLen;
            int32_t ldm = (monthLen - dom + dow) % 7;
            // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here.

            // Get the limit day for the blocked-off rectangular month; that
            // is, the day which is one past the last day of the month,
            // after the month has already been filled in with phantom days
            // to fill out the last week.  This day has a normalized DOW of 0.
            int32_t limit = monthLen + 7 - ldm;

            // Now roll between start and (limit - 1).
            int32_t gap = limit - start;
            int32_t newDom = (dom + amount*7 - start) % gap;
            if (newDom < 0) 
                newDom += gap;
            newDom += start;

            // Finally, pin to the real start and end of the month.
            if (newDom < 1) 
                newDom = 1;
            if (newDom > monthLen) 
                newDom = monthLen;

            // Set the DAY_OF_MONTH.  We rely on the fact that this field
            // takes precedence over everything else (since all other fields
            // are also set at this point).  If this fact changes (if the
            // disambiguation algorithm changes) then we will have to unset
            // the appropriate fields here so that DAY_OF_MONTH is attended
            // to.

            // If we are in the cutover month, manipulate ms directly.  Don't do
            // this in general because it doesn't work across DST boundaries
            // (details, details).  This takes care of the discontinuity.
            setTimeInMillis(cMonthStart + (newDom-1)*kOneDay, status);                
            return;
        }

    default:
        Calendar::roll(field, amount, status);
        return;
    }
}
Esempio n. 4
0
/**
* Override Calendar to compute several fields specific to the Islamic
* calendar system.  These are:
*
* <ul><li>ERA
* <li>YEAR
* <li>MONTH
* <li>DAY_OF_MONTH
* <li>DAY_OF_YEAR
* <li>EXTENDED_YEAR</ul>
* 
* The DAY_OF_WEEK and DOW_LOCAL fields are already set when this
* method is called. The getGregorianXxx() methods return Gregorian
* calendar equivalents for the given Julian day.
* @draft ICU 2.4
*/
void IslamicCalendar::handleComputeFields(int32_t julianDay, UErrorCode &status) {
    int32_t year, month, dayOfMonth, dayOfYear;
    int32_t startDate;
    int32_t days = julianDay - CIVIL_EPOC;

    if (cType == CIVIL || cType == TBLA) {
        if(cType == TBLA) {
            days = julianDay - ASTRONOMICAL_EPOC;
        }
        // Use the civil calendar approximation, which is just arithmetic
        year  = (int)ClockMath::floorDivide( (double)(30 * days + 10646) , 10631.0 );
        month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
        month = month<11?month:11;
        startDate = monthStart(year, month);
    } else if(cType == ASTRONOMICAL){
        // Guess at the number of elapsed full months since the epoch
        int32_t months = (int32_t)uprv_floor((double)days / CalendarAstronomer::SYNODIC_MONTH);

        startDate = (int32_t)uprv_floor(months * CalendarAstronomer::SYNODIC_MONTH);

        double age = moonAge(internalGetTime(), status);
        if (U_FAILURE(status)) {
            status = U_MEMORY_ALLOCATION_ERROR;
            return;
        }
        if ( days - startDate >= 25 && age > 0) {
            // If we're near the end of the month, assume next month and search backwards
            months++;
        }

        // Find out the last time that the new moon was actually visible at this longitude
        // This returns midnight the night that the moon was visible at sunset.
        while ((startDate = trueMonthStart(months)) > days) {
            // If it was after the date in question, back up a month and try again
            months--;
        }

        year = months / 12 + 1;
        month = months % 12;
    } else if(cType == UMALQURA) {
        int32_t umalquraStartdays = yearStart(UMALQURA_YEAR_START) ;
        if( days < umalquraStartdays){
                //Use Civil calculation
                year  = (int)ClockMath::floorDivide( (double)(30 * days + 10646) , 10631.0 );
                month = (int32_t)uprv_ceil((days - 29 - yearStart(year)) / 29.5 );
                month = month<11?month:11;
                startDate = monthStart(year, month);
            }else{
                int y =UMALQURA_YEAR_START-1, m =0;
                long d = 1;
                while(d > 0){ 
                    y++; 
                    d = days - yearStart(y) +1;
                    if(d == handleGetYearLength(y)){
                        m=11;
                        break;
                    }else if(d < handleGetYearLength(y) ){
                        int monthLen = handleGetMonthLength(y, m); 
                        m=0;
                        while(d > monthLen){
                            d -= monthLen;
                            m++;
                            monthLen = handleGetMonthLength(y, m);
                        }
                        break;
                    }
                }
                year = y;
                month = m;
            }
    } else { // invalid 'civil'
      U_ASSERT(false); // should not get here, out of range
      year=month=0;
    }

    dayOfMonth = (days - monthStart(year, month)) + 1;

    // Now figure out the day of the year.
    dayOfYear = (days - monthStart(year, 0)) + 1;


    internalSet(UCAL_ERA, 0);
    internalSet(UCAL_YEAR, year);
    internalSet(UCAL_EXTENDED_YEAR, year);
    internalSet(UCAL_MONTH, month);
    internalSet(UCAL_DAY_OF_MONTH, dayOfMonth);
    internalSet(UCAL_DAY_OF_YEAR, dayOfYear);       
}