LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
NormalizeDateTime.cpp
Go to the documentation of this file.
1// Copyright 2002-2019 CEA LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
6/************************************************************************
7 *
8 * @file NormalizeDateTime.cpp
9 * @author Besancon Romaric (romaric.besancon@cea.fr)
10 * @date Tue Jun 13 2006
11 * copyright Copyright (C) 2006-2019 by CEA LIST
12 *
13 ***********************************************************************/
14
15#include "NormalizeDateTime.h"
16#include "NormalizationUtils.h"
23
24#include <QtCore/QDate>
25
26#include <limits>
27#ifdef WIN32
28#undef min
29#undef max
30#endif
31
32using namespace Lima::Common::MediaticData;
35
36// using namespace boost;
37// using namespace boost::local_time;
38// using namespace boost::posix_time;
39
40
41using namespace std;
42
43namespace Lima {
44namespace LinguisticProcessing {
45namespace SpecificEntities {
46
47#define DATESTRING_FEATURE_NAME "date_string" // date as a string
48#define DATE_FEATURE_NAME "date" // date as a QDate
49#define DATE_BEGIN_FEATURE_NAME "date_begin"
50#define DATE_END_FEATURE_NAME "date_end"
51#define DATE_SPAN_FEATURE_NAME "date_span"
52#define DAY_FEATURE_NAME "day"
53#define DAYEND_FEATURE_NAME "dayend"
54#define MONTH_FEATURE_NAME "month"
55#define MONTHEND_FEATURE_NAME "monthend"
56#define YEAR_FEATURE_NAME "year"
57#define NUMDAY_FEATURE_NAME "numday"
58#define NUMDAYEND_FEATURE_NAME "numdayend"
59#define NUMMONTH_FEATURE_NAME "nummonth"
60#define NUMMONTHEND_FEATURE_NAME "nummonthend"
61#define NUMDAYMONTH_FEATURE_NAME "numdaymonth" // when 10/04 is a single token as fraction
62#define NUMYEAR_FEATURE_NAME "numyear"
63#define NUMYEAREND_FEATURE_NAME "numyearend"
64
65#define LOCALTIME_FEATURE_NAME "local_time"
66#define UTCTIME_FEATURE_NAME "utc_time"
67#define TIMESTRING_FEATURE_NAME "time_string"
68
69//**********************************************************************
70// factories for actions defined in this file
73
76
79
82
83
85m_dateRefName("document"),
86m_timeRefName("document"),
87m_locRefName("document")
88{}
89
91
93{
94 if (! complement.isEmpty()) {
95 //uint64_t i(0),prev(0); portage 32 64
96 int i(0),prev(0);
97 do {
98 i=complement.indexOf(LimaChar(','),prev);
99 parseReference(complement.mid(prev,i-prev));
100 prev=i+1;
101 } while (i!=-1);
102 }
103}
104
106{
107 static const LimaString datePrefix=Common::Misc::utf8stdstring2limastring("date_");
108 static const LimaString locPrefix=Common::Misc::utf8stdstring2limastring("loc_");
109 static const LimaString timePrefix=Common::Misc::utf8stdstring2limastring("time_");
110
111 if (str.indexOf(datePrefix)==0) {
112 m_dateRefName=Common::Misc::limastring2utf8stdstring(str.mid(5));
113 }
114 else if (str.indexOf(locPrefix)==0) {
115 m_locRefName=Common::Misc::limastring2utf8stdstring(str.mid(4));
116 }
117 else if (str.indexOf(timePrefix)==0) {
118 m_timeRefName=Common::Misc::limastring2utf8stdstring(str.mid(5));
119 }
120}
121
123getReferenceDate(const AnalysisContent& analysis,
124 QDate& date) const
125{
126 // get posix time from current text metadata
127 auto data = analysis.getData("LinguisticMetaData");
128 if (data == 0) {
129 SELOGINIT;
130 LERROR << "missing data 'LinguisticMetaData'";
131 return false;
132 }
133 auto metadata = std::dynamic_pointer_cast<const LinguisticMetaData>(data);
134
135 date=metadata->getDate(m_dateRefName);
136#ifdef DEBUG_LP
137 SELOGINIT;
138 LDEBUG << "m_dateRefName =" << m_dateRefName <<" , date = " << date.toString();
139#endif
140 if (!date.isValid()) {
141 //try backoff on document date
142 SELOGINIT;
143 LWARN << "no reference date '"<< m_dateRefName << "'";
144
145 date=metadata->getDate("document");
146 if (!date.isValid()) {
147 SELOGINIT;
148 LWARN << "no reference date 'document'";
149 return false;
150 }
151 return true;
152 }
153 return true;
154}
155
157getReferenceTime(const AnalysisContent& analysis,
158 QTime& time) const
159{
160 // get posix time from current text metadata
161 auto data = analysis.getData("LinguisticMetaData");
162 if (data == 0) {
163 SELOGINIT;
164 LERROR << "missing data 'LinguisticMetaData'";
165 return false;
166 }
167 auto metadata = std::dynamic_pointer_cast<const LinguisticMetaData>(data);
168
169 time=metadata->getTime(m_timeRefName);
170 return (time.isValid());
171}
172
175 std::string& location) const
176{
177 // get posix time from current text metadata
178 auto data = analysis.getData("LinguisticMetaData");
179 if (data == 0) {
180 SELOGINIT;
181 LERROR << "missing data 'LinguisticMetaData'";
182 return false;
183 }
184 auto metadata = std::dynamic_pointer_cast<const LinguisticMetaData>(data);
185
186 location=metadata->getLocation(m_locRefName);
187 return (! location.empty());
188}
189
190//**********************************************************************
192{
193 // change features so that the DEFAULT_ATTRIBUTE contains the true normalization
194 //
195 if (m.features().find(DATE_FEATURE_NAME) != m.features().end()) {
197 m.features().setFeature(DEFAULT_ATTRIBUTE,m.features().find(DATE_FEATURE_NAME)->getValueLimaString());
198 }
199 // set value only for exact dates: otherwise, the default normalization of years (2014 -> [2014-01-01,2014-12-31])
200 // is a bit too much
201// else if (m.features().find(DATE_BEGIN_FEATURE_NAME) != m.features().end()) {
202// m.features().setFeature(DATESTRING_FEATURE_NAME,m.features().find(DEFAULT_ATTRIBUTE)->getValueLimaString());
203// LimaString norm="["
204// +m.features().find(DATE_BEGIN_FEATURE_NAME)->getValueLimaString()+","
205// +m.features().find(DATE_END_FEATURE_NAME)->getValueLimaString()+"]";
206// m.features().setFeature(DEFAULT_ATTRIBUTE,norm);
207// }
208}
209
210
211//**********************************************************************
213NormalizeDate(MediaId language,
214 const LimaString& complement):
215Automaton::ConstraintFunction(language,complement),
216m_language(language),
217m_resources(0),
218m_referenceData(),
219m_microsForMonth(0),
220m_microsForDays(0),
221m_microAccessor(0),
222m_isInterval(false)
223{
225
226 m_microAccessor=&(static_cast<const Common::MediaticData::LanguageData&>(Common::MediaticData::MediaticData::single().mediaData(language)).getPropertyCodeManager().getPropertyAccessor("MICRO"));
227
228 if (language != UNDEFLANG) {
229 try {
230 auto res = LinguisticResources::single().getResource(language,"microsForDateTimeNormalization");
231 auto micros = std::dynamic_pointer_cast<MicrosForNormalization>(res);
232 m_microsForMonth=micros->getMicros("MonthMicros");
233 m_microsForDays=micros->getMicros("DayMicros");
234 }
235 catch (std::exception& e) {
236 SELOGINIT;
237 LWARN << "Exception caught: " << e.what();
238 LWARN << "-> micros for person name normalization are not initialized";
239 }
240 }
241
242 try {
243 auto res = LinguisticResources::changeable().getResource(language,"DateTimeNormalization");
244 if (res==0) {
245 SELOGINIT;
246 LWARN << "no resource 'DateTimeNormalization'";
247 }
248 else {
249 m_resources = std::dynamic_pointer_cast<NormalizeDateTimeResources>(res);
250 }
251 }
252 catch (std::exception& e) {
253 // resources are not loaded when compiling the rules
254 SELOGINIT;
255 LWARN << "Exception caught: " << e.what();
256 }
257
258 static const LimaString intervalString=Common::Misc::utf8stdstring2limastring("isInterval");
259 if (complement.indexOf(intervalString)!=-1) {
260 m_isInterval=true;
261 }
262}
263
266 const QDate& currentDate) const
267{
268 // get metadata to update
269 auto data = analysis.getData("LinguisticMetaData");
270 if (data == 0) {
271 SELOGINIT;
272 LERROR << "missing data 'LinguisticMetaData'";
273 return;
274 }
275 auto metadata = std::dynamic_pointer_cast<LinguisticMetaData>(data);
276
277 metadata->setDate("current", currentDate);
278}
279
280unsigned short NormalizeDate::getDayFromString(const LimaString& numdayString) const
281{
282#ifdef DEBUG_LP
283 SELOGINIT;
284#endif
285 // try to extract number as int from string <number><ordinalSuffix> like 4th, 22nd, 1st or <number> like 17
286 unsigned short day = m_resources->getValueFromNumberOrdinal(numdayString);
287#ifdef DEBUG_LP
288 LDEBUG << "NormalizeDate::getDayFromString: testConversion 1 of " << numdayString << "1 day=" << day;
289#endif
290 // try first conversion of type "premier" -> 1
291 // then try conversion of type "10th" -> 10
293 day = m_resources->getValueFromWordCardinalOrOrdinal(numdayString);
294#ifdef DEBUG_LP
295 LDEBUG << "NormalizeDate::getDayFromString: testConversion 2 of " << numdayString << "1 day=" << day;
296#endif
297 }
298 // then try conversion of type "10" -> 10
300 bool ok;
301 day = numdayString.toUShort(&ok);
302#ifdef DEBUG_LP
303 LDEBUG << "NormalizeDate::getDayFromString: testConversion 3 of " << numdayString << "1 day=" << day;
304#endif
305 if( !ok )
307 }
308 return day;
309}
310
312 const std::string& featureName) const
313{
314 // returns the day of month if found in the featureName (numeric value contained in the feature)
315 // otherwise, returns the day of week in the alternative (name of day)
316 unsigned short day(0);
317 if (m.features().find(featureName) != m.features().end())
318 {
319 LimaString numdayString = (*m.features().find(featureName)).getValueLimaString();
320 day = getDayFromString(numdayString);
321 }
322 if (day>31) {
323 SELOGINIT;
324 LWARN << "Error in date normalization: wrong value for day (" << day << ")";
325 day=0;
326 }
327 return day;
328}
329
331 const std::string& featureName) const
332{
333 unsigned short day(0);
334 if (m.features().find(featureName) != m.features().end() && m_resources != 0) {
335 day=m_resources->getDayNumber((*m.features().find(featureName)).getValueLimaString());
336 }
337 return day;
338}
339
341 const std::string& featureName,
342 const std::string& alternative) const
343{
344 unsigned short month(0);
345 if (m.features().find(featureName) != m.features().end())
346 {
347 bool ok = true;
348 month = (*m.features().find(featureName)).getValueLimaString().toUShort(&ok);
349 }
350 else if ((alternative != "") &&
351 (m.features().find(alternative) != m.features().end()
352 && m_resources))
353 {
354 month = m_resources->getMonthNumber((*m.features().find(alternative)).getValueLimaString());
355 }
356 return month;
357}
358
360 const std::string& featureName) const
361{
362 unsigned short year(0);
363 if (m.features().find(featureName) != m.features().end()) {
364 year = (*m.features().find(featureName)).getValueLimaString().toUShort();
365 // ad hoc correction for two-digit years
366 if (year!=0 && year<99)
367 {
368 // consider that we refer to the current century up to 10 years in the future
369 // otherwise we refer to the past century (completely arbitrary rule)
370 unsigned short currentYear=QDate::currentDate().year();
371 // century (should be 2000)
372 unsigned short century=int(float(currentYear)/100)*100;
373 if (century+year<=currentYear+10) {
374 year=century+year;
375 }
376 else {
377 year=(century-100)+year;
378 }
379 }
380 }
381 return year;
382}
383
384QString NormalizeDate::getDateSpan(unsigned short year, unsigned short month, unsigned short day) const
385{
386 QString dateSpan = "XXXX";
387 if( year != 0 )
388 dateSpan = QString::number(year);
389 dateSpan.append("-");
390 if( month == 0 )
391 {
392 dateSpan.append("XX-XX");
393 }
394 else
395 {
396 QString monthString = QString(QLatin1String("%1")).arg(month, 2, 10, QLatin1Char('0'));
397 dateSpan.append(monthString);
398 dateSpan.append("-");
399 if( day == 0 )
400 {
401 dateSpan.append("XX");
402 }
403 else
404 {
405 QString dayString = QString(QLatin1String("%1")).arg(day, 2, 10, QLatin1Char('0'));
406 dateSpan.append(dayString);
407 }
408 }
409 return dateSpan;
410}
411
412
414 AnalysisContent& analysis) const
415{
416#ifdef DEBUG_LP
417 SELOGINIT;
418 LDEBUG << "NormalizeDate::operator()"<<m;
419#endif
420 // cerr << "NormalizeDate::operator() features="<< m.features() << endl;
421
422 // assume all information for normalization is in recognized
423 // expression: do not use external information
424
425 unsigned short day=getDay(m, NUMDAY_FEATURE_NAME);
426 unsigned short day_end=getDay(m, NUMDAYEND_FEATURE_NAME);
427
428 unsigned short month=getMonth(m, NUMMONTH_FEATURE_NAME, MONTH_FEATURE_NAME);
429 unsigned short month_end=getMonth(m, NUMMONTHEND_FEATURE_NAME, MONTHEND_FEATURE_NAME);
430
431 unsigned short year=getYear(m,NUMYEAR_FEATURE_NAME);
432 unsigned short year_end=getYear(m,NUMYEAREND_FEATURE_NAME);
433
434 // cerr << "NormalizeDate: day=" << day << ", month=" << month << ", year=" << year
435 // << ", day_end=" << day_end << ", month_end=" << month_end << ", year_end=" << year_end << endl;
436
437 // ad hoc single feature for day and month, when 10/10 is a single t_fraction token
438 if (day==0 && month==0 && m.features().find(NUMDAYMONTH_FEATURE_NAME) != m.features().end())
439 {
440 LimaString daymonth = (*m.features().find(NUMDAYMONTH_FEATURE_NAME)).getValueLimaString();
441 QStringList l=daymonth.split("/");
442 day=l[0].toUShort();
443 month=l[1].toUShort();
444 // ad hoc modif: if day and month values are not compatible with a date, try swapping them (english order)
445 if (month >12 && day <=12 ) {
446 swap(month,day);
447 }
448 }
449
450 QDate referenceDate;
451 unsigned short refyear(0), refmonth(0);
452 if (m_referenceData.getReferenceDate(analysis,referenceDate))
453 {
454 refyear=referenceDate.year();
455 refmonth=referenceDate.month();
456 }
457
458 if (year==0) {
459 year=refyear;
460 //cerr << "--set default year to " << year << endl;
461 }
462 if ( year_end == 0 && (day_end != 0 || month_end != 0) ) {
463 year_end=refyear;
464 //cerr << "--set default year_end to " << year_end << endl;
465 }
466
467 // check if explicit interval
468 QDate dateEnd;
469 if (year_end!=0) {
470 if (month_end==0) {
471 dateEnd=QDate(year_end,12,31);
472 }
473 else if (day_end==0) {
474 // last day of month
475 dateEnd=QDate(year_end,month_end,1).addMonths(1).addDays(-1);
476 }
477 else {
478 dateEnd=QDate(year_end,month_end,day_end);
479 }
480 }
481
482 QString dateSpan=getDateSpan(year,month,day);
484
485 // if incomplete information, set interval values
486 if (year!=0) {
487 if (day==0) {
488 if (month==0) {
489 // set interval to whole year
490 m.features().setFeature(DATE_BEGIN_FEATURE_NAME,QDate(year,01,01));
491 m.features().setFeature(DATE_END_FEATURE_NAME,QDate(year,12,31));
492 }
493 else {
494 // set interval to whole month
495 QDate firstDayOfMonth(year,month,1);
496 m.features().setFeature(DATE_BEGIN_FEATURE_NAME,firstDayOfMonth);
497 m.features().setFeature(DATE_END_FEATURE_NAME,firstDayOfMonth.addMonths(1).addDays(-1));
498 }
499 // priority to explicit interval
500 if (dateEnd.isValid()) {
502 }
503 }
504 else if (month==0) { // numday set without month: take current month
505 month=refmonth;
506 }
507 }
508
509 // the normalized date
510 QDate date=QDate(year,month,day);
511
512 if (date.isValid())
513 {
514 // if interval
515 if (dateEnd.isValid()) {
518 }
519 else {
521 }
522 updateCurrentDate(analysis,date);
523 }
524 else {
525 // default normalization: keep string
527 }
528
530 return true;
531}
532
533//**********************************************************************
535NormalizeRelativeDate(MediaId language,
536 const LimaString& complement):
537NormalizeDate(language,complement),
538m_getNext(false), // default is previous date
539m_diff(0)
540{
541 static const LimaString nextString=Common::Misc::utf8stdstring2limastring("next_");
542 if (complement.indexOf(nextString)!=-1) {
543 m_getNext=true;
544 }
545 static const LimaString diffString=Common::Misc::utf8stdstring2limastring("diff_");
547 //static const LimaString months=Common::Misc::utf8stdstring2limastring("m");
548 //static const LimaString years=Common::Misc::utf8stdstring2limastring("y");
549 //uint64_t i=complement.find(diffString); portage 32 64
550 int i=complement.indexOf(diffString);
551 if (i!=-1) {
552 i+=5; // at end of diff_
553 uint64_t end=complement.indexOf(days,i);
554 LimaString str = complement.mid(i,end-i);
555 uint64_t days=atoi(Common::Misc::limastring2utf8stdstring(str).c_str());
556 m_diff=days;
557 }
558}
559
560QDate adjustDate(unsigned short mention, unsigned short ref, const QDate& refDate, bool getNext, bool months=false) {
561 // adjust to previous/next day/month given the day/month mention in the text and the reference day/month
562 // modulo is 7 for days, 12 for months
563 QDate newDate;
564 int diff=mention - ref;
565 unsigned short modulo=7;
566 int add(0);
567 if (months) {
568 modulo=12;
569 }
570 if (getNext) {
571 add=(modulo+diff)%modulo;
572 if (diff==0) {
573 add=modulo; // ad hoc change, if same value in 'next' context, force jump to next
574 }
575 }
576 else {
577 add=-((modulo-diff)%modulo);
578 }
579 //cerr << "adjust date: ref="<< ref <<", mentioned="<< mention
580 // <<", diff=" << diff << ", add=" << add << endl;
581 // ad hoc distinction between days and months by the modulo
582 if (months) {
583 newDate=refDate.addMonths(add);
584 }
585 else {
586 newDate=refDate.addDays(add);
587 }
588 return newDate;
589}
590
593 AnalysisContent& analysis) const
594{
595 // use a reference to normalize the relative date
596 //cerr << "NormalizeRelativeDate: " << m.getString() << ", features=" << m.features() << endl;
597
598 if (m_resources == 0) {
599 // no resources: cannot normalize date
600#ifdef DEBUG_LP
601 SELOGINIT;
602 LDEBUG << "NormalizeRelativeDate: no resources" ;
603#endif
605 return true;
606 }
607
608// "datemod"
609// "century"
610 unsigned short dayOfMonth=getDay(m, NUMDAY_FEATURE_NAME);
611 unsigned short dayOfWeek=getWeekDay(m, DAY_FEATURE_NAME);
612 unsigned short month=getMonth(m, NUMMONTH_FEATURE_NAME, MONTH_FEATURE_NAME);
613 // assume year is never fixed in relative dates (otherwise, is not relative)
614 unsigned short year=0;
615
616 // cerr << "NormalizeRelativeDate: dayOfWeek="<< dayOfWeek << ", dayOfMonth=" << dayOfMonth
617 // << ", month=" << month << endl;
618
619 // always sets the span
620 QString dateSpan=getDateSpan(year,month,dayOfMonth);
622
623 QDate referenceDate;
624 if (! m_referenceData.getReferenceDate(analysis,referenceDate)) {
626 return true;
627 }
628 unsigned short refday=referenceDate.dayOfWeek();
629 unsigned short refmonth=referenceDate.month();
630
631 QDate newCurrentDate;
632
633 if (month==0) {
634 // relative day
635 if (dayOfMonth==0 && dayOfWeek!=NormalizeDateTimeResources::no_day) {
636 // adjust according to day of week (lundi prochain)
637 newCurrentDate= adjustDate(dayOfWeek, refday, referenceDate, m_getNext); m.features().setFeature(DATE_FEATURE_NAME,newCurrentDate);
638 }
639 }
640 else { // there is a month
641 // adjust according to month (novembre prochain)
642 QDate newDate= adjustDate(month, refmonth, referenceDate, m_getNext, true);
643 // if a day is specified
644 if (dayOfMonth!=0) {
645 newCurrentDate=QDate(newDate.year(),newDate.month(),dayOfMonth);
646 m.features().setFeature(DATE_FEATURE_NAME,newCurrentDate);
647 m.features().setFeature(DATE_SPAN_FEATURE_NAME,getDateSpan(newDate.year(),newDate.month(),dayOfMonth));
648 }
649 else {
650 // set an interval value
651 QDate firstDayOfMonth(newDate.year(),newDate.month(),1);
652 m.features().setFeature(DATE_BEGIN_FEATURE_NAME,firstDayOfMonth);
653 m.features().setFeature(DATE_END_FEATURE_NAME,firstDayOfMonth.addMonths(1).addDays(-1));
654 m.features().setFeature(DATE_SPAN_FEATURE_NAME,getDateSpan(newDate.year(),newDate.month(),0));
655 }
656 }
657
658 // other cases: specific diff (hier,ajourd'hui...)
659 if (m_diff != 0) {
660 newCurrentDate=referenceDate.addDays(m_diff);
661 m.features().setFeature(DATE_FEATURE_NAME,newCurrentDate);
662 }
663
664 // special case : centuries
665 unsigned short century(0);
666 if (m.features().find("century") != m.features().end()) {
667 (*m.features().find("century")).getValue();
668 try {
669 century = boost::any_cast<unsigned short>((*m.features().find("century")).getValue());
670 }
671 catch(const boost::bad_any_cast &) {
672 century = (*m.features().find("century")).getValueLimaString().toUShort();
673 }
674 // 20 (th century) changed to year 1900
675 year = (century-1)*100;
676 }
677
678 if (newCurrentDate.isValid()) {
679 updateCurrentDate(analysis,newCurrentDate);
680 }
682 return true;
683}
684
685//**********************************************************************
687NormalizeTime(MediaId language,
688 const LimaString& complement):
689Automaton::ConstraintFunction(language,complement),
690m_language(language),
691m_resources(0),
692m_referenceData()
693{
694 // default reference date and location are the one indicated for
695 // the document, if set...
696
697 // parse complement to find reference location and reference date,
698 // if indicated
699 m_referenceData.parseComplement(complement);
700
701 try {
702 auto res = LinguisticResources::changeable().getResource(language,"DateTimeNormalization");
703 if (res==0) {
704 SELOGINIT;
705 LWARN << "no resource 'DateTimeNormalization'";
706 }
707 else {
708 m_resources = std::dynamic_pointer_cast<NormalizeDateTimeResources>(res);
709 }
710 }
711 catch (std::exception& e) {
712 // resources are not loaded when compiling the rules
713 }
714}
715
717getTimeDuration(const RecognizerMatch& m) const
718{
719#ifdef DEBUG_LP
720 SELOGINIT;
721 LDEBUG << "NormalizeTime::getTimeDuration...";
722#endif
723 QTime timeDuration;
724
725 unsigned short hou(0),min(0),sec(0);
726 if (m.features().find("hour") != m.features().end()) {
727 try {
728 hou = boost::any_cast<unsigned short>((*m.features().find("hour")).getValue());
729 }
730 catch(const boost::bad_any_cast &) {
731 hou = (*m.features().find("hour")).getValueLimaString().toUShort();
732 }
733 }
734 if (m.features().find("minute") != m.features().end()) {
735 try {
736 min = boost::any_cast<unsigned short>((*m.features().find("minute")).getValue());
737 }
738 catch(const boost::bad_any_cast &) {
739 min = (*m.features().find("minute")).getValueLimaString().toUShort();
740 }
741 }
742 if (m.features().find("second") != m.features().end()) {
743 try {
744 sec = boost::any_cast<unsigned short>((*m.features().find("second")).getValue());
745 }
746 catch(const boost::bad_any_cast &) {
747 sec = (*m.features().find("second")).getValueLimaString().toUShort();
748 }
749 }
750
751#ifdef DEBUG_LP
752 LDEBUG << "NormalizeTime::getTimeDuration h=" << hou << ",m=" << min << ",s" << sec;
753#endif
754
755 if (m.features().find("time") != m.features().end()) {
756 std::string timeString=(*m.features().find("time")).getValueLimaString().toUtf8().constData();
757 //uint64_t i=timeString.find(':'); portage 32 64
758 string::size_type i=timeString.find(':');
759 if (i!=string::npos) {
760 try {
761 // has at least one ":" sep -> guess it has form hh:mm or hh:mm:ss,
762 // try use direct construction from string
763 timeDuration=QTime::fromString(QString::fromUtf8(timeString.c_str()));
764 }
765 catch (std::exception& e) {
766 SELOGINIT;
767 LWARN << "Error getting time duration from string '"
768 << timeString << "'";
769 return timeDuration;
770 }
771 }
772 else {
773 i=timeString.find_first_of("hH");
774 if (i!=string::npos) {
775 hou=atoi(string(timeString,0,i).c_str());
776 min=atoi(string(timeString,i+1).c_str());
777 }
778 }
779 }
780 timeDuration=QTime(hou,min,sec);
781 return timeDuration;
782}
783
784
785// normalizeTime helper functions
787getUTCTime(const QDate& d,
788 const QTime& duration/*,
789 const std::string& location,
790 const boost::local_time::tz_database& tz_db*/) const
791{
792 return QDateTime(d,duration).toUTC().time();
793}
794
796NormalizeLocalTime(MediaId language,
797 const LimaString& complement):
798NormalizeTime(language,complement)
799{
800}
801
804 AnalysisContent& analysis) const
805{
806 // normalize hour to UTC => needs to know the location
807 // use 'DocumentLocation' if exists
808 // otherwise, use adaptor from locale
809
810 // get reference dates and location
811 QDate referenceDate;
812 std::string referenceLocation;
813 bool hasReferenceLocation(true);
814
815 if (! getReferenceData().getReferenceDate(analysis,referenceDate)) {
817 return true;
818 }
819
820 if (! getReferenceData().getReferenceLocation(analysis,referenceLocation)) {
821 SELOGINIT;
822 LWARN << "no reference location '"<< getReferenceData().getLocRefName()
823 << "' found";
824 hasReferenceLocation=false;
825 }
826
827 // parse recognized expression to get duration
828 QTime timeDuration=getTimeDuration(m);
829 if (!timeDuration.isValid()) {
831 return true;
832 }
833
834 try {
835 QTime local(QDateTime(referenceDate,timeDuration).time());
836
838
839 if (! hasReferenceLocation) {
840 return true;
841 }
842
843 if (hasResources() && getResources()->hasTimezoneDatabase()) {
844 QTime utc=getUTCTime(referenceDate,timeDuration/*,
845 referenceLocation,
846 getResources()->getTimezoneDatabase()*/);
847 if (!utc.isValid()) {
848 SELOGINIT;
849 LWARN << "failed to normalize time: ";
850 LDEBUG << "NormalizeLocalTime::operator(): m.getString()=" << m.getString();
852 }
853 else {
855 }
856 }
857 }
858 catch (std::exception& e) {
859 SELOGINIT;
860 LWARN << "exception caught in time normalization of '"
862 << "': " << e.what();
864 }
865 return true;
866}
867
868//**********************************************************************
870NormalizeUTCTime(MediaId language,
871 const LimaString& complement):
872NormalizeTime(language,complement)
873{
874}
875
878 AnalysisContent& analysis) const
879{
880 // do not use a reference location, time is supposed to be UTC already
881#ifdef DEBUG_LP
882 SELOGINIT;
883 LDEBUG << "NormalizeUTCTime::operator()...";
884#endif
885
886 // get reference date
887 QDate referenceDate;
888 if (! getReferenceData().getReferenceDate(analysis,referenceDate)) {
890#ifdef DEBUG_LP
891 LDEBUG << "NormalizeUTCTime::operator: setFeature(TIMESTRING_FEATURE_NAME=" << m.getString();
892#endif
893 return true;
894 }
895
896 QTime timeDuration=getTimeDuration(m);
897 if (!timeDuration.isValid()) {
898 SELOGINIT;
899 LWARN << "cannot compute time duration for '"
901 << "'";
903 return true;
904 }
905
906 try {
907 QTime utcTime(QDateTime(referenceDate,timeDuration).toUTC().time());
909 }
910 catch (std::exception& e) {
911 SELOGINIT;
912 LWARN << "exception caught in time normalization of '"
914 << "': " << e.what();
916 }
917
918 return true;
919}
920
921} // end namespace
922} // end namespace
923} // end namespace
#define DEFAULT_ATTRIBUTE
#define LWARN
Definition LimaCommon.h:160
#define UNDEFLANG
Definition LimaCommon.h:252
#define LDEBUG
Definition LimaCommon.h:157
#define LERROR
Definition LimaCommon.h:161
#define SELOGINIT
#define DATE_SPAN_FEATURE_NAME
#define MONTHEND_FEATURE_NAME
#define DATE_FEATURE_NAME
#define NUMDAY_FEATURE_NAME
#define NUMYEAREND_FEATURE_NAME
#define NUMYEAR_FEATURE_NAME
#define NUMMONTH_FEATURE_NAME
#define NUMMONTHEND_FEATURE_NAME
#define DAY_FEATURE_NAME
#define DATE_END_FEATURE_NAME
#define UTCTIME_FEATURE_NAME
#define DATESTRING_FEATURE_NAME
#define MONTH_FEATURE_NAME
#define NUMDAYEND_FEATURE_NAME
#define TIMESTRING_FEATURE_NAME
#define LOCALTIME_FEATURE_NAME
#define DATE_BEGIN_FEATURE_NAME
#define NUMDAYMONTH_FEATURE_NAME
#define NormalizeDateId
#define NormalizeRelativeDateId
#define NormalizeLocalTimeId
#define NormalizeUTCTimeId
Holds all data that pass through the ProcessUnits Analysis data are shared pointers,...
std::shared_ptr< AnalysisData > getData(const QString &id)
return AnalysisData by id
Holds linguistic data for one language.
const MediaData & mediaData(MediaId media) const
␈rief A class for the description of automata
Definition automaton.h:87
void setFeature(const std::string &name, const ValueType &value)
void addFeature(const std::string &name, const ValueType &value)
EntityFeatures::const_iterator find(const std::string &featureName) const
unsigned short getDayFromString(const LimaString &numdayString) const
std::shared_ptr< NormalizeDateTimeResources > m_resources
NormalizeDate(MediaId language, const LimaString &complement=LimaString())
unsigned short getDay(Automaton::RecognizerMatch &m, const std::string &featureName) const
unsigned short getYear(Automaton::RecognizerMatch &m, const std::string &featureName) const
unsigned short getMonth(Automaton::RecognizerMatch &m, const std::string &featureName, const std::string &alt="") const
unsigned short getWeekDay(Automaton::RecognizerMatch &m, const std::string &featureName) const
QString getDateSpan(unsigned short year, unsigned short month, unsigned short day) const
bool operator()(Automaton::RecognizerMatch &m, AnalysisContent &analysis) const override
zero-ary constraint function : applies the function without a vertex indication (used for actions,...
const Common::PropertyCode::PropertyAccessor * m_microAccessor
void updateCurrentDate(AnalysisContent &analysis, const QDate &currentDate) const
bool operator()(Automaton::RecognizerMatch &m, AnalysisContent &analysis) const override
zero-ary constraint function : applies the function without a vertex indication (used for actions,...
NormalizeLocalTime(MediaId language, const LimaString &complement=LimaString())
bool operator()(Automaton::RecognizerMatch &m, AnalysisContent &analysis) const override
zero-ary constraint function : applies the function without a vertex indication (used for actions,...
NormalizeRelativeDate(MediaId language, const LimaString &complement=LimaString())
QTime getUTCTime(const QDate &d, const QTime &duration) const
const std::shared_ptr< NormalizeDateTimeResources > getResources() const
NormalizeTime(MediaId language, const LimaString &complement=LimaString())
QTime getTimeDuration(const Automaton::RecognizerMatch &m) const
NormalizeUTCTime(MediaId language, const LimaString &complement=LimaString())
bool operator()(Automaton::RecognizerMatch &m, AnalysisContent &analysis) const override
zero-ary constraint function : applies the function without a vertex indication (used for actions,...
bool getReferenceDate(const AnalysisContent &analysis, QDate &date) const
bool getReferenceLocation(const AnalysisContent &analysis, std::string &location) const
bool getReferenceTime(const AnalysisContent &analysis, QTime &time) const
static const MediaticData & single()
const singleton accessor
Definition Singleton.h:51
static LinguisticResources & changeable()
singleton accessor
Definition Singleton.h:71
std::string limastring2utf8stdstring(const Lima::LimaString &phrase, uint32_t size0)
Convert a wide string to a string , in dest up to size bytes.
LimaString utf8stdstring2limastring(const std::string &src)
Automaton::ConstraintFunctionFactory< NormalizeLocalTime > NormalizeLocalTimeFactory(NormalizeLocalTimeId)
Automaton::ConstraintFunctionFactory< NormalizeDate > NormalizeDateFactory(NormalizeDateId)
QDate adjustDate(unsigned short mention, unsigned short ref, const QDate &refDate, bool getNext, bool months=false)
Automaton::ConstraintFunctionFactory< NormalizeUTCTime > NormalizeUTCTimeFactory(NormalizeUTCTimeId)
Automaton::ConstraintFunctionFactory< NormalizeRelativeDate > NormalizeRelativeDateFactory(NormalizeRelativeDateId)
NAUTITIA.
QChar LimaChar
Definition LimaString.h:30
QString LimaString
Definition LimaString.h:33
STL namespace.
void swap(T &lhs, T &rhs)
Definition pugixml.cpp:7439