def test_duration_string(self): duration = timezone.timedelta(hours=1, minutes=30, seconds=45) self.assertEqual(duration_string(duration), '1 hour, 30 minutes, 45 seconds') self.assertEqual(duration_string(duration, 'm'), '1 hour, 30 minutes') self.assertEqual(duration_string(duration, 'h'), '1 hour') self.assertRaises(TypeError, lambda: duration_string('1 hour'))
def test_duration_string(self): duration = timezone.timedelta(hours=1, minutes=30, seconds=45) self.assertEqual(utils.duration_string(duration), "1 hour, 30 minutes, 45 seconds") self.assertEqual(utils.duration_string(duration, "m"), "1 hour, 30 minutes") self.assertEqual(utils.duration_string(duration, "h"), "1 hour") self.assertRaises(TypeError, lambda: utils.duration_string("1 hour"))
def get_paginated_response(self, data): return Response( OrderedDict([ ('count', self.count), ('next', self.get_next_link()), ('previous', self.get_previous_link()), ('total_duration', duration_string(self.total_duration)), ('subtotal_duration', duration_string(self.subtotal_duration)), ('results', data) ]))
def _format_label(duration, start_time, end_time): """ Formats a time block label. :param duration: Duration. :param start_time: Start time. :param end_time: End time. :return: Formatted string with duration, start, and end time. """ return 'Asleep {} ({} to {})'.format(duration_string(duration), start_time.strftime('%I:%M %p'), end_time.strftime('%I:%M %p'))
def _format_label(duration, start_time, end_time): """ Formats a time block label. :param duration: Duration. :param start_time: Start time. :param end_time: End time. :return: Formatted string with duration, start, and end time. """ return 'Asleep {} ({} to {})'.format( duration_string(duration), formats.time_format(start_time, 'TIME_FORMAT'), formats.time_format(end_time, 'TIME_FORMAT'))
def duration_string(duration, precision="s"): """ Format a duration (e.g. "2 hours, 3 minutes, 35 seconds"). :param duration: a timedetla instance. :param precision: the level of precision to return (h for hours, m for minutes, s for seconds) :returns: a string representation of the duration. """ if not duration: return "" try: return utils.duration_string(duration, precision) except (ValueError, TypeError): return ""
def sleep_pattern(instances): """ Create a graph showing blocked out periods of sleep during each day. :param instances: a QuerySet of Sleep instances. :returns: a tuple of the the graph's html and javascript. """ # TODO: Simplify this using the bar charts "base" property. y_df = pd.DataFrame() text_df = pd.DataFrame() last_end_time = None adjustment = None df_index = 0 for instance in instances: start_time = timezone.localtime(instance.start) end_time = timezone.localtime(instance.end) start_date = start_time.date().isoformat() duration = instance.duration # Check if the previous entry crossed midnight (see below). if adjustment: # Fake (0) entry to keep the color switching logic working. df_index = _add_sleep_entry(y_df, text_df, 0, adjustment['column'], 0) # Real adjustment entry. df_index = _add_sleep_entry( y_df, text_df, df_index, adjustment['column'], adjustment['duration'].seconds / 60, 'Asleep {} ({} to {})'.format( duration_string(adjustment['duration']), adjustment['start_time'].strftime('%I:%M %p'), adjustment['end_time'].strftime('%I:%M %p'))) last_end_time = timezone.localtime(adjustment['end_time']) adjustment = None # If the dates do not match, set up an adjustment for the next day. if end_time.date() != start_time.date(): adj_start_time = end_time.replace(hour=0, minute=0, second=0) adjustment = { 'column': end_time.date().isoformat(), 'start_time': adj_start_time, 'end_time': end_time, 'duration': end_time - adj_start_time } # Adjust end_time for the current entry. end_time = end_time.replace(year=start_time.year, month=start_time.month, day=start_time.day, hour=23, minute=59, second=0) duration = end_time - start_time if start_date not in y_df: last_end_time = start_time.replace(hour=0, minute=0, second=0) # Awake time. df_index = _add_sleep_entry(y_df, text_df, df_index, start_date, (start_time - last_end_time).seconds / 60) # Asleep time. df_index = _add_sleep_entry( y_df, text_df, df_index, start_date, duration.seconds / 60, 'Asleep {} ({} to {})'.format(duration_string(duration), start_time.strftime('%I:%M %p'), end_time.strftime('%I:%M %p'))) # Update the previous entry duration if an offset change occurred. # This can happen when an entry crosses a daylight savings time change. if start_time.utcoffset() != end_time.utcoffset(): diff = start_time.utcoffset() - end_time.utcoffset() duration -= timezone.timedelta(seconds=diff.seconds) y_df.set_value(df_index - 1, start_date, duration.seconds / 60) last_end_time = end_time dates = list(y_df) traces = [] color = 'rgba(255, 255, 255, 0)' for index, row in y_df.iterrows(): traces.append( go.Bar( x=dates, y=row, text=text_df.ix[index], hoverinfo='text', marker={'color': color}, showlegend=False, )) if color == 'rgba(255, 255, 255, 0)': color = 'rgb(35, 110, 150)' else: color = 'rgba(255, 255, 255, 0)' layout_args = utils.default_graph_layout_options() layout_args['margin']['b'] = 100 layout_args['barmode'] = 'stack' layout_args['hovermode'] = 'closest' layout_args['title'] = '<b>Sleep Pattern</b>' layout_args['height'] = 800 layout_args['xaxis']['title'] = 'Date' layout_args['xaxis']['tickangle'] = -65 layout_args['xaxis']['rangeselector'] = utils.rangeselector_date() start = timezone.localtime().strptime('12:00 AM', '%I:%M %p') ticks = OrderedDict() ticks[0] = start.strftime('%I:%M %p') for i in range(30, 60 * 24, 30): ticks[i] = (start + timezone.timedelta(minutes=i)).strftime('%I:%M %p') layout_args['yaxis']['title'] = 'Time of day' layout_args['yaxis']['rangemode'] = 'tozero' layout_args['yaxis']['tickmode'] = 'array' layout_args['yaxis']['tickvals'] = list(ticks.keys()) layout_args['yaxis']['ticktext'] = list(ticks.values()) layout_args['yaxis']['tickfont'] = {'size': 10} fig = go.Figure({'data': traces, 'layout': go.Layout(**layout_args)}) output = plotly.plot(fig, output_type='div', include_plotlyjs=False) return utils.split_graph_output(output)
def get_objects(child, date): """ Create a time-sorted dictionary of all events for a child. :param child: an instance of a Child. :param date: a DateTime instance for the day to be summarized. :returns: a list of the day's events. """ min_date = date max_date = date.replace(hour=23, minute=59, second=59) events = [] instances = DiaperChange.objects.filter(child=child).filter( time__range=(min_date, max_date)).order_by('-time') for instance in instances: change_type = '' if instance.wet and instance.solid: change_type = 'wet and solid' elif instance.wet: change_type = 'wet' elif instance.solid: change_type = 'solid' events.append({ 'time': timezone.localtime(instance.time), 'event': _('%(child)s had a diaper change.') % { 'child': child.first_name, 'change_type': change_type }, 'detail': _('%(change_type)s (%(color)s)') % { 'change_type': change_type, 'color': instance.color if instance.color else '' }, 'model_name': instance.model_name, }) instances = Feeding.objects.filter(child=child).filter( start__range=(min_date, max_date)).order_by('-start') for instance in instances: feeding_type = '' if instance.type == 'breast milk': feeding_type = "{type} {method}".format(type=instance.type, method=instance.method) elif instance.type in ['formula', 'fortified breast milk']: if instance.amount: feeding_type = "{type} ({amount})".format(type=instance.type, amount=instance.amount) else: feeding_type = "{type}".format(type=instance.type) events.append({ 'time': timezone.localtime(instance.start), 'event': _('%(child)s started feeding.') % { 'child': instance.child.first_name }, 'detail': _('%(feeding_type)s') % { 'feeding_type': feeding_type }, 'model_name': instance.model_name, 'type': 'start' }) events.append({ 'time': timezone.localtime(instance.end), 'event': _('%(child)s finished feeding.') % { 'child': instance.child.first_name }, 'detail': _('%(feeding_type)s') % { 'feeding_type': feeding_type }, 'model_name': instance.model_name, 'type': 'end' }) instances = Sleep.objects.filter(child=child).filter( start__range=(min_date, max_date)).order_by('-start') for instance in instances: events.append({ 'time': timezone.localtime(instance.start), 'event': _('%(child)s fell asleep.') % { 'child': instance.child.first_name }, 'detail': _('%(duration)s') % { 'duration': '' }, 'model_name': instance.model_name, 'type': 'start' }) events.append({ 'time': timezone.localtime(instance.end), 'event': _('%(child)s woke up.') % { 'child': instance.child.first_name }, 'detail': _('%(duration)s') % { 'duration': duration_string(instance.duration) }, 'model_name': instance.model_name, 'type': 'end' }) instances = TummyTime.objects.filter(child=child).filter( start__range=(min_date, max_date)).order_by('-start') for instance in instances: events.append({ 'time': timezone.localtime(instance.start), 'event': _('%(child)s started tummy time!') % { 'child': instance.child.first_name }, 'detail': _('%(duration)s') % { 'duration': '' }, 'model_name': instance.model_name, 'type': 'start' }) events.append({ 'time': timezone.localtime(instance.end), 'event': _('%(child)s finished tummy time.') % { 'child': instance.child.first_name }, 'detail': _('%(duration)s') % { 'duration': duration_string(instance.duration) }, 'model_name': instance.model_name, 'type': 'end' }) events.sort(key=lambda x: x['time'], reverse=True) return events