First public contribution.
1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // This file contains the implementation of internal classes used to parse TInternetDate data
19 @file tinternetdateparser.cpp
20 @see tinternetdateparser.h
23 #include "tinternetdateparser.h"
24 #include "inetprottextutils.h"
29 const TInt KRfc1123DateTimeLength = 29; // Sun, 06 Nov 1994 08:49:37 GMT
30 const TInt KHHMMSSFormatLength=8; // HH:MM:SS
32 // Long form day names, 'weekday' in RFC850
34 static const TText8* const KInternetWeekDays[] =
45 // Month names, 'month' in RFC1123 & RFC850
47 static const TText8* const KInternetMonths[] =
64 Converts from TDateTime to Internet RFC1123 Style date strings
67 @param aDateTime The date/time to be parsed
69 @return HBufC8* aDescriptor containing a RFC1123 style date.
71 HBufC8* TInternetDateParser::ConvertToRfc1123FormL(const TDateTime& aDateTime)
73 const TChar KSpace = ' ';
75 HBufC8* dateTime = HBufC8::NewLC(KRfc1123DateTimeLength);
76 TPtr8 dateTimePtr = dateTime->Des();
78 TTime time(aDateTime);
79 TInt wkDay = time.DayNoInWeek();
80 TPtrC8 wkDayText(KInternetWeekDays[wkDay]);
81 dateTimePtr.Append(wkDayText.Left(3));
84 // Append the day number
85 _LIT8(KDayNumberFormat, ", %02d");
86 TInt dayNumber = aDateTime.Day() + 1;
87 dateTimePtr.AppendFormat(KDayNumberFormat, dayNumber);
90 dateTimePtr.Append(KSpace);
91 TInt month = aDateTime.Month();
92 dateTimePtr.Append(TPtrC8(KInternetMonths[month]));
95 _LIT8(KYearDigitFormat, " %4d");
96 TInt year = aDateTime.Year();
97 dateTimePtr.AppendFormat(KYearDigitFormat, year);
99 // Append Time HH:MM:SS
101 dateTimePtr.Append(KSpace);
102 _LIT8(KHHMMSSFormat, "%02d:%02d:%02d GMT");
103 dateTimePtr.AppendFormat(KHHMMSSFormat, aDateTime.Hour(),aDateTime.Minute(),aDateTime.Second());
105 CleanupStack::Pop(dateTime);
111 Used to parse internet text date/time into a TDateTime
114 @param aInternetTextDateTime The date/time in a text format
115 @param aDateTime The result of parsing is placed here
116 @leave KErrNoMemory, KErrCorrupt If the format of the descriptor is not valid
118 void TInternetDateParser::ConvertFromInternetFormL(const TDesC8& aInternetTextDateTime, TDateTime& aDateTime)
120 const TChar KComma = ',';
121 TInt colonLoc = aInternetTextDateTime.Locate(KComma);
124 case -1: // ANSI C asctime() format: Sun Nov 6 08:49:37 1994
125 ConvertFromAscTimeFormL(aInternetTextDateTime, aDateTime);
127 case 3: // RFC 1123 Style Date: Sun, 06 Nov 1994 08:49:37 GMT
128 case 6: // RFC 850 Style Date: Sunday, 06-Nov-94 08:49:37 GMT
133 TPtrC8 dateTime(aInternetTextDateTime.Right(aInternetTextDateTime.Length() -(colonLoc+1))); // Remove "<day>,"
134 ConvertFromRfc1123And850FormL(dateTime, aDateTime);
138 User::Leave(KErrCorrupt);
144 @param aDateTime The result of parsing is placed here
146 void TInternetDateParser::ConvertFromRfc1123And850FormL(const TDesC8& aRfcDateTime, TDateTime& aDateTime)
148 TPtrC8 dateTime(aRfcDateTime);
149 InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveBoth);
150 TInt textLeft = ParseRfcDateDayMonthYearL(dateTime, aDateTime);
152 User::Leave(KErrCorrupt);
153 dateTime.Set(dateTime.Right(textLeft));
154 InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
155 ParseHHMMSSTimeL(dateTime, aDateTime);
156 textLeft= dateTime.Length() - KHHMMSSFormatLength;
157 if (textLeft > 1) // Must still have leading space
159 dateTime.Set(dateTime.Right(textLeft));
160 InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
161 TTimeIntervalMinutes timeOffset = 0;
162 ParseTimeOffsetL(dateTime, timeOffset);
164 if (timeOffset.Int() > 0 || timeOffset.Int() < 0)
166 TTime time(aDateTime);
168 aDateTime = time.DateTime();
172 User::Leave(KErrCorrupt); // Must include a timezone or timeoffset
177 @param aOffsetMinutes
179 void TInternetDateParser::ParseHHMMTimeOffsetL(const TDesC8& aTimeOffset, TTimeIntervalMinutes& aOffsetMinutes)
181 TInt offsetTextLength=aTimeOffset.Length();
182 if (offsetTextLength != 5) // +0000 or -0000
183 User::Leave(KErrCorrupt);
185 TPtrC8 timeOffset(aTimeOffset.Right(offsetTextLength-1));
188 if (InetProtTextUtils::ConvertDescriptorToInt(timeOffset, num) !=4)
189 User::Leave(KErrCorrupt); // not 0000
191 TInt minutes = num % 100;
192 TInt hours = num / 100;
193 TInt offsetMinutes=0;
194 if (minutes < 60 && hours < 24)
195 offsetMinutes = minutes + (hours * 60);
197 if (aTimeOffset[0] == '-')
200 aOffsetMinutes = offsetMinutes;
205 @param aOffsetMinutes
207 void TInternetDateParser::ParseTimeOffsetL(const TDesC8& aTimeOffset, TTimeIntervalMinutes& aOffsetMinutes)
209 TInt offsetMinutes=0;
210 TInt offsetTextLength = aTimeOffset.Length();
211 if (offsetTextLength > 1)
213 // check second letter to see if UT, GMT
214 // and to differentiate between Standard and Daylight Savings
215 switch (aTimeOffset[1])
222 case 'S': // Standard Time (Daylight Savings Time is one hour ahead);
225 case 'D' : // Daylight Savings Time
228 // Must be either corrupt or an explicit HHMM +/- offset
229 ParseHHMMTimeOffsetL(aTimeOffset, aOffsetMinutes);
233 // Check first letter to find out if its Eastern, Central, Mountain or Pacific Time
234 switch (aTimeOffset[0])
236 case 'E' : // EST or EDT -4
239 case 'C' : // CST or CDT -5
242 case 'M' : // MST or MDT -6
243 offsetMinutes -= 360;
245 case 'P' : // PST or PDT -7
249 // either the format is invalid or it is a non standard 3 letter timezone
254 else // This must be a military single letter format time zone
255 // According to RFC2882 These Military Timezones are obsolete. Also since A can be either +1 or -1 depending on the specification
256 // it should be ignored unless there is additional Out of band Information
258 return; // Do nothing
261 aOffsetMinutes = offsetMinutes;
268 void TInternetDateParser::ParseHHMMSSTimeL(const TDesC8& aDateTimeText, TDateTime& aDateTime)
270 if (aDateTimeText.Length() < KHHMMSSFormatLength) // Must be at least HH:MM:SS
271 User::Leave(KErrCorrupt);
273 TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(aDateTimeText, num);
274 if (consumed != 2 || num < 0 || num > 23)
275 User::Leave(KErrCorrupt);
276 TPtrC8 dateTime(aDateTimeText.Right(aDateTimeText.Length() -3)); // Remove HH:
277 aDateTime.SetHour(num);
279 consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, num);
280 if (consumed != 2 || num < 0 || num > 59)
281 User::Leave(KErrCorrupt);
282 dateTime.Set(dateTime.Right(dateTime.Length() -3)); // Remove MM:
283 aDateTime.SetMinute(num);
285 consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, num);
286 if (consumed != 2 || num < 0 || num > 59)
287 User::Leave(KErrCorrupt);
288 aDateTime.SetSecond(num);
296 TInt TInternetDateParser::ParseRfcDateDayMonthYearL(const TDesC8& aDateTimeText, TDateTime& aDateTime)
298 // Parse RFC 1123 and RFC 850 style date month year parts
299 // 06 Nov 1994 (RFC 1123)
300 // 06-Nov-94 (RFC 850) In this case if YY < 50 then treat as 20YY otherwise 19YY
302 TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(aDateTimeText,day);
303 if ((consumed !=1 && consumed != 2) || aDateTimeText.Length() <= 2)
304 User::Leave(KErrCorrupt);
306 --day; // Symbian OS month days start from 0
308 // Skip over DD and separator
309 TPtrC8 dateTimeText(aDateTimeText.Right(aDateTimeText.Length()-(consumed+1)));
310 TMonth month = GetMonthL(dateTimeText);
311 // Skip over MMM and separator
312 const TInt KConsumedMonthLength = 4;
313 TInt rightLength = dateTimeText.Length() - KConsumedMonthLength ;
316 User::Leave(KErrCorrupt);
318 dateTimeText.Set(dateTimeText.Right(rightLength));
322 consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTimeText, year);
323 if (consumed != 4 && consumed !=2)
324 User::Leave(KErrCorrupt);
326 // check for YY and adjust
328 year += year > 50 ? 1900 : 2000;
330 if (aDateTime.Set(year, month, day, 0, 0, 0, 0) != KErrNone)
331 User::Leave(KErrCorrupt);
333 return dateTimeText.Length() - (consumed +1);
340 TMonth TInternetDateParser::GetMonthL(const TDesC8& aMonthText)
342 if (aMonthText.Length() < 3)
343 User::Leave(KErrCorrupt);
345 switch (aMonthText[0])
347 case 'J': // Jan, Jun, Jul
348 return (aMonthText[1] == 'a' ? EJanuary : aMonthText[2] == 'n' ? EJune : EJuly);
351 case 'M': // Mar, May
352 return (aMonthText[2] == 'r' ? EMarch : EMay);
353 case 'A': // Apr, Aug
354 return (aMonthText[1] == 'p' ? EApril : EAugust);
364 User::Leave(KErrCorrupt);
371 @param aAscTimeDateTime
374 void TInternetDateParser::ConvertFromAscTimeFormL(const TDesC8& aAscTimeDateTime, TDateTime& aDateTime)
376 // Convert a date in ascTime format ( Sun Nov 6 08:49:37 1994 )
378 const TChar KSpace = ' ';
380 // First remove the wkDay
381 TPtrC8 dateTime(aAscTimeDateTime);
382 InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveBoth);
383 TInt endOfWkDayLoc = dateTime.Locate(KSpace);
384 if (endOfWkDayLoc != 3) // Must be following a wkDay "Sun "
385 User::Leave(KErrCorrupt);
386 dateTime.Set(dateTime.Right(dateTime.Length() - 3));
387 InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
388 // Now parse the month then skip over MMM
389 TMonth month = GetMonthL(dateTime);
390 dateTime.Set(dateTime.Right(dateTime.Length() - 3));
391 InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
392 // Now parse the monthDay
394 TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, day);
396 User::Leave(KErrCorrupt);
398 dateTime.Set(dateTime.Right(dateTime.Length() - consumed));
399 InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
402 ParseHHMMSSTimeL(dateTime, aDateTime);
403 dateTime.Set(dateTime.Right(dateTime.Length() - KHHMMSSFormatLength));
405 InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
407 consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, year);
409 User::Leave(KErrCorrupt);
411 if (aDateTime.Set(year, month, day-1, aDateTime.Hour(), aDateTime.Minute(), aDateTime.Second(), 0) != KErrNone)
412 User::Leave(KErrCorrupt);