22import re
33import logging
44import certifi
5- from datetime import datetime
5+ from datetime import datetime , date
6+ from dateutil .relativedelta import relativedelta
67from functools import reduce
78from mongoengine import EmbeddedDocumentField , EmbeddedDocument , Document , QuerySet , register_connection
89from mongoengine .fields import DateField , DateTimeField , ComplexDateTimeField
@@ -1257,9 +1258,58 @@ def _make_date_filter(cls, date_field, key, operator):
12571258 }]
12581259
12591260 @classmethod
1260- def analyze (cls , * args , granularity = None , fields = None , select = None , group_by = None , field_group = None , filter = None ,
1261- filter_or = None , page = None , sort = None , start = None , end = None , date_field = 'date' , start_field = None ,
1262- end_field = None , target = 'SECONDARY_PREFERRED' , ** kwargs ):
1261+ def _parse_start_and_end_time (cls , key , value ) -> date :
1262+ if isinstance (value , date ):
1263+ return value
1264+ elif isinstance (value , datetime ):
1265+ return value .date ()
1266+ elif isinstance (value , str ):
1267+
1268+ if len (value ) == 4 :
1269+ date_format = '%Y'
1270+ date_type = 'YYYY'
1271+ elif len (value ) == 7 :
1272+ date_format = '%Y-%m'
1273+ date_type = 'YYYY-MM'
1274+ else :
1275+ date_format = '%Y-%m-%d'
1276+ date_type = 'YYYY-MM-DD'
1277+
1278+ try :
1279+ dt = datetime .strptime (value , date_format ).date ()
1280+
1281+ if date_type == 'YYYY' :
1282+ if key == 'start' :
1283+ return datetime (dt .year , 1 , 1 )
1284+ else :
1285+ return datetime (dt .year , 1 , 1 ) + relativedelta (years = 1 )
1286+ elif date_type == 'YYYY-MM' :
1287+ if key == 'start' :
1288+ return datetime (dt .year , dt .month , 1 )
1289+ else :
1290+ return datetime (dt .year , dt .month , 1 ) + relativedelta (months = 1 )
1291+ else :
1292+ if key == 'start' :
1293+ return datetime (dt .year , dt .month , dt .day )
1294+ else :
1295+ return datetime (dt .year , dt .month , dt .day ) + relativedelta (days = 1 )
1296+
1297+ except Exception as e :
1298+ raise ERROR_INVALID_PARAMETER_TYPE (key = key , type = date_type )
1299+ else :
1300+ raise ERROR_INVALID_PARAMETER (key = key , reason = f'{ key } option should be datetime or str' )
1301+
1302+ @classmethod
1303+ def _convert_date_value (cls , date_value , date_field_format ):
1304+ if isinstance (date_field_format , str ):
1305+ return date_value .strftime (date_field_format )
1306+ else :
1307+ return date_value
1308+
1309+ @classmethod
1310+ def analyze (cls , * args , granularity = None , fields = None , select = None , group_by = None , field_group = None ,
1311+ filter = None , filter_or = None , page = None , sort = None , start = None , end = None ,
1312+ date_field = 'date' , date_field_format = '%Y-%m-%d' , target = 'SECONDARY_PREFERRED' , ** kwargs ):
12631313
12641314 if fields is None :
12651315 raise ERROR_REQUIRED_PARAMETER (key = 'fields' )
@@ -1275,12 +1325,14 @@ def analyze(cls, *args, granularity=None, fields=None, select=None, group_by=Non
12751325 page_limit = page .get ('limit' )
12761326
12771327 if start :
1278- start_field = start_field or date_field
1279- filter += cls ._make_date_filter (start_field , start , 'gte' )
1328+ start_time : date = cls ._parse_start_and_end_time ('start' , start )
1329+ start_value = cls ._convert_date_value (start_time , date_field_format )
1330+ filter += cls ._make_date_filter (date_field , start_value , 'gte' )
12801331
12811332 if end :
1282- end_field = end_field or date_field
1283- filter += cls ._make_date_filter (end_field , end , 'lte' )
1333+ end_time : date = cls ._parse_start_and_end_time ('end' , end )
1334+ end_value = cls ._convert_date_value (end_time , date_field_format )
1335+ filter += cls ._make_date_filter (date_field , end_value , 'lt' )
12841336
12851337 group_keys = cls ._make_group_keys (group_by , date_field , granularity )
12861338 group_fields = cls ._make_group_fields (fields )
0 commit comments