source: XMLIO_V2/external/src/POCO/Foundation/DateTimeParser.cpp @ 80

Last change on this file since 80 was 80, checked in by ymipsl, 14 years ago

ajout lib externe

  • Property svn:eol-style set to native
File size: 9.6 KB
Line 
1//
2// DateTimeParser.cpp
3//
4// $Id: //poco/1.3/Foundation/src/DateTimeParser.cpp#7 $
5//
6// Library: Foundation
7// Package: DateTime
8// Module:  DateTimeParser
9//
10// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// Permission is hereby granted, free of charge, to any person or organization
14// obtaining a copy of the software and accompanying documentation covered by
15// this license (the "Software") to use, reproduce, display, distribute,
16// execute, and transmit the Software, and to prepare derivative works of the
17// Software, and to permit third-parties to whom the Software is furnished to
18// do so, all subject to the following:
19//
20// The copyright notices in the Software and this entire statement, including
21// the above license grant, this restriction and the following disclaimer,
22// must be included in all copies of the Software, in whole or in part, and
23// all derivative works of the Software, unless such copies or derivative
24// works are solely in the form of machine-executable object code generated by
25// a source language processor.
26//
27// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
30// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
31// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
32// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33// DEALINGS IN THE SOFTWARE.
34//
35
36
37#include <Poco/DateTimeParser.h>
38#include <Poco/DateTimeFormat.h>
39#include <Poco/DateTime.h>
40#include <Poco/Exception.h>
41#include <cctype>
42
43
44namespace Poco {
45
46
47#define SKIP_JUNK() \
48        while (it != end && !std::isdigit(*it)) ++it
49
50
51#define PARSE_NUMBER(var) \
52        while (it != end && std::isdigit(*it)) var = var*10 + ((*it++) - '0')
53
54
55#define PARSE_NUMBER_N(var, n) \
56        { int i = 0; while (i++ < n && it != end && std::isdigit(*it)) var = var*10 + ((*it++) - '0'); }
57
58
59void DateTimeParser::parse(const std::string& fmt, const std::string& str, DateTime& dateTime, int& timeZoneDifferential)
60{
61        int year   = 0;
62        int month  = 0;
63        int day    = 0;
64        int hour   = 0;
65        int minute = 0;
66        int second = 0;
67        int millis = 0;
68        int micros = 0;
69        int tzd    = 0;
70
71        std::string::const_iterator it   = str.begin();
72        std::string::const_iterator end  = str.end();
73        std::string::const_iterator itf  = fmt.begin();
74        std::string::const_iterator endf = fmt.end();
75
76        while (itf != endf && it != end)
77        {
78                if (*itf == '%')
79                {
80                        if (++itf != endf)
81                        {
82                                switch (*itf)
83                                {
84                                case 'w':
85                                case 'W':
86                                        while (it != end && std::isspace(*it)) ++it;
87                                        while (it != end && std::isalpha(*it)) ++it;
88                                        break;
89                                case 'b':
90                                case 'B':
91                                        month = parseMonth(it, end);
92                                        break;
93                                case 'd':
94                                case 'e':
95                                case 'f':
96                                        SKIP_JUNK();
97                                        PARSE_NUMBER_N(day, 2);
98                                        break;
99                                case 'm':
100                                case 'n':
101                                case 'o':
102                                        SKIP_JUNK();
103                                        PARSE_NUMBER_N(month, 2);
104                                        break;                                   
105                                case 'y':
106                                        SKIP_JUNK();
107                                        PARSE_NUMBER_N(year, 2);
108                                        if (year >= 69) 
109                                                year += 1900;
110                                        else
111                                                year += 2000;
112                                        break;
113                                case 'Y':
114                                        SKIP_JUNK();
115                                        PARSE_NUMBER_N(year, 4);
116                                        break;
117                                case 'r':
118                                        SKIP_JUNK();
119                                        PARSE_NUMBER(year);
120                                        if (year < 1000)
121                                        {
122                                                if (year >= 69) 
123                                                        year += 1900;
124                                                else
125                                                        year += 2000;
126                                        }
127                                        break;
128                                case 'H':
129                                case 'h':
130                                        SKIP_JUNK();
131                                        PARSE_NUMBER_N(hour, 2);
132                                        break;
133                                case 'a':
134                                case 'A':
135                                        hour = parseAMPM(it, end, hour);
136                                        break;
137                                case 'M':
138                                        SKIP_JUNK();
139                                        PARSE_NUMBER_N(minute, 2);
140                                        break;
141                                case 'S':
142                                        SKIP_JUNK();
143                                        PARSE_NUMBER_N(second, 2);
144                                        break;
145                                case 'i':
146                                        SKIP_JUNK();
147                                        PARSE_NUMBER_N(millis, 3);
148                                        break;
149                                case 'c':
150                                        SKIP_JUNK();
151                                        PARSE_NUMBER_N(millis, 1);
152                                        millis *= 100;
153                                        break;
154                                case 'F':
155                                        SKIP_JUNK();
156                                        PARSE_NUMBER_N(millis, 3);
157                                        PARSE_NUMBER_N(micros, 3);
158                                        break;
159                                case 'z':
160                                case 'Z':
161                                        tzd = parseTZD(it, end);
162                                        break;
163                                }
164                                ++itf;
165                        }
166                }
167                else ++itf;
168        }
169        if (month == 0) month = 1;
170        if (day == 0) day = 1;
171        if (DateTime::isValid(year, month, day, hour, minute, second, millis, micros))
172                dateTime.assign(year, month, day, hour, minute, second, millis, micros);
173        else 
174                throw SyntaxException("date/time component out of range");
175        timeZoneDifferential = tzd;
176}
177
178
179DateTime DateTimeParser::parse(const std::string& fmt, const std::string& str, int& timeZoneDifferential)
180{
181        DateTime result;
182        parse(fmt, str, result, timeZoneDifferential);
183        return result;
184}
185
186       
187bool DateTimeParser::tryParse(const std::string& fmt, const std::string& str, DateTime& dateTime, int& timeZoneDifferential)
188{
189        try
190        {
191                parse(fmt, str, dateTime, timeZoneDifferential);
192        }
193        catch (Exception&)
194        {
195                return false;
196        }
197        return true;
198}
199
200
201void DateTimeParser::parse(const std::string& str, DateTime& dateTime, int& timeZoneDifferential)
202{
203        if (!tryParse(str, dateTime, timeZoneDifferential))
204                throw SyntaxException("Unsupported or invalid date/time format");
205}
206
207       
208DateTime DateTimeParser::parse(const std::string& str, int& timeZoneDifferential)
209{
210        DateTime result;
211        if (tryParse(str, result, timeZoneDifferential))
212                return result;
213        else
214                throw SyntaxException("Unsupported or invalid date/time format");
215}
216
217       
218bool DateTimeParser::tryParse(const std::string& str, DateTime& dateTime, int& timeZoneDifferential)
219{
220        if (str.length() < 4) return false;
221       
222        if (str[3] == ',')
223                return tryParse("%w, %e %b %r %H:%M:%S %Z", str, dateTime, timeZoneDifferential);
224        else if (str[3] == ' ')
225                return tryParse(DateTimeFormat::ASCTIME_FORMAT, str, dateTime, timeZoneDifferential);
226        else if (str.find(',') != std::string::npos)
227                return tryParse("%W, %e %b %r %H:%M:%S %Z", str, dateTime, timeZoneDifferential);
228        else if (std::isdigit(str[0]))
229        {
230                if (str.find(' ') != std::string::npos || str.length() == 10)
231                        return tryParse(DateTimeFormat::SORTABLE_FORMAT, str, dateTime, timeZoneDifferential);
232                else
233                        return tryParse(DateTimeFormat::ISO8601_FORMAT, str, dateTime, timeZoneDifferential);
234        }
235        else return false;
236}
237
238
239int DateTimeParser::parseTZD(std::string::const_iterator& it, const std::string::const_iterator& end)
240{
241        struct Zone
242        {
243                const char* designator;
244                int         timeZoneDifferential;
245        };
246
247        static Zone zones[] =
248        {
249                {"Z",           0},
250                {"UT",          0},
251                {"GMT",         0},
252                {"BST",    1*3600},
253                {"IST",    1*3600},
254                {"WET",         0},
255                {"WEST",   1*3600},
256                {"CET",    1*3600},
257                {"CEST",   2*3600},
258                {"EET",    2*3600},
259                {"EEST",   3*3600},
260                {"MSK",    3*3600},
261                {"MSD",    4*3600},
262                {"NST",   -3*3600-1800},
263                {"NDT",   -2*3600-1800},
264                {"AST",   -4*3600},
265                {"ADT",   -3*3600},
266                {"EST",   -5*3600},
267                {"EDT",   -4*3600},
268                {"CST",   -6*3600},
269                {"CDT",   -5*3600},
270                {"MST",   -7*3600},
271                {"MDT",   -6*3600},
272                {"PST",   -8*3600},
273                {"PDT",   -7*3600},
274                {"AKST",  -9*3600},
275                {"AKDT",  -8*3600},
276                {"HST",  -10*3600},
277                {"AEST",  10*3600},
278                {"AEDT",  11*3600},
279                {"ACST",   9*3600+1800},
280                {"ACDT",  10*3600+1800},
281                {"AWST",   8*3600},
282                {"AWDT",   9*3600}
283        };
284
285        while (it != end && std::isspace(*it)) ++it;
286        if (it != end)
287        {
288                if (std::isalpha(*it))
289                {
290                        std::string designator;
291                        designator += *it++;
292                        if (it != end && std::isalpha(*it)) designator += *it++;
293                        if (it != end && std::isalpha(*it)) designator += *it++;
294                        if (it != end && std::isalpha(*it)) designator += *it++;
295                        for (unsigned i = 0; i < sizeof(zones)/sizeof(Zone); ++i)
296                        {
297                                if (designator == zones[i].designator)
298                                        return zones[i].timeZoneDifferential;
299                        }
300                }
301                else if (*it == '+' || *it == '-')
302                {
303                        int sign = *it == '+' ? 1 : -1;
304                        ++it;
305                        int hours = 0;
306                        PARSE_NUMBER_N(hours, 2);
307                        if (it != end && *it == ':') ++it;
308                        int minutes = 0;
309                        PARSE_NUMBER_N(minutes, 2);
310                        return sign*(hours*3600 + minutes*60);
311                }
312        }
313        return 0;
314}
315
316
317int DateTimeParser::parseMonth(std::string::const_iterator& it, const std::string::const_iterator& end)
318{
319        std::string month;
320        while ((it != end && std::isspace(*it)) || std::ispunct(*it)) ++it;
321        bool isFirst = true;
322        while (it != end && std::isalpha(*it)) 
323        {
324                char ch = (*it++);
325                if (isFirst) { month += std::toupper(ch); isFirst = false; }
326                else month += std::tolower(ch);
327        }
328        if (month.length() < 3) throw SyntaxException("Month name must be at least three characters long", month);
329        for (int i = 0; i < 12; ++i) 
330        {
331                if (DateTimeFormat::MONTH_NAMES[i].find(month) == 0)
332                        return i + 1;
333        }
334        throw SyntaxException("Not a valid month name", month);
335}
336
337
338int DateTimeParser::parseDayOfWeek(std::string::const_iterator& it, const std::string::const_iterator& end)
339{
340        std::string dow;
341        while ((it != end && std::isspace(*it)) || std::ispunct(*it)) ++it;
342        bool isFirst = true;
343        while (it != end && std::isalpha(*it)) 
344        {
345                char ch = (*it++);
346                if (isFirst) { dow += std::toupper(ch); isFirst = false; }
347                else dow += std::tolower(ch);
348        }
349        if (dow.length() < 3) throw SyntaxException("Weekday name must be at least three characters long", dow);
350        for (int i = 0; i < 7; ++i) 
351        {
352                if (DateTimeFormat::WEEKDAY_NAMES[i].find(dow) == 0)
353                        return i;
354        }
355        throw SyntaxException("Not a valid weekday name", dow);
356}
357
358
359int DateTimeParser::parseAMPM(std::string::const_iterator& it, const std::string::const_iterator& end, int hour)
360{
361        std::string ampm;
362        while ((it != end && std::isspace(*it)) || std::ispunct(*it)) ++it;
363        while (it != end && std::isalpha(*it)) 
364        {
365                char ch = (*it++);
366                ampm += std::toupper(ch);
367        }
368        if (ampm == "AM")
369        {
370                if (hour == 12)
371                        return 0;
372                else
373                        return hour;
374        }
375        else if (ampm == "PM")
376        {
377                if (hour < 12)
378                        return hour + 12;
379                else
380                        return hour;
381        }
382        else throw SyntaxException("Not a valid AM/PM designator", ampm);
383}
384
385
386} // namespace Poco
Note: See TracBrowser for help on using the repository browser.