// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Symbian Foundation License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32\euser\us_time.cpp
// System date and time functions
// 
//


#include "us_std.h"

// Date and time related constants

static const TInt KMinutesToMicroSeconds = 60000000;
static const TInt KSecondsToMicroSeconds = 1000000;
static const TInt64 KDaysToMicroSeconds = I64LIT(86400000000);
static const TInt64 KHoursToMicroSeconds = I64LIT(3600000000);

// Days in each month
LOCAL_D const TInt8 mTab[2][12]=
    {
    {31,28,31,30,31,30,31,31,30,31,30,31}, // 28 days in Feb
    {31,29,31,30,31,30,31,31,30,31,30,31}  // 29 days in Feb
    };

// Days in year before 1st of each month
LOCAL_D const TInt cmTab[2][12]=
	{
	{0,31,59,90,120,151,181,212,243,273,304,334},
	{0,31,60,91,121,152,182,213,244,274,305,335}
	};

//
// Time::FormatL overflow handler
//
#if defined(_UNICODE)
NONSHARABLE_CLASS(TTimeOverflowLeave) : public TDes16Overflow
	{
public:
	virtual void Overflow(TDes16 &aDes);
	};
void TTimeOverflowLeave::Overflow(TDes16 &/*aDes*/)
	{
	User::Leave(KErrOverflow);
	}
#else
NONSHARABLE_CLASS(TTimeOverflowLeave) : public TDes8Overflow
	{
public:
	virtual void Overflow(TDes8 &aDes);
	};
void TTimeOverflowLeave::Overflow(TDes8 &/*aDes*/)
	{
	User::Leave(KErrOverflow);
	}
#endif
//

EXPORT_C TDateTime::TDateTime(TInt aYear,TMonth aMonth,TInt aDay,TInt aHour,TInt aMinute,TInt aSecond,TInt aMicroSecond)
//
// always panic on a bad date/time field
//
/**
Constructs the TDateTime object with the seven fields which comprise a date 
and time.

@param aYear        The year. No check is made for validity.
@param aMonth       The month. Range is EJanuary to EDecember.
@param aDay         The day. Range is zero to number of days in month minus one.
@param aHour        The hour. Range is 0 to 23.
@param aMinute      The minute. Range is 0 to 59.
@param aSecond      The second. Range is 0 to 59
@param aMicroSecond The microsecond. Range is 0 to 999999

@panic USER 3, if an attempt is made to set an invalid value for any of 
       the fields, except for the year. No check is made upon the validity
       of the year.
*/
	{

	TInt ret=Set(aYear,aMonth,aDay,aHour,aMinute,aSecond,aMicroSecond);
	__ASSERT_ALWAYS(ret==KErrNone,Panic(ETDateTimeBadDateTime));
	}

EXPORT_C TInt TDateTime::Set(TInt aYear,TMonth aMonth,TInt aDay,TInt aHour,TInt aMinute,TInt aSecond,TInt aMicroSecond)
//
// set the various time fields checking that each is valid
// bomb out as soon as invalid field is set to forestall causing a panic
//
/**
Sets all date and time components.

Note:

1. When setting the day and month, subtract one because the ranges are offset 
   from zero. 

2. If the function returns an error, only those fields preceding the field which 
   caused the error will be changed. For example, if the hour is out of range, 
   the year, month and day will be set, all other components will remain unchanged.

@param aYear        Year. No check is made on its validity, except that if the
                    date is set to February 29th, the year can only be set to a
                    leap year, otherwise  an error is returned.
@param aMonth       Month. The valid range is EJanuary to EDecember. If an
                    attempt is made to set an invalid month, or if the current
                    day number in the month is greater than or equal to the
                    number of days in the new month, an error is returned.
@param aDay         The number of the day within the month, offset from zero.
                    If greater than or equal to the total number of days in
                    the month,an error is returned.
@param aHour        Hour. Range is 0 to 23.
@param aMinute      Minute. Range is 0 to 59.
@param aSecond      Second. Range is 0 to 59.
@param aMicroSecond Microsecond. Range is 0 to 999999.

@return KErrNone if successful, KErrGeneral if not.
*/
	{

	iYear=aYear;

	if (aMonth<EJanuary || aMonth>EDecember)
		return KErrGeneral;
	iMonth=aMonth;

	if (aDay<0 || aDay>=Time::DaysInMonth(iYear,iMonth))
		return KErrGeneral;
	iDay=aDay;

	if (aHour<0 || aHour>=24)
		return KErrGeneral;
	iHour=aHour;

	if (aMinute<0 || aMinute>=60)
		return KErrGeneral;
	iMinute=aMinute;

	if (aSecond<0 || aSecond>=60)
		return KErrGeneral;
	iSecond=aSecond;

	if (aMicroSecond<0 || aMicroSecond>=1000000)
		return KErrGeneral;
	iMicroSecond=aMicroSecond;

	return KErrNone;
	}

EXPORT_C TInt TDateTime::SetYear(TInt aYear)
//
// doesnt let you reset 29th February to non-leap year, no check on year range
//
/**
Sets the year without a leap year check.

No check is made on the validity of the year except that if the current date
is February 29th, the year can only be changed to another leap year, otherwise
an error is returned.

@param aYear The year.

@return KErrNone if successful, KErrGeneral if not.
*/
	{

	if (iDay>=Time::DaysInMonth(aYear,iMonth))
		return KErrGeneral;
	iYear=aYear;
	return KErrNone;
	}

EXPORT_C TInt TDateTime::SetYearLeapCheck(TInt aYear)
//
// lets you reset 29th February to non-leap year(moves date to 28th/Feb), no check on year range
//
/**
Sets the year with a leap year check.

Unlike SetYear(), if the date is the 29th February, this function allows
the year to be set to a non-leap year. In this case, the date is reset to
the 28th February.

@param aYear The year.

@return KErrNone if successful, KErrGeneral if not.

@see TDateTime::SetYear
*/
	{

	if (iDay>=Time::DaysInMonth(aYear,iMonth))
        iDay=27;
    iYear=aYear;
	return KErrNone;
	}

EXPORT_C TInt TDateTime::SetMonth(TMonth aMonth)
/**
Sets the month component of the date/time.

@param aMonth The month to be set. The range is from EJanuary to EDecember.
              If an attempt is made to set an invalid month, or if the current
              day number in the month is greater than or equal to the number of
              days in the new month, an error is returned.
              
@return KErrNone if successful, KErrGeneral if not.
*/
	{

	if (aMonth<EJanuary || aMonth>EDecember || iDay>=Time::DaysInMonth(iYear,aMonth))
		return KErrGeneral;
	iMonth=aMonth;
	return KErrNone;
	}

EXPORT_C TInt TDateTime::SetDay(TInt aDay)
/**
Sets the day component of the date/time.

@param aDay The number of the day within the month, offset from zero. If equal 
            to or greater than the total number of days in the month, an error
            is returned.
            
@return KErrNone if successful, KErrGeneral if not.
*/
	{

	if (aDay<0 || aDay>=Time::DaysInMonth(iYear,iMonth))
		return KErrGeneral;
	iDay=aDay;
	return KErrNone;
	}

EXPORT_C TInt TDateTime::SetHour(TInt aHour)
/**
Sets the hour component of the date/time.

@param aHour The hour. Range is 0 to 23.

@return KErrNone if successful, KErrGeneral if not.
*/
	{

	if (aHour<0 || aHour>=24) // GC - bug fix
		return KErrGeneral;
	iHour=aHour;
	return KErrNone;
	}

EXPORT_C TInt TDateTime::SetMinute(TInt aMinute)
/**
Sets the minute component of the date/time.

@param aMinute The minute. Range is 0 to 59.

@return KErrNone if successful, KErrGeneral if not.
*/
	{

	if (aMinute<0 || aMinute>=60)
		return KErrGeneral;
	iMinute=aMinute;
	return KErrNone;
	}

EXPORT_C TInt TDateTime::SetSecond(TInt aSecond)
/**
Sets the second component of the date/time.

@param aSecond The second. Range is 0 to 59.

@return KErrNone if successful, KErrGeneral if not.
*/
	{

	if (aSecond<0 || aSecond>=60)
		return KErrGeneral;
	iSecond=aSecond;
	return KErrNone;
	}

EXPORT_C TInt TDateTime::SetMicroSecond(TInt aMicroSecond)
/**
Sets the microsecond component of the date/time.

@param aMicroSecond The microsecond. Range is 0 to 999999.

@return KErrNone if successful, KErrGeneral if not.
*/
	{

	if (aMicroSecond<0 || aMicroSecond>=1000000)
		return KErrGeneral;
	iMicroSecond=aMicroSecond;
	return KErrNone;
	}

// class TTime

EXPORT_C TTime::TTime(const TDesC &aString)
/**
Constructs a TTime object with a text string.

The string consists of up to three components, any or all of which
may be omitted:

1. year, month and day, followed by a colon

2. hour, minute and second, followed by a dot

3. microsecond

When all three components are present, the string should take the form:

YYYYMMDD:HHMMSS.MMMMMM

The conversion from text to time is carried out in the same manner as that 
used in TTime::Set().

For a list of the range of valid values for date and time components,
see TDateTime::Set().

@param aString Date and time string for initializing the TTime object. 

@panic USER 113, if the string is syntactically incorrect, for example, if 
                 neither a colon nor a dot is present, or if any component of
                 the date or time is assigned an invalid value, or the year
                 is negative.

@see TTime::Set
@see TDateTime::Set
*/
	{

	__ASSERT_ALWAYS(Set(aString)==KErrNone,Panic(ETTimeValueOutOfRange));
	}

EXPORT_C TTime::TTime(const TDateTime &aDateTime) : iTime(Convert(aDateTime).Int64())
/**
Constructs a TTime object with the seven fields which comprise a date and time.

@param aDateTime Date and time to which to initialise the TTime object.
*/

    {}

EXPORT_C TInt TTime::Set(const TDesC &aString)
//
// Convert string to time. String is in the format:
//
// YYYYMMDD:HHMMSS.MMMMMM
//
// Any part may be ommitted, but either the
// dot or colon or both must be present
//
/**
Assigns a date and time contained in a descriptor to this TTime object.

The string consists of up to three components, any or all of which may
be omitted:

1. year, month and day, followed by a colon 

2. hour, minute and second, followed by a dot 

3. microsecond

When all three components are present, the string should take the form:

YYYYMMDD:HHMMSS.MMMMMM

If omitted, the first component is set to January 1st 0 AD nominal Gregorian. 
If either the second or third components are omitted, they are set to zero.

Notes:

1. The month and day values are offset from zero.

2. The only situations in which either the colon or dot may be omitted are as 
   follows:
   
   2.1 If the microsecond component is omitted, the preceding dot may also
       be omitted.

   2.2 The colon can be omitted only if a dot is located at string position
       zero (indicating that the first two components are missing), or at
       string position six (indicating that the first component only is
       missing).

@param aString The date and time to be assigned to this TTime object.
       
@return KErrNone if successful,
        KErrGeneral if the string is syntactically incorrect, for example,
        if neither a colon nor a dot is present, or if any component of the
        date or time is given an invalid value, or the year is negative.
        For a list of valid values for date and time components,
        see TDateTime::Set().
        If an error occurs, the date and time will remain unchanged.
*/
	{

//
// Get position of the colon and dot separators
//
    TInt colon=aString.Locate(':');
    TInt dot=aString.Locate('.');

    if(colon==KErrNotFound && dot==KErrNotFound)
        return(KErrGeneral);
//
// Zero parts that aren't supplied
//
    TInt yy=0;
    TInt mm=0;
    TInt dd=0;
    TInt hr=0;
    TInt mi=0;
    TInt se=0;
    TInt ms=0;
//
// Convert YYYYMMDD if present
//
    switch(colon)
        {
        case 0:
       	    break;
        case KErrNotFound:
            if(dot!=0 && dot!=6)
                return(KErrGeneral);
            colon=-1;
            break;
        case 8:
	   		{
            TLex y=aString.Left(4);
            TLex m=aString.Mid(4,2);
            TLex d=aString.Mid(6,2);
            y.Val(yy);
            m.Val(mm);
            d.Val(dd);
	    	}
            break;
        default: // Colon in wrong position - return error
            return(KErrGeneral);
        }
//
// Convert HHMMSS if present
//
    if(dot==KErrNotFound)
        dot=aString.Length();
     
    if(dot==colon+7)
        {
        TLex h=aString.Mid(dot-6,2);
        TLex m=aString.Mid(dot-4,2);
        TLex s=aString.Mid(dot-2,2);
        h.Val(hr);
        m.Val(mi);
        s.Val(se);
        }
    else if(dot!=KErrNotFound && dot!=0 && dot!=colon+1)
    	return(KErrGeneral);

    if(dot!=KErrNotFound)
        {
        if(aString.Length()>dot+7)
            return(KErrGeneral); // microseconds is more than 6 digits
        if(dot<aString.Length())
        	{
        	TLex m=aString.Mid(dot+1);
        	m.Val(ms);
        	}
        }
        
//
// Set the time! Do not construct newtime using the values or
// it may cause TTime::Set() to panic rather than return an error
//
	TDateTime newtime;
	if(newtime.Set(yy,TMonth(mm),dd,hr,mi,se,ms)!=KErrNone)
		return(KErrGeneral);
    (*this)=newtime;
	return KErrNone;
	}

EXPORT_C TInt TTime::HomeTimeSecure()
/**
Sets the date and time of this TTime to the secure home time. 
Returns KErrNoSecureTime if there is no secure time source
*/
	{
	TInt utOffset=0;
	TInt r = Exec::TimeNowSecure(*(TInt64*)this,utOffset);
    operator+=(TTimeIntervalSeconds(utOffset));
	return r;
	}

EXPORT_C TInt TTime::UniversalTimeSecure()
/**
Sets the date and time of this TTime to the secure universal time.
*/
	{
	TInt utOffset=0;
	return Exec::TimeNowSecure(*(TInt64*)this,utOffset);
	}

EXPORT_C void TTime::HomeTime()
/**
Sets the date and time of this TTime to the home time.
*/
	{
	TInt utOffset=0;
	Exec::TimeNow(*(TInt64*)this,utOffset);
    operator+=(TTimeIntervalSeconds(utOffset));
	}

EXPORT_C void TTime::UniversalTime()
/**
Sets the date and time of this TTime to the universal time.
*/
	{
	TInt utOffset=0;
	Exec::TimeNow(*(TInt64*)this,utOffset);
	}

EXPORT_C void TTime::RoundUpToNextMinute()
/**
Rounds this TTime up to the next minute.

Both the seconds and microseconds components are set to zero.
*/
	{

	if (iTime>0)
		iTime+=59999999;
//*	TInt64 remainder;
//*	Int64().DivMod(60000000,remainder);
//*	iTime-=remainder;	
	iTime-=iTime%60000000;
	}

TTime TTime::Convert(const TDateTime &aDateTime)
//
// converts TDateTime into a TTime, doesnt check for overflows
//
	{
	
	TInt days=365*aDateTime.Year()+Time::LeapYearsUpTo(aDateTime.Year());
	TBool isleap=Time::IsLeapYear(aDateTime.Year());
	days+=cmTab[isleap][aDateTime.Month()];
	days+=aDateTime.Day();

	TUint sum=aDateTime.MicroSecond()+aDateTime.Second()*KSecondsToMicroSeconds+aDateTime.Minute()*KMinutesToMicroSeconds;
	return(((TInt64(days*3)<<3)+TInt64(aDateTime.Hour()))*KHoursToMicroSeconds+TInt64(sum));
	}

EXPORT_C TTime &TTime::operator=(const TDateTime &aDateTime)
/**
Assigns a TDateTime object to this TTime object.

@param aDateTime The date and time to assign to this TTime object.

@return This TTime object.
*/
	{

	iTime=Convert(aDateTime).Int64();
	return(*this);
	}

EXPORT_C TDateTime TTime::DateTime() const
//
// converts iTime back into its TDateTime components
//
/**
Converts the TTime object into a TDateTime object.

This conversion must be done before the seven fields which comprise a date
and time can be accessed.

@return The components of the time, indicating year, month, day, hour, minute, 
        second, microsecond.
*/
	{

	TInt64 rem;
	TInt64 daysSince0AD64(iTime);
	
	rem = daysSince0AD64 % KDaysToMicroSeconds;
	daysSince0AD64 /= KDaysToMicroSeconds;

	TInt daysSince0AD = static_cast<TInt>(daysSince0AD64);

	TInt year;
	TInt daysLeft;
	if (iTime<0)
		{ // -1 to make daysLeft +ve and assume leap year every 4 years
		if (rem!=TInt64(0))
			{
			daysSince0AD--;
			rem=iTime-TInt64(daysSince0AD)*KDaysToMicroSeconds;
			}
		year=(4*daysSince0AD)/((4*365)+1);
		if ((4*daysSince0AD)%((4*365)+1))
			year--;
		daysLeft=daysSince0AD-((year*365)+Time::LeapYearsUpTo(year));
		}
	else
		{ // after 1600 leap years less than every four years
		year=(4*daysSince0AD)/((4*365)+1);
		daysLeft=daysSince0AD-((year*365)+Time::LeapYearsUpTo(year));
		TInt daysInYear=365+Time::IsLeapYear(year);
	    while (daysLeft>=daysInYear)
		    {
			year++;
	        daysLeft-=daysInYear;
			daysInYear=365+Time::IsLeapYear(year);
			}
		}

	TDateTime result(0,EJanuary,0,0,0,0,0);
	result.SetYear(year);

   	TBool isleap=Time::IsLeapYear(year);
    TInt month=11;
	const TInt* pCM=&(cmTab[isleap][11])+1;
	while(daysLeft<*--pCM)
		month--;
	daysLeft-=*pCM;

	result.SetMonth((TMonth)month);
	result.SetDay(daysLeft);

	TInt hour = static_cast<TInt>(rem >> 10) / 3515625;	// 3515625=KHoursToMicroSeconds/1024
	result.SetHour(hour);
	TUint rem32=I64LOW(rem-(TInt64(hour*3515625)<<10));
	TUint min=rem32/KMinutesToMicroSeconds;
	result.SetMinute((TInt)min);
	rem32-=min*KMinutesToMicroSeconds;
	TUint sec=rem32/KSecondsToMicroSeconds;
	result.SetSecond((TInt)sec);
	rem32-=sec*KSecondsToMicroSeconds;
	result.SetMicroSecond(TInt(rem32));
	return(result);
	}

EXPORT_C TTimeIntervalMicroSeconds TTime::MicroSecondsFrom(TTime aTime) const
//
// this - aTime
//
/**
Calculates the number of microseconds difference between the specified TTime
and this TTime.

@param aTime The time to be compared with this TTime.

@return Difference in microseconds between the two times. If the time specified 
        in the argument is later than this TTime, this value is negative.
*/
	{

	TInt64 difference=iTime-aTime.Int64();
	return(difference);
	}

EXPORT_C TInt TTime::SecondsFrom(TTime aTime,TTimeIntervalSeconds &aInterval) const
//
// this - aTime as whole seconds
// this function may fail if difference > no of seconds that can be represented in a TInt
//
/**
Calculates the number of seconds difference between the specified TTime and
this TTime.

The difference may be positive or negative.

@param aTime     The time to be compared with this TTime.
@param aInterval On return contains the difference in seconds between the two 
                 times. If the time specified in the first argument is later than
                 this TTime, then this returned value is negative.
                 
@return Error code. KErrNone if successful. 
                    KErrOverflow, if the calculated interval is too large for
                    a 32-bit integer.
*/
	{
	TInt64 diff;
	if (iTime>aTime.Int64())
		{
		diff= TInt64(TUint64(iTime-aTime.Int64())/KSecondsToMicroSeconds);	
		}
	else 
		{
		diff= -TInt64(TUint64(aTime.Int64()-iTime)/KSecondsToMicroSeconds);
		}	
	if (diff>KMaxTInt || diff<KMinTInt)	
	    return KErrOverflow; 
	aInterval = static_cast<TInt>(diff);
	return KErrNone;
	}
	
EXPORT_C TInt TTime::MinutesFrom(TTime aTime,TTimeIntervalMinutes &aInterval) const
//
// iTime - aTime as whole minutes
// function may fail if difference can't be represented as a TInt
//
/**
Calculates the number of minutes difference between the specified TTime and
this TTime.

The difference may be positive or negative.

@param aTime     The time to be compared with this TTime.
@param aInterval On return contains the difference in minutes between the two 
                 times. If the time specified in the first argument is later
                 than this TTime, then this returned value is negative.
                 
@return Error code. KErrNone if successful. 
                    KErrOverflow, if the calculated interval is too large for
                    a 32-bit integer.
*/
	{
	TInt64 diff;
	if (iTime>aTime.Int64())
		{
		diff= TInt64(TUint64(iTime-aTime.Int64())/KMinutesToMicroSeconds);	
		}
	else 
		{
		diff= -TInt64(TUint64(aTime.Int64()-iTime)/KMinutesToMicroSeconds);
		}	
	if (diff>KMaxTInt || diff<KMinTInt)	
	    return KErrOverflow; 
	aInterval = static_cast<TInt>(diff);
	return KErrNone; 
	}

EXPORT_C TInt TTime::HoursFrom(TTime aTime,TTimeIntervalHours &aInterval) const
//
// iTime - aTime as whole hours
// function may fail if difference can't be represented as a TInt
//
/**
Calculates the number of hours difference between the specified TTime and
this TTime. 

The difference may be positive or negative.

@param aTime     The time to be compared with this TTime.
@param aInterval On return contains the difference in hours between the two 
                 times. If the time specified in the first argument is later
                 than this TTime, then this returned value is negative.
                 
@return Error code. KErrNone if successful. 
                    KErrOverflow, if the calculated interval is too large for
                    a 32-bit integer.
*/
	{
	TInt64 diff;
	if (iTime>aTime.Int64())
		{
		diff= TInt64(TUint64(iTime-aTime.Int64())/KHoursToMicroSeconds);	
		}
	else 
		{
		diff= -TInt64(TUint64(aTime.Int64()-iTime)/KHoursToMicroSeconds);
		}
	if (diff>KMaxTInt || diff<KMinTInt)	
	    return KErrOverflow; 
	aInterval = static_cast<TInt>(diff);
	return KErrNone;
	}  


EXPORT_C TTimeIntervalDays TTime::DaysFrom(TTime aTime) const
//
// iTime - aTime as whole days
//
/**
Calculates the number of days difference between the specified TTime and
this TTime. 

The difference may be positive or negative.

@param aTime  The time to be compared with this TTime.

@return Difference in days between the two times. If the time specified in 
        aTime is later than this TTime, the returned value will be negative.
*/
	{
	if (iTime>aTime.Int64())
		{
		return TInt(TUint64(iTime-aTime.Int64())/KDaysToMicroSeconds);	
		}
	else 
		{
		return -TInt(TUint64(aTime.Int64()-iTime)/KDaysToMicroSeconds);
		}	
	}

EXPORT_C TTimeIntervalMonths TTime::MonthsFrom(TTime aTime) const
//
// iTime - aTime as whole months - ie aTime must be on a later day in the month and later in that day
// except for last days etc eg 31st October - 30 November is one month to be consistent with other
// functions
//
/**
Calculates the number of months between the specified TTime and this TTime.

The result may be positive or negative.

The interval in months between two TTimes is calculated by incrementing it 
by one each time the same day number and time in the previous or following 
month has been reached. Exceptions to this rule occur when this TTime is on 
the last day of the month. In this case, the following rules apply:

When comparing this TTime with a later time:

1. if the following month is shorter, one month is deemed to separate the times 
   when the same time on the last day of the following month is reached. In this 
   case, the two day numbers are not the same.

When comparing this TTime with an earlier time:

1. if the previous month is shorter, one month is deemed to separate the times 
   when the last microsecond of the previous month is reached (23:59:59.999999 
   on the last day of the month).

2. if the previous month is longer, one month is deemed to separate the times 
   when the same time on the last day of previous month is reached. In this case, 
   the two day numbers are not the same.

@param aTime The time to be compared with this TTime.

@return Difference in months between the two times. If the time specified in 
        the argument is later than this TTime, the interval is negative.
*/
	{

	TDateTime dateTimei=DateTime();
	TDateTime dateTimea=aTime.DateTime();
	
	TInt monthsDifference=(dateTimei.Year()-dateTimea.Year())*12+(dateTimei.Month()-dateTimea.Month());

	if (monthsDifference>0)
		{
		if (dateTimei.Day()<=dateTimea.Day())
			{
			if (iTime%KDaysToMicroSeconds<aTime.Int64()%KDaysToMicroSeconds || (dateTimei.Day()!=dateTimea.Day() && dateTimei.Day()!=DaysInMonth()-1))
				monthsDifference--;
			}
		}
	else
		if (monthsDifference!=0)//monthsDifference<0
			{
			if (dateTimei.Day()>=dateTimea.Day())
				{
				if (iTime%KDaysToMicroSeconds>aTime.Int64()%KDaysToMicroSeconds || (dateTimei.Day()!=dateTimea.Day() && dateTimea.Day()!=aTime.DaysInMonth()-1))
					monthsDifference++;
				}
			}

	return(monthsDifference);			
	}

EXPORT_C TTimeIntervalYears TTime::YearsFrom(TTime aTime) const
//
// as above,but for twelve months
//
/**
Calculates the number of years between the specified TTime and this TTime.

The result may be positive or negative.

Note that the interval in years between two TTimes is calculated by
incrementing it by one each time the same day number and time in the previous
or following year has been reached. The exception to this rule occurs when this
TTime is the last day in February in a leap year. In this case, one year is
deemed to have passed when the same time of day on the last day in the preceding 
or following February has been reached.

@param aTime The time to be compared with this TTime.

@return Difference in years between the two times. If the time specified in 
        the argument is later than this TTime, the interval is negative.
*/
	{

	TTimeIntervalMonths mos= TTime::MonthsFrom(aTime);
	TTimeIntervalYears ret=mos.Int()/12;
	return(ret);			
	}

EXPORT_C TTime TTime::operator+(TTimeIntervalYears aYear) const
/**
Adds a time interval to this TTime, returning the result
as a TTime.

Note that in a leap year, when adding one year to the 29th February, the result
is the 28th February in the following year.

Note also that this TTime object is not changed.

@param aYear A time interval in years. The argument is stored as a 32 bit
             signed integer. The maximum value which it can represent is
             2147483647. Any attempt to add more than this amount will
             produce incorrect results.

@return The new time.
*/
	{

	return((*this)+TTimeIntervalMonths(aYear.Int()*12));
	}

EXPORT_C TTime TTime::operator+(TTimeIntervalMonths aMonth) const
/**
Adds a time interval to this TTime, returning the result
as a TTime.

Note that when adding one month to the last day in the month, if the following
month is shorter, the result is the last day in the following month.
For example, when adding one month to 31st August, the result is
the 30th September.

Note also that this TTime object is not changed.

@param aMonth A time interval in months. The argument is stored as a 32 bit
              signed integer. The maximum value which it can represent is
              2147483647. Any attempt to add more than this amount will
              produce incorrect results.

@return The new time.
*/
	{

	TDateTime dateTime=DateTime();
	TInt month=dateTime.Month()+(dateTime.Year()*12)+aMonth.Int();
	TInt day=dateTime.Day();
	TInt year=month/12;
	month%=12;
	if (month<0)
		{
		year--;
		month+=12;
		}
	TInt daysInMonth=(mTab[Time::IsLeapYear(year)][month]-1); 
	if (day>=daysInMonth)
		day=daysInMonth;
	dateTime.Set(year,TMonth(month),day,dateTime.Hour(),dateTime.Minute(),dateTime.Second(),dateTime.MicroSecond());
	return(dateTime);
	}
							 
EXPORT_C TTime TTime::operator+(TTimeIntervalDays aDay) const
/**
Adds a time interval to this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aDay A time interval in days. The argument is stored as a 32 bit
            signed integer. The maximum value which it can represent is
            2147483647. Any attempt to add more than this amount will
            produce incorrect results.

@return The new time.
*/
	{ 

	return(iTime+TInt64(aDay.Int())*KDaysToMicroSeconds);
	}

EXPORT_C TTime TTime::operator+(TTimeIntervalHours aHour) const
/**
Adds a time interval to this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aHour A time interval in hours. The argument is stored as a 32 bit
             signed integer. The maximum value which it can represent is
             2147483647. Any attempt to add more than this amount will
             produce incorrect results.

@return The new time.
*/
	{

	return(iTime+TInt64(aHour.Int())*KHoursToMicroSeconds);
	}

EXPORT_C TTime TTime::operator+(TTimeIntervalMinutes aMinute) const
/**
Adds a time interval to this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aMinute A time interval in minutes. The argument is stored as a 32 bit
               signed integer. The maximum value which it can represent is
               2147483647. Any attempt to add more than this amount will
               produce incorrect results.

@return The new time.
*/
	{

	return(iTime+TInt64(aMinute.Int())*KMinutesToMicroSeconds);
	}

EXPORT_C TTime TTime::operator+(TTimeIntervalSeconds aSecond) const
/**
Adds a time interval to this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aSecond A time interval in seconds. The argument is stored as a 32 bit
               signed integer. The maximum value which it can represent is
               2147483647. Any attempt to add more than this amount will
               produce incorrect results.

@return The new time.
*/
	{

	return(iTime+TInt64(aSecond.Int())*KSecondsToMicroSeconds);
	}

 
EXPORT_C TTime TTime::operator+(TTimeIntervalMicroSeconds aMicroSecond) const
/**
Adds a time interval to this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aMicroSecond A time interval in microseconds.

@return The new time.
*/
	{

	return(iTime+(aMicroSecond.Int64()));
	}

EXPORT_C TTime TTime::operator+(TTimeIntervalMicroSeconds32 aMicroSecond) const
/**
Adds a time interval to this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aMicroSecond A time interval in microseconds. The argument is stored as
                    a 32 bit signed integer. The maximum value which it can
                    represent is 2147483647. Any attempt to add more than this
                    amount will produce incorrect results.

@return The new time.
*/
	{

	return(iTime+aMicroSecond.Int());
	}

EXPORT_C TTime TTime::operator-(TTimeIntervalYears aYear) const
/**
Substracts a time interval from this TTime, returning the result
as a TTime.

Note that in a leap year, when subtracting one year from the 29th February,
the result is 28th February in the preceding year.

Note also that this TTime object is not changed.

@param aYear A time interval in years. The argument is stored as
             a 32 bit signed integer. The maximum value which it can
             represent is 2147483647. Any attempt to subtract more than this
             amount will produce incorrect results.

@return The new time.
*/
	{

	return((*this)-TTimeIntervalMonths(aYear.Int()*12));
	}

EXPORT_C TTime TTime::operator-(TTimeIntervalMonths aMonth) const
/**
Substracts a time interval from this TTime, returning the result
as a TTime.

Note that when subtracting one month from the last day in the month, if the
preceding month is shorter, the result is the last day in the preceding month.
For example, when subtracting 1 month from 31st October, the result is
the 30th September.

Note also that this TTime object is not changed.

@param aMonth A time interval in months. The argument is stored as
              a 32 bit signed integer. The maximum value which it can
              represent is 2147483647. Any attempt to subtract more than this
              amount will produce incorrect results.

@return The new time.
*/
	{

	return((*this)+TTimeIntervalMonths(aMonth.Int()*-1));
	}
							 
EXPORT_C TTime TTime::operator-(TTimeIntervalDays aDay) const
/**
Substracts a time interval from this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aDay A time interval in days. The argument is stored as
            a 32 bit signed integer. The maximum value which it can
            represent is 2147483647. Any attempt to subtract more than this
            amount will produce incorrect results.

@return The new time.
*/
	{ 

	return(iTime-TInt64(aDay.Int())*KDaysToMicroSeconds);
	}

EXPORT_C TTime TTime::operator-(TTimeIntervalHours aHour) const
/**
Substracts a time interval from this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aHour A time interval in hours. The argument is stored as
             a 32 bit signed integer. The maximum value which it can
             represent is 2147483647. Any attempt to subtract more than this
             amount will produce incorrect results.

@return The new time.
*/
	{

	return(iTime-TInt64(aHour.Int())*KHoursToMicroSeconds);
	}

EXPORT_C TTime TTime::operator-(TTimeIntervalMinutes aMinute) const
/**
Substracts a time interval from this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aMinute A time interval in minutes. The argument is stored as
               a 32 bit signed integer. The maximum value which it can
               represent is 2147483647. Any attempt to subtract more than this
               amount will produce incorrect results.

@return The new time.
*/
	{

	return(iTime-TInt64(aMinute.Int())*KMinutesToMicroSeconds);
	}

EXPORT_C TTime TTime::operator-(TTimeIntervalSeconds aSecond) const
/**
Substracts a time interval from this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aSecond A time interval in seconds. The argument is stored as
               a 32 bit signed integer. The maximum value which it can
               represent is 2147483647. Any attempt to subtract more than this
               amount will produce incorrect results.

@return The new time.
*/
	{

	return(iTime-TInt64(aSecond.Int())*KSecondsToMicroSeconds);
	}

EXPORT_C TTime TTime::operator-(TTimeIntervalMicroSeconds aMicroSecond) const
/**
Substracts a time interval from this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aMicroSecond A time interval in microseconds.

@return The new time.
*/
	{

	return(iTime-(aMicroSecond.Int64()));
	}

EXPORT_C TTime TTime::operator-(TTimeIntervalMicroSeconds32 aMicroSecond) const
/**
Substracts a time interval from this TTime, returning the result
as a TTime.

Note that this TTime object is not changed.

@param aMicroSecond A time interval in microseconds. The argument is stored as
                    a 32 bit signed integer. The maximum value which it can
                    represent is 2147483647. Any attempt to subtract more than
                    this amount will produce incorrect results.

@return The new time.
*/
	{

	return(iTime-aMicroSecond.Int());
	}

EXPORT_C TTime &TTime::operator+=(TTimeIntervalYears aYear)
/**
Adds a time interval to this TTime, returning a reference to this TTime.

@param aYear A time interval in years.

@return A reference to this TTime.
*/
	{	

	TTime tim=(*this)+aYear;
	iTime=tim.Int64();
	return(*this);
	}

EXPORT_C TTime &TTime::operator+=(TTimeIntervalMonths aMonth)
/**
Adds a time interval to this TTime, returning a reference to this TTime.

@param aMonth A time interval in months.

@return A reference to this TTime.
*/
	{

	TTime tim=(*this)+aMonth;
	iTime=tim.Int64();
	return(*this);
	}

EXPORT_C TTime &TTime::operator+=(TTimeIntervalDays aDay)
/**
Adds a time interval to this TTime, returning a reference to this TTime.

@param aDay A time interval in days.

@return A reference to this TTime.
*/
	{

	iTime+=TInt64(aDay.Int())*KDaysToMicroSeconds;
	return(*this);
	}

EXPORT_C TTime &TTime::operator+=(TTimeIntervalHours aHour)
/**
Adds a time interval to this TTime, returning a reference to this TTime.

@param aHour A time interval in hours.

@return A reference to this TTime.
*/
	{

	iTime+=TInt64(aHour.Int())*KHoursToMicroSeconds;
	return(*this);
	}

EXPORT_C TTime &TTime::operator+=(TTimeIntervalMinutes aMinute)
/**
Adds a time interval to this TTime, returning a reference to this TTime.

@param aMinute A time interval in minutes.

@return A reference to this TTime.
*/
	{

	iTime+=TInt64(aMinute.Int())*KMinutesToMicroSeconds;
	return(*this);
	}

EXPORT_C TTime &TTime::operator+=(TTimeIntervalSeconds aSecond)
/**
Adds a time interval to this TTime, returning a reference to this TTime.

@param aSecond A time interval in seconds.

@return A reference to this TTime.
*/
	{

	iTime+=TInt64(aSecond.Int())*KSecondsToMicroSeconds;
	return(*this);
	}

EXPORT_C TTime &TTime::operator+=(TTimeIntervalMicroSeconds aMicroSecond)
/**
Adds a time interval to this TTime, returning a reference to this TTime.

@param aMicroSecond A time interval in microseconds.

@return A reference to this TTime.
*/
	{

	iTime+=aMicroSecond.Int64();
	return(*this);
	}
 
EXPORT_C TTime &TTime::operator+=(TTimeIntervalMicroSeconds32 aMicroSecond)
/**
Adds a time interval to this TTime, returning a reference to this TTime.

@param aMicroSecond A time interval in microseconds, as a 32-bit integer.

@return A reference to this TTime.
*/
	{

	iTime+=aMicroSecond.Int();
	return(*this);
	}
 
EXPORT_C TTime &TTime::operator-=(TTimeIntervalYears aYear)
/**
Subtracts a time interval from this TTime, returning a reference to this TTime.

@param aYear A time interval in years.

@return A reference to this TTime.
*/
	{	

	TTime tim=(*this)-aYear;
	iTime=tim.Int64();
	return(*this);
	}

EXPORT_C TTime &TTime::operator-=(TTimeIntervalMonths aMonth)
/**
Subtracts a time interval from this TTime, returning a reference to this TTime.

@param aMonth A time interval in months.

@return A reference to this TTime.
*/
	{

	TTime tim=(*this)-aMonth;
	iTime=tim.Int64();
	return(*this);
	}

EXPORT_C TTime &TTime::operator-=(TTimeIntervalDays aDay)
/**
Subtracts a time interval from this TTime, returning a reference to this TTime.

@param aDay A time interval in days.

@return A reference to this TTime.
*/
	{

	iTime-=TInt64(aDay.Int())*KDaysToMicroSeconds;
	return(*this);
	}

EXPORT_C TTime &TTime::operator-=(TTimeIntervalHours aHour)
/**
Subtracts a time interval from this TTime, returning a reference to this TTime.

@param aHour A time interval in hours.

@return A reference to this TTime.
*/
	{

	iTime-=TInt64(aHour.Int())*KHoursToMicroSeconds;
	return(*this);
	}

EXPORT_C TTime &TTime::operator-=(TTimeIntervalMinutes aMinute)
/**
Subtracts a time interval from this TTime, returning a reference to this TTime.

@param aMinute A time interval in minutes.

@return A reference to this TTime.
*/
	{

	iTime-=TInt64(aMinute.Int())*KMinutesToMicroSeconds;
	return(*this);
	}

EXPORT_C TTime &TTime::operator-=(TTimeIntervalSeconds aSecond)
/**
Subtracts a time interval from this TTime, returning a reference to this TTime.

@param aSecond A time interval in seconds.

@return A reference to this TTime.
*/
	{

	iTime-=TInt64(aSecond.Int())*KSecondsToMicroSeconds;
	return(*this);
	}

EXPORT_C TTime &TTime::operator-=(TTimeIntervalMicroSeconds aMicroSecond)
/**
Subtracts a time interval from this TTime, returning a reference to this TTime.

@param aMicroSecond A time interval in microseconds.

@return A reference to this TTime.
*/
	{

	iTime-=aMicroSecond.Int64();
	return(*this);
	}

EXPORT_C TTime &TTime::operator-=(TTimeIntervalMicroSeconds32 aMicroSecond)
/**
Subtracts a time interval from this TTime, returning a reference to this TTime.

@param aMicroSecond A time interval in microseconds, as a 32-bit integer.

@return A reference to this TTime.
*/
	{

	iTime-=aMicroSecond.Int();
	return(*this);
	}
 
EXPORT_C TInt TTime::DaysInMonth() const
/**
Gets the number of days in the current month.

@return The number of days in the month.
*/
	{

	TDateTime dateTime=DateTime();
	return(Time::DaysInMonth(dateTime.Year(),dateTime.Month()));
	}

EXPORT_C TDay TTime::DayNoInWeek() const
//
// 1st January 0AD was a Monday
//
/**
Gets the day number within the current week.

This is a value in the range zero to six inclusive, and honours the 
setting specified in TLocale::SetStartOfWeek().

By default the first day in the week is Monday.

@return The number of the day within the week. The range is EMonday to ESunday.

@see TLocale::SetStartOfWeek
*/
	{


	TInt64 fullDays=iTime/KDaysToMicroSeconds;
	TInt day = static_cast<TInt>(fullDays) % 7;
	if (iTime<0)
		{
		if (fullDays*KDaysToMicroSeconds!=iTime)
			day+=6;
		else
			if (day!=0)
				day+=7;
		}
	return((TDay)day);
	}

EXPORT_C TInt TTime::DayNoInMonth() const
/**
Gets the day number in the month.

@return The day number in the month. The first day in the month is numbered 
        zero.
*/
	{

	return(DateTime().Day());
	}

EXPORT_C TInt TTime::DayNoInYear() const
//
// day number in comparison to 1st January
//
/**
Gets the day number in the year. 

@return The day number in the year. The first day in the year is day one.
*/
	{

	TDateTime dateTime=DateTime();
	TTime jan1st=TDateTime(dateTime.Year(),EJanuary,0,0,0,0,0);
	return(DayNoInYear(jan1st));
	}

EXPORT_C TInt TTime::DayNoInYear(TTime aStartDate) const
//
// day number in comparison to given date, check is made to ensure first day is within a year before aDay
//
/**
Gets the day number in the year when the start of the year is aStartDate. 

If no start date is specified, the default is January 1st.

@param aStartDate Indicates the date which is to be considered the start of 
                  the year. Default is 1st January.
                  
@return The day number in the year. The first day in the year is day one.
*/
	{

	TInt y=DateTime().Year();
	TMonth m=aStartDate.DateTime().Month();
	TInt d=aStartDate.DateTime().Day();
    if (d>=Time::DaysInMonth(y,m))
        d=27;
    TDateTime yearStart(y,m,d,0,0,0,0);              // LEAP YEAR PROBLEMS ???
	aStartDate=yearStart;
	if (aStartDate>*this)
		{
		yearStart.SetYearLeapCheck(y-1);
		aStartDate=yearStart;
		}
    return((DaysFrom(aStartDate).Int())+1) ;
    }

EXPORT_C TInt TTime::WeekNoInYear() const
/**
Gets the number of the current week in the year.

@return Week number in the year.
*/
	{

	return(WeekNoInYear(EFirstFourDayWeek));
	}

EXPORT_C TInt TTime::WeekNoInYear(TTime aStartDate) const
/**
Gets the number of the current week in the year when the year starts
on aStartDate. 

@param aStartDate If specified, indicates the date which is to be considered 
                  the start of the year. Default is 1st January.
                  
@return Week number in the year.
*/
	{
    
    return(WeekNoInYear(aStartDate,EFirstFourDayWeek));
	}

EXPORT_C TInt TTime::WeekNoInYear(TFirstWeekRule aRule) const
/**
Finds the number of the current week in the year using the first week rule 
specified in aRule. 

@param aRule Determines how the first week in the year is to be calculated. 
             By default EFirstFourDayWeek.
             
@return Week number in the year.
*/
	{
	
	TInt year=DateTime().Year();
	TTime startDate=TDateTime(year,EJanuary,0,0,0,0,0);
	return(WeekNoInYear(startDate,aRule));
	}

EXPORT_C TInt TTime::WeekNoInYear(TTime aStartDate,TFirstWeekRule aRule) const
//
// number of weeks between aTime and aStartDate according to given rule
// the first week starts either on the week containing the first day (EFirstWeek), 
// the first week having at least four days within the new year (EFirstFourDayWeek,
//  default) or the first full week in the year (EFirstFullWeek)
//
/**
Finds the number of the current week in the year when the year starts from 
aStartDate and when using the start week rule aRule.

@param aStartDate If specified, indicates the date which is to be considered 
                  the start of the year. Default is 1st January.
@param aRule      Determines how the first week in the year is to be
                  calculated. By default EFirstFourDayWeek.
                  
@return Week number in the year.
*/
	{                    
	TInt dayNoInWeek=DayNoInWeek();
	TInt dayNoInYear=(DayNoInYear(aStartDate))-1;    // puts start into correct year
	TDateTime startDateTime(aStartDate.DateTime());
	TDateTime nextYearStartDate(startDateTime);
	nextYearStartDate.SetYearLeapCheck(DateTime().Year());    // find start of next year
	TTime nextYearStartTime(nextYearStartDate);            // makes sure start date for year
	if (*this>nextYearStartTime)                           // is in the very next year
		{
		nextYearStartDate.SetYearLeapCheck(nextYearStartDate.Year()+1);
		nextYearStartTime=nextYearStartDate;
		}
	nextYearStartTime+=TTimeIntervalMicroSeconds(KDaysToMicroSeconds-1); // avoid problems if the time is not midnight
	TLocale local;
	TDay startOfFirstWeek=local.StartOfWeek();
	// calculate the day-in-week number (0 to 6) based on the locale start-of-week
	dayNoInWeek -= startOfFirstWeek;
	if (dayNoInWeek < 0)
		dayNoInWeek += 7;
	// calculate the days from the start-of-week to the start-of-next-year
	TInt daysFrom=nextYearStartTime.DaysFrom(*this).Int()+dayNoInWeek;
	// calculate the days from start-of-year to start-of-week (note this may be negative, but never < -6)
	TInt days=dayNoInYear-dayNoInWeek;

	// the rule allows a certain number of week-1 days to lie in the previous year
	TInt prevyeardays;
	switch (aRule)
		{
	default:
		return -1;
	case EFirstWeek:
		prevyeardays = 6;
		break;
	case EFirstFourDayWeek:
		prevyeardays = 3;
		break;
	case EFirstFullWeek:
		prevyeardays = 0;
		break;
		}

	// check for a week which belongs to last year
	if (days + prevyeardays < 0)
		{
		// in week 52 or 53 of last year, find the week # of the first day in the week
		startDateTime.SetYearLeapCheck(startDateTime.Year()-1);
		return (*this-TTimeIntervalDays(dayNoInWeek)).WeekNoInYear(TTime(startDateTime),aRule);
		}

	// check for a week which belongs to next year
	if (daysFrom <= prevyeardays)
		return 1;

	// calculate the week number, accounting for the requested week-1 rule
	return (days + 7 + prevyeardays)/7;
	}

EXPORT_C void TTime::FormatL(TDes &aDes,const TDesC &aFormat) const
//
// Fill aString with current Date and Time according to given aFormat string
//
/**
Puts this TTime into a descriptor and formats it according to the format string 
specified in the second argument.

Many of the formatting commands use the 
system's locale settings for the date and time, for example the characters 
used to separate components of the date and time and the ordering of day, 
month and year. The list of formatting commands below is divided into two 
sections, the first of which lists the commands which operate without reference 
to the locale's date and time settings (see class TLocale) and the second 
table lists the commands which do use these settings.

The following formatting commands do not honour the locale-specific system 
settings:

\%\% : Include a single '%' character in the string

\%* : Abbreviate following item (the following item should not be preceded 
by a '%' character).

\%C : Interpret the argument as the six digit microsecond component of the 
time. In its abbreviated form, ('%*C') this should be followed by an integer 
between zero and six, where the integer indicates the number of digits to display.

\%D : Interpret the argument as the two digit day number in the month. Abbreviation 
suppresses leading zero.

\%E : Interpret the argument as the day name. Abbreviation is language-specific 
(e.g. English uses the first three letters).

\%F : Use this command for locale-independent ordering of date components. 
This orders the following day/month/year component(s) (\%D, \%M, \%Y for example) 
according to the order in which they are specified in the string. This removes 
the need to use \%1 to \%5 (described below).

\%H : Interpret the argument as the one or two digit hour component of the 
time in 24 hour time format. Abbreviation suppresses leading zero. For locale-dependent 
hour formatting, use \%J.

\%I : Interpret the argument as the one or two digit hour component of the 
time in 12 hour time format. The leading zero is automatically suppressed 
so that abbreviation has no effect. For locale-dependent hour formatting, 
use \%J.

\%M : Interpret the argument as the one or two digit month number. Abbreviation 
suppresses leading zero.

\%N : Interpret the argument as the month name. Abbreviation is language specific, e.g. 
English uses the first three letters only. When using locale-dependent formatting, 
(that is, \%F has not previously been specified), specifying \%N causes any 
subsequent occurrence of a month specifier in the string to insert the month 
as text rather than in numeric form. When using locale-independent formatting, 
specifying \%N causes the month to be inserted as text at that position, but 
any subsequent occurrence of \%M will cause the month to be inserted in numeric 
form.

\%S : Interpret the argument as the one or two digit seconds component of the 
time. Abbreviation suppresses leading zero.

\%T : Interpret the argument as the one or two digit minutes component of the 
time. Abbreviation suppresses leading zero.

\%W : Interpret the argument as the one or two digit week number in year. Abbreviation 
suppresses leading zero.

\%X : Interpret the argument as the date suffix. Cannot be abbreviated. When 
using locale-dependent formatting (that is, \%F has not previously been specified), 
\%X causes all further occurrences of the day number to be displayed with the 
date suffix. When using locale-independent formatting, a date suffix will 
be inserted only after the occurrence of the day number which \%X follows in 
the format string. Any further occurrence of \%D without a following \%X will 
insert the day number without a suffix.

\%Y : Interpret the argument as the four digit year number. Abbreviation suppresses 
the first two digits.

\%Z : Interpret the argument as the one, two or three digit day number in the 
year. Abbreviation suppresses leading zeros.

The following formatting commands do honour the locale-specific system settings:

\%. : Interpret the argument as the decimal separator character (as set by 
TLocale::SetDecimalSeparator()). The decimal separator is used to separate 
seconds and microseconds, if present.

\%: : Interpret the argument as one of the four time separator characters (as 
set by TLocale::SetTimeSeparator()). Must be followed by an integer between 
zero and three inclusive to indicate which time separator character is being 
referred to.

\%/ : Interpret the argument as one of the four date separator characters (as 
set by TLocale::SetDateSeparator()). Must be followed by an integer between 
zero and three inclusive to indicate which date separator character is being 
referred to.

\%1 : Interpret the argument as the first component of a three component date 
(i.e. day, month or year) where the order has been set by TLocale::SetDateFormat(). 
When the date format is EDateEuropean, this is the day, when EDateAmerican, 
the month, and when EDateJapanese, the year. For more information on this 
and the following four formatting commands, see the Notes section immediately 
below.

\%2 : Interpret the argument as the second component of a three component date 
where the order has been set by TLocale::SetDateFormat(). When the date format 
is EDateEuropean, this is the month, when EDateAmerican, the day and when 
EDateJapanese, the month.

\%3 : Interpret the argument as the third component of a three component date 
where the order has been set by TLocale::SetDateFormat(). When the date format 
is EDateEuropean, or EDateAmerican this is the year and when EDateJapanese, 
the day.

\%4 : Interpret the argument as the first component of a two component date 
(day and month) where the order has been set by TLocale::SetDateFormat(). 
When the date format is EDateEuropean this is the day, and when EDateAmerican 
or EDateJapanese, the month.

\%5 : Interpret the argument as the second component of a two component date 
(day and month) where the order has been set by TLocale::SetDateFormat(). 
When the date format is EDateEuropean this is the month, and when EDateAmerican 
or EDateJapanese, the day.

\%A : Interpret the argument as "am" or "pm" text according to the current 
language and time of day. Unlike the \%B formatting command (described below), 
\%A disregards the locale's 12 or 24 hour clock setting, so that when used 
without an inserted + or - sign, am/pm text will always be displayed. Whether 
a space is inserted between the am/pm text and the time depends on the locale-specific 
settings. However, if abbreviated (\%*A), no space is inserted, regardless 
of the locale's settings. The am/pm text appears before or after the time, 
according to the position of the \%A, regardless of the locale-specific settings. 
For example, the following ordering of formatting commands causes am/pm text 
to be printed after the time: \%H \%T \%S \%A. Optionally, a minus or plus sign 
may be inserted between the "%" and the "A". This operates as follows:

\%-A causes am/pm text to be inserted into the descriptor only if the am/pm 
symbol position has been set in the locale to ELocaleBefore. Cannot be abbreviated 
using asterisk.

\%+A causes am/pm text to be inserted into the descriptor only if the am/pm 
symbol position has been set in the locale to ELocaleAfter. Cannot be abbreviated 
using asterisk. For example, the following formatting commands will cause 
am/pm text to be displayed after the time if the am/pm position has been set 
in the locale to ELocaleAfter or before the time if ELocaleBefore: \%-A \%H 
\%T \%S \%+A.

\%B Interpret the argument as am or pm text according to the current language 
and time of day. Unlike the \%A command, when using \%B, am/pm text is displayed 
only if the clock setting in the locale is 12-hour. Whether a space is inserted 
between the am/pm text and the time depends on the locale-specific settings. 
However, if abbreviated (\%*B), no space is inserted, regardless of the locale's 
settings. The am/pm text appears before or after the time, according to the 
location of the "%B", regardless of the locale-specific settings. For example, 
the following formatting commands cause am/pm text to be printed after the 
time: \%H \%T \%S \%B. Optionally, a minus or plus sign may be inserted between 
the "%" and the "B". This operates as follows:

\%-B causes am/pm text to be inserted into the descriptor only if using a 12 
hour clock and the am/pm symbol position has been set in the locale to ELocaleBefore. 
Cannot be abbreviated using asterisk.

\%+B causes am/pm text to be inserted into the descriptor only if using a 12 
hour clock and the am/pm symbol position has been set in the locale to ELocaleAfter. 
Cannot be abbreviated using asterisk. For example, the following formatting 
commands cause am/pm text to be printed after the time if the am/pm position 
has been set in the locale to ELocaleAfter or before the time if ELocaleBefore: 
\%-B \%H \%T \%S \%+B.

\%J Interpret the argument as the hour component of the time in either 12 or 
24 hour clock format depending on the locale's clock format setting. When 
the clock format has been set to 12 hour, leading zeros are automatically 
suppressed so that abbreviation has no effect. Abbreviation suppresses leading 
zero only when using a 24 hour clock.

Notes:

The \%1, \%2, \%3, \%4 and \%5 formatting commands are used in conjunction with 
\%D, \%M and \%Y to format the date locale-dependently. When formatting the date 
locale-dependently, the order of the day, month and year components within 
the string is determined by the order of the \%1 to \%5 formatting commands, 
not that of \%D, \%M, \%Y.

When formatting the date locale-independently (that is, \%F has been specified 
in the format string), the \%1 to \%5 formatting commands are not required, 
and should be omitted. In this case, the order of the date components is determined 
by the order of the \%D, \%M, \%Y format commands within aFormat.

Up to four date separators and up to four time separators can be used to separate 
the components of a date or time. When formatting a numerical date consisting 
of the day, month and year or a time containing hours, minutes and seconds, 
all four separators should always be specified in the format command string. 
Usually, the leading and trailing separators should not be displayed. In this 
case, the first and fourth separators should still be specified, but should 
be represented by a null character.

The date format follows the pattern:

DateSeparator[0] DateComponent1 DateSeparator[1] DateComponent2 DateSeparator[2] 
DateComponent3 DateSeparator[3]

where the ordering of date components is determined by the locale's date format 
setting.

The time format follows the pattern:

TimeSeparator[0] Hours TimeSeparator[1] Minutes TimeSeparator[2] Seconds TimeSeparator[3]

If the time includes a microseconds component, the third separator should 
occur after the microseconds, and the seconds and microseconds should be separated 
by the decimal separator. When formatting a two component time, the following 
rules apply:

if the time consists of hours and minutes, the third time delimiter should 
be omitted 

if the time consists of minutes and seconds, the second time delimiter should 
be omitted

@param aDes    Descriptor, which,  on return contains the formatted date/time string.
@param aFormat Format string which determines the format of the date and time.

@leave KErrOverflow The date/time string is too long for the descriptor aDes.
@leave KErrGeneral  A formatting error has occurred.
*/
	{
	TLocale local;
	FormatL(aDes,aFormat,local);
	}

EXPORT_C void TTime::FormatL(TDes &aDes,const TDesC &aFormat,const TLocale &aLocale) const
//
// Fill aString with current Date and Time according to given aFormat string
//
/**
Puts this TTime into a descriptor and formats it according to the format string 
specified in the second argument.

Many of the formatting commands use the 
system's locale settings for the date and time, for example the characters 
used to separate components of the date and time and the ordering of day, 
month and year. The list of formatting commands below is divided into two 
sections, the first of which lists the commands which operate without reference 
to the locale's date and time settings (see class TLocale) and the second 
table lists the commands which do use these settings.

The following formatting commands do not honour the locale-specific system 
settings:

\%\% : Include a single '%' character in the string

\%* : Abbreviate following item (the following item should not be preceded 
by a '%' character).

\%C : Interpret the argument as the six digit microsecond component of the 
time. In its abbreviated form, ('%*C') this should be followed by an integer 
between zero and six, where the integer indicates the number of digits to display.

\%D : Interpret the argument as the two digit day number in the month. Abbreviation 
suppresses leading zero.

\%E : Interpret the argument as the day name. Abbreviation is language-specific 
(e.g. English uses the first three letters).

\%F : Use this command for locale-independent ordering of date components. 
This orders the following day/month/year component(s) (\%D, \%M, \%Y for example) 
according to the order in which they are specified in the string. This removes 
the need to use \%1 to \%5 (described below).

\%H : Interpret the argument as the one or two digit hour component of the 
time in 24 hour time format. Abbreviation suppresses leading zero. For locale-dependent 
hour formatting, use \%J.

\%I : Interpret the argument as the one or two digit hour component of the 
time in 12 hour time format. The leading zero is automatically suppressed 
so that abbreviation has no effect. For locale-dependent hour formatting, 
use \%J.

\%M : Interpret the argument as the one or two digit month number. Abbreviation 
suppresses leading zero.

\%N : Interpret the argument as the month name. Abbreviation is language specific, e.g. 
English uses the first three letters only. When using locale-dependent formatting, 
(that is, \%F has not previously been specified), specifying \%N causes any 
subsequent occurrence of a month specifier in the string to insert the month 
as text rather than in numeric form. When using locale-independent formatting, 
specifying \%N causes the month to be inserted as text at that position, but 
any subsequent occurrence of \%M will cause the month to be inserted in numeric 
form.

\%S : Interpret the argument as the one or two digit seconds component of the 
time. Abbreviation suppresses leading zero.

\%T : Interpret the argument as the one or two digit minutes component of the 
time. Abbreviation suppresses leading zero.

\%W : Interpret the argument as the one or two digit week number in year. Abbreviation 
suppresses leading zero.

\%X : Interpret the argument as the date suffix. Cannot be abbreviated. When 
using locale-dependent formatting (that is, \%F has not previously been specified), 
\%X causes all further occurrences of the day number to be displayed with the 
date suffix. When using locale-independent formatting, a date suffix will 
be inserted only after the occurrence of the day number which \%X follows in 
the format string. Any further occurrence of \%D without a following \%X will 
insert the day number without a suffix.

\%Y : Interpret the argument as the four digit year number. Abbreviation suppresses 
the first two digits.

\%Z : Interpret the argument as the one, two or three digit day number in the 
year. Abbreviation suppresses leading zeros.

The following formatting commands do honour the locale-specific system settings:

\%. : Interpret the argument as the decimal separator character (as set by 
TLocale::SetDecimalSeparator()). The decimal separator is used to separate 
seconds and microseconds, if present.

\%: : Interpret the argument as one of the four time separator characters (as 
set by TLocale::SetTimeSeparator()). Must be followed by an integer between 
zero and three inclusive to indicate which time separator character is being 
referred to.

\%/ : Interpret the argument as one of the four date separator characters (as 
set by TLocale::SetDateSeparator()). Must be followed by an integer between 
zero and three inclusive to indicate which date separator character is being 
referred to.

\%1 : Interpret the argument as the first component of a three component date 
(i.e. day, month or year) where the order has been set by TLocale::SetDateFormat(). 
When the date format is EDateEuropean, this is the day, when EDateAmerican, 
the month, and when EDateJapanese, the year. For more information on this 
and the following four formatting commands, see the Notes section immediately 
below.

\%2 : Interpret the argument as the second component of a three component date 
where the order has been set by TLocale::SetDateFormat(). When the date format 
is EDateEuropean, this is the month, when EDateAmerican, the day and when 
EDateJapanese, the month.

\%3 : Interpret the argument as the third component of a three component date 
where the order has been set by TLocale::SetDateFormat(). When the date format 
is EDateEuropean, or EDateAmerican this is the year and when EDateJapanese, 
the day.

\%4 : Interpret the argument as the first component of a two component date 
(day and month) where the order has been set by TLocale::SetDateFormat(). 
When the date format is EDateEuropean this is the day, and when EDateAmerican 
or EDateJapanese, the month.

\%5 : Interpret the argument as the second component of a two component date 
(day and month) where the order has been set by TLocale::SetDateFormat(). 
When the date format is EDateEuropean this is the month, and when EDateAmerican 
or EDateJapanese, the day.

\%A : Interpret the argument as "am" or "pm" text according to the current 
language and time of day. Unlike the \%B formatting command (described below), 
\%A disregards the locale's 12 or 24 hour clock setting, so that when used 
without an inserted + or - sign, am/pm text will always be displayed. Whether 
a space is inserted between the am/pm text and the time depends on the locale-specific 
settings. However, if abbreviated (\%*A), no space is inserted, regardless 
of the locale's settings. The am/pm text appears before or after the time, 
according to the position of the \%A, regardless of the locale-specific settings. 
For example, the following ordering of formatting commands causes am/pm text 
to be printed after the time: \%H \%T \%S \%A. Optionally, a minus or plus sign 
may be inserted between the "%" and the "A". This operates as follows:

\%-A causes am/pm text to be inserted into the descriptor only if the am/pm 
symbol position has been set in the locale to ELocaleBefore. Cannot be abbreviated 
using asterisk.

\%+A causes am/pm text to be inserted into the descriptor only if the am/pm 
symbol position has been set in the locale to ELocaleAfter. Cannot be abbreviated 
using asterisk. For example, the following formatting commands will cause 
am/pm text to be displayed after the time if the am/pm position has been set 
in the locale to ELocaleAfter or before the time if ELocaleBefore: \%-A \%H 
\%T \%S \%+A.

\%B Interpret the argument as am or pm text according to the current language 
and time of day. Unlike the \%A command, when using \%B, am/pm text is displayed 
only if the clock setting in the locale is 12-hour. Whether a space is inserted 
between the am/pm text and the time depends on the locale-specific settings. 
However, if abbreviated (\%*B), no space is inserted, regardless of the locale's 
settings. The am/pm text appears before or after the time, according to the 
location of the "%B", regardless of the locale-specific settings. For example, 
the following formatting commands cause am/pm text to be printed after the 
time: \%H \%T \%S \%B. Optionally, a minus or plus sign may be inserted between 
the "%" and the "B". This operates as follows:

\%-B causes am/pm text to be inserted into the descriptor only if using a 12 
hour clock and the am/pm symbol position has been set in the locale to ELocaleBefore. 
Cannot be abbreviated using asterisk.

\%+B causes am/pm text to be inserted into the descriptor only if using a 12 
hour clock and the am/pm symbol position has been set in the locale to ELocaleAfter. 
Cannot be abbreviated using asterisk. For example, the following formatting 
commands cause am/pm text to be printed after the time if the am/pm position 
has been set in the locale to ELocaleAfter or before the time if ELocaleBefore: 
\%-B \%H \%T \%S \%+B.

\%J Interpret the argument as the hour component of the time in either 12 or 
24 hour clock format depending on the locale's clock format setting. When 
the clock format has been set to 12 hour, leading zeros are automatically 
suppressed so that abbreviation has no effect. Abbreviation suppresses leading 
zero only when using a 24 hour clock.

Notes:

The \%1, \%2, \%3, \%4 and \%5 formatting commands are used in conjunction with 
\%D, \%M and \%Y to format the date locale-dependently. When formatting the date 
locale-dependently, the order of the day, month and year components within 
the string is determined by the order of the \%1 to \%5 formatting commands, 
not that of \%D, \%M, \%Y.

When formatting the date locale-independently (that is, \%F has been specified 
in the format string), the \%1 to \%5 formatting commands are not required, 
and should be omitted. In this case, the order of the date components is determined 
by the order of the \%D, \%M, \%Y format commands within aFormat.

Up to four date separators and up to four time separators can be used to separate 
the components of a date or time. When formatting a numerical date consisting 
of the day, month and year or a time containing hours, minutes and seconds, 
all four separators should always be specified in the format command string. 
Usually, the leading and trailing separators should not be displayed. In this 
case, the first and fourth separators should still be specified, but should 
be represented by a null character.

The date format follows the pattern:

DateSeparator[0] DateComponent1 DateSeparator[1] DateComponent2 DateSeparator[2] 
DateComponent3 DateSeparator[3]

where the ordering of date components is determined by the locale's date format 
setting.

The time format follows the pattern:

TimeSeparator[0] Hours TimeSeparator[1] Minutes TimeSeparator[2] Seconds TimeSeparator[3]

If the time includes a microseconds component, the third separator should 
occur after the microseconds, and the seconds and microseconds should be separated 
by the decimal separator. When formatting a two component time, the following 
rules apply:

if the time consists of hours and minutes, the third time delimiter should 
be omitted 

if the time consists of minutes and seconds, the second time delimiter should 
be omitted

@param aDes    Descriptor, which,  on return contains the formatted date/time string.
@param aFormat Format string which determines the format of the date and time.
@param aLocale Specific locale which formatting will be based on.

@leave KErrOverflow The date/time string is too long for the descriptor aDes.
@leave KErrGeneral  A formatting error has occurred.
*/
	{

	TDateTime dateTime=DateTime();
	aDes.Zero(); // ensure string is empty at start

 	TLex aFmt(aFormat);
	TBool fix=EFalse; // fixed date format
	TBool da=EFalse; // day unabreviated
	TBool ma=EFalse; // month unabreviated
	TBool ya=EFalse; // year unabreviated
	TBool suff=EFalse; // default no suffix
	TBool mnam=EFalse; // default month as a number
	TTimeOverflowLeave overflowLeave;

   	while (!aFmt.Eos())
		{
		TChar ch=aFmt.Get();
		TBool abb=EFalse;
		const TInt NoPosSpecified=-1;
		TInt pos=NoPosSpecified;
		if (ch=='%')
			ch=aFmt.Get();
		else // not formatting,just want to add some characters to string
			goto doAppend; 
		if (ch=='*') // => abbreviate next field
			{
			abb=ETrue;
			ch=aFmt.Get();
			}
		else if (ch=='+' || ch=='-') // => leading or following Am/Pm
			{
			pos= ((ch=='+') ? ELocaleAfter : ELocaleBefore);
			ch=aFmt.Get();
			if (ch!='A' && ch!='B')
				User::Leave(KErrGeneral);
			}
		switch (ch)
			{
		case ':': // local time separator
				{
				if (aDes.Length()==aDes.MaxLength())
					User::Leave(KErrOverflow);
				ch=aFmt.Get();//Which separator?
				if (ch<'0' || ch>='0'+KMaxTimeSeparators)
					User::Leave(KErrGeneral);
				ch-='0';
				TChar separator=aLocale.TimeSeparator(ch);
				if (separator!=0)
					aDes.Append(separator);
				}
			break;
		case '/': // local date separator
				{
				if (aDes.Length()==aDes.MaxLength())
					User::Leave(KErrOverflow);
				ch=aFmt.Get();//Which separator?
				if (ch<'0' || ch>='0'+KMaxDateSeparators)
					User::Leave(KErrGeneral);
				ch-='0';
				TChar separator=aLocale.DateSeparator(ch);
				if (separator!=0)
					aDes.Append(separator);
				}
			break;
		case '.': // local decimal separator
				{
				if (aDes.Length()==aDes.MaxLength())
					User::Leave(KErrOverflow);
				aDes.Append(aLocale.DecimalSeparator());
				}
			break;
		case '1': // 1st element of date,local order
			switch (aLocale.DateFormat())
				{
			case EDateAmerican:
				goto doMonth;
			case EDateJapanese:
				goto doYear;
			default: // European
				goto doDay;
				}
		case '2': // 2nd element of date,local order
			switch (aLocale.DateFormat())
				{
			case EDateAmerican:
				goto doDay;
			default: // European and Japanese have month second
				goto doMonth;
				}
		case '3': // 3rd element of date,local order
			switch (aLocale.DateFormat())
				{
			case EDateJapanese:
				goto doDay;
			default: // European and American have year last
				goto doYear;
				}
		case '4': // 1st element of date (no year),local order
			switch (aLocale.DateFormat())
				{
			case EDateEuropean:
				goto doDay;
			default:
				goto doMonth;
				}
		case '5': // 2nd element of date (no year),local order
			switch (aLocale.DateFormat())
				{
			case EDateEuropean:
				goto doMonth;
			default:
				goto doDay;
				}
		case 'A': // am/pm text
doAmPm:
            {
            if (pos==NoPosSpecified || pos==aLocale.AmPmSymbolPosition())
				{
				TBuf<KMaxAmPmName+1> format(_S("%S"));
				if (!abb && aLocale.AmPmSpaceBetween())
					{
					if (aLocale.AmPmSymbolPosition()==ELocaleBefore)
						format.Append(' ');
					else
						{
						if (aDes.Length()==aDes.MaxLength())
							User::Leave(KErrOverflow);
						aDes.Append(' ');
						}
					}
				TAmPmName amPm((dateTime.Hour()<12) ? EAm : EPm);
				aDes.AppendFormat(format,&overflowLeave,&amPm);
				}
			break;
            }
		case 'B': // am/pm text if local time format is 12 hour clock
			if (aLocale.TimeFormat()==ETime24)
				break;
			else
				goto doAmPm;
		case 'C':
			{
			TBuf<6> digits;
			digits.AppendFormat(_L("%06d"),dateTime.MicroSecond());
			TUint numChars=6;	// Default length
			if (abb)
				{
				ch=aFmt.Get();
				if (ch>='0' && ch<='6')
					{
					numChars=ch;
					numChars-='0';
					}
				}
			if (aDes.Length()>(TInt)(aDes.MaxLength()-numChars))
			    User::Leave(KErrOverflow);
			aDes.Append(digits.Left(numChars));
			}	
			break;
		case 'D': // day in date
			if (abb)
				da=ETrue;
			if (!fix)
				break;
			else
				{
doDay:
				aDes.AppendFormat((da||abb) ? _L("%d"):_L("%02d"),&overflowLeave,dateTime.Day()+1);
				if (suff)
doSuffix:
                    {
                    TDateSuffix day(dateTime.Day());
					aDes.AppendFormat(_L("%S"),&overflowLeave,&day);
                    }
				break;
				}
		case 'E': // Day name
            {
			TDay day=DayNoInWeek();
			if (abb)
				{
	            TDayNameAbb nameAbb(day);
				aDes.AppendFormat(_L("%S"),&overflowLeave,&nameAbb);
				}
			else
				{
	            TDayName name(day);
				aDes.AppendFormat(_L("%S"),&overflowLeave,&name);
				}
			break;
            }
		case 'F': // => user wants day,month,year order fixed
			fix=ETrue;
			break;
		case 'H': // hour in 24 hour time format
do24:
			aDes.AppendFormat((abb) ? _L("%d"):_L("%02d"),&overflowLeave,dateTime.Hour());
			break;
		case 'I': // hour in 12 hour time format
do12:
			{
			TInt hour=dateTime.Hour();
			if (hour==0)
				hour=12;
			else if (hour>12)
				hour-=12;
			aDes.AppendFormat(_L("%d"),&overflowLeave,hour);
			break;
			}
		case 'J': //default time format for hour
			if (aLocale.TimeFormat()==ETime12)
				goto do12;
			else
				goto do24;
		case 'M': // month as a number (default value)
			if (abb)
				ma=ETrue;
			if (fix)
				goto doMonth;
			break;
		case 'N': // month as a name
			mnam=ETrue;
			if (abb)
				ma=ETrue;
			if (!fix)
				break;
			else
				{
doMonth:
				if (mnam)
					{
					TMonth month=dateTime.Month();
					if (ma || abb)
						{
		                TMonthNameAbb nameAbb(month);
						aDes.AppendFormat(_L("%S"),&overflowLeave,&nameAbb);
						}
					else
						{
	                    TMonthName name(month);
						aDes.AppendFormat(_L("%S"),&overflowLeave,&name);
						}
					}
				else
					aDes.AppendFormat((ma||abb) ? _L("%d"):_L("%02d"),&overflowLeave,dateTime.Month()+1);
				break;
				}
		case 'S': // seconds
			aDes.AppendFormat((abb) ? _L("%d"):_L("%02d"),&overflowLeave,dateTime.Second());
			break;	
		case 'T': // minutes	
			aDes.AppendFormat((abb) ? _L("%d"):_L("%02d"),&overflowLeave,dateTime.Minute());
			break;
		case 'W': // week no in year
			aDes.AppendFormat((abb) ? _L("%d"):_L("%02d"),&overflowLeave,WeekNoInYear());
			break;
		case 'X': // => wants day suffix
			if (fix)
				goto doSuffix;
			else
				{
				suff=ETrue;
				break;
				}
		case 'Y': // year
			if (abb)
				ya=ETrue;
			if (!fix)
				break;
			else
				{
doYear:
				if (ya || abb)
					aDes.AppendFormat(_L("%02d"),&overflowLeave,((dateTime.Year())%100));
				else
					aDes.AppendFormat(_L("%04d"),&overflowLeave,dateTime.Year());
				break;
				}
		case 'Z': // day no in year
			aDes.AppendFormat((abb) ? _L("%d"):_L("%03d"),&overflowLeave,DayNoInYear());
			break;
		default:
doAppend:
			if (aDes.Length()==aDes.MaxLength())
				User::Leave(KErrOverflow);
			aDes.Append(ch);
			break;
			}
		}
	}




EXPORT_C TTime Time::NullTTime()
/**
Gets a TTime with a null value.

@return TTime object with a null value.
*/
	{
	return UI64LIT(0x8000000000000000);
	}

EXPORT_C TTime Time::MaxTTime()
/**
Gets the maximum time value which can be held in a TTime object.

@return The maximum TTime value.
*/
	{
	return I64LIT(0x7fffffffffffffff);
	}

EXPORT_C TTime Time::MinTTime()
/**
Gets the minimum time value which can be held in a TTime object.

@return The minimum TTime value.
*/
	{
	return UI64LIT(0x8000000000000001);
	}

EXPORT_C TInt Time::DaysInMonth(TInt aYear,TMonth aMonth)
/**
Gets the number of days in a month.

@param aYear  The year. Must be specified because of leap years.
@param aMonth Month, from EJanuary to EDecember.

@return The number of days in the month.
*/
	{

    __ASSERT_DEBUG(aMonth<=EDecember && aMonth>=EJanuary,::Panic(ETTimeValueOutOfRange));
    return(mTab[IsLeapYear(aYear)][aMonth]);
	}

EXPORT_C TBool Time::IsLeapYear(TInt aYear)
//
// up to and including 1600 leap years were every 4 years,since then leap years are every 4 years unless
// the year falls on a century which is not divisible by 4 (ie 1900 wasnt,2000 will be)
// for simplicity define year 0 as a leap year
//
/**
Tests whether a year is a leap year.

@param aYear The year of interest.

@return True if leap year, False if not.
*/
	{

	if (aYear>1600)
    	return(!(aYear%4) && (aYear%100 || !(aYear%400)));
	return(!(aYear%4));
	}

EXPORT_C TInt Time::LeapYearsUpTo(TInt aYear)
//
// from 0AD to present year according to the rule above
//
/**
Gets the number of leap years between 0 AD nominal Gregorian and the specified 
year - inclusive.

@param aYear The final year in the range to search. If negative, the function 
             will return a negative number of leap years.

@return The number of leap years between 0 AD nominal Gregorian and aYear.
*/
	{

	if (aYear<=0)
		return(aYear/4);
	if (aYear<=1600)
		return(1+((aYear-1)/4));
	TInt num=401; // 1600/4+1
	aYear-=1601;
	TInt century=aYear/100;
	num+=(aYear/4-century+century/4);
	return(num);
	}

