def validate_analysis_period(self):
a_per = self.header.analysis_period<EOL>n_ap = [a_per.st_month, a_per.st_day, a_per.st_hour, a_per.end_month,<EOL>a_per.end_day, a_per.end_hour, a_per.timestep, a_per.is_leap_year]<EOL>sort_datetimes, sort_values = zip(*sorted(zip(self.datetimes, self.values)))<EOL>if not a_per.is_reversed and not a_per.is_annual:<EOL><INDENT>if sort_datetimes[<NUM_LIT:0>].doy < a_per.st_time.doy:<EOL><INDENT>n_ap[<NUM_LIT:0>] = sort_datetimes[<NUM_LIT:0>].month<EOL>n_ap[<NUM_LIT:1>] = sort_datetimes[<NUM_LIT:0>].day<EOL><DEDENT>if sort_datetimes[-<NUM_LIT:1>].doy > a_per.end_time.doy:<EOL><INDENT>n_ap[<NUM_LIT:3>] = sort_datetimes[-<NUM_LIT:1>].month<EOL>n_ap[<NUM_LIT:4>] = sort_datetimes[-<NUM_LIT:1>].day<EOL><DEDENT><DEDENT>elif a_per.is_reversed:<EOL><INDENT>last_ind = None<EOL>for i, date_t in enumerate(sort_datetimes):<EOL><INDENT>last_ind = i if date_t.moy <= a_per.end_time.moy else last_ind<EOL><DEDENT>if last_ind is not None:<EOL><INDENT>last_ind = last_ind + <NUM_LIT:1><EOL>sort_datetimes = sort_datetimes[last_ind:] + sort_datetimes[:last_ind]<EOL>sort_values = sort_values[last_ind:] + sort_values[:last_ind]<EOL><DEDENT>if sort_datetimes[<NUM_LIT:0>].doy > a_per.end_time.doy andsort_datetimes[<NUM_LIT:0>].doy < a_per.st_time.doy:<EOL><INDENT>n_ap[<NUM_LIT:0>], n_ap[<NUM_LIT:1>], n_ap[<NUM_LIT:3>], n_ap[<NUM_LIT:4>] = <NUM_LIT:1>, <NUM_LIT:1>, <NUM_LIT:12>, <NUM_LIT><EOL>sort_datetimes, sort_values = zip(*sorted(zip(<EOL>self.datetimes, self.values)))<EOL><DEDENT><DEDENT>if not a_per.is_annual:<EOL><INDENT>if a_per.st_hour != <NUM_LIT:0>:<EOL><INDENT>for date_t in sort_datetimes:<EOL><INDENT>n_ap[<NUM_LIT:2>] = date_t.hour if date_t.hour < n_ap[<NUM_LIT:2>] else n_ap[<NUM_LIT:2>]<EOL><DEDENT><DEDENT>if a_per.end_hour != <NUM_LIT>:<EOL><INDENT>for date_t in sort_datetimes:<EOL><INDENT>n_ap[<NUM_LIT:5>] = date_t.hour if date_t.hour > n_ap[<NUM_LIT:5>] else n_ap[<NUM_LIT:5>]<EOL><DEDENT><DEDENT><DEDENT>for i in xrange(len(sort_datetimes)):<EOL><INDENT>assert sort_datetimes[i] != sort_datetimes[i - <NUM_LIT:1>], '<STR_LIT>''<STR_LIT>'.format(sort_datetimes[i])<EOL><DEDENT>mins_per_step = int(<NUM_LIT> / n_ap[<NUM_LIT:6>])<EOL>for date_t in sort_datetimes:<EOL><INDENT>if date_t.moy % mins_per_step != <NUM_LIT:0>:<EOL><INDENT>i = <NUM_LIT:0><EOL>valid_steps = sorted(a_per.VALIDTIMESTEPS.keys())<EOL>while date_t.moy % mins_per_step != <NUM_LIT:0> and i < len(valid_steps):<EOL><INDENT>mins_per_step = int(<NUM_LIT> / valid_steps[i])<EOL>i += <NUM_LIT:1><EOL><DEDENT>n_ap[<NUM_LIT:6>] = int(<NUM_LIT> / mins_per_step)<EOL><DEDENT><DEDENT>if a_per.is_leap_year is False:<EOL><INDENT>for date_t in sort_datetimes:<EOL><INDENT>if date_t.month == <NUM_LIT:2> and date_t.day == <NUM_LIT>:<EOL><INDENT>n_ap[<NUM_LIT:7>] = True<EOL><DEDENT><DEDENT><DEDENT>new_ap = AnalysisPeriod(*n_ap)<EOL>new_header = self.header.duplicate()<EOL>new_header._analysis_period = new_ap<EOL>new_coll = HourlyDiscontinuousCollection(new_header, sort_values, sort_datetimes)<EOL>new_coll._validated_a_period = True<EOL>return new_coll<EOL>
Get a collection where the header analysis_period aligns with datetimes.

        This means that checks for five criteria will be performed:
        1) All datetimes in the data collection are in chronological orderstarting
            from the analysis_period start hour to the end hour.
        2) No duplicate datetimes exist in the data collection.
        3) There are no datetimes that lie outside of the analysis_period time range.
        4) There are no datetimes that do not align with the analysis_period timestep.
        5) Datetimes for February 29th are excluded if is_leap_year is False on
            the analysis_period.

        Note that there is no need to run this check any time that a discontinous
        data collection has been derived from a continuous one or when the
        validated_a_period attribute of the collection is True.  Furthermore, most
        methods on this data collection will still run without a validated
        analysis_period.