77import math
88from copy import copy
99from numbers import Real
10+ from datetime import datetime
1011from textwrap import indent , shorten
11- from datetime import datetime , timedelta
1212from functools import partial , total_ordering
1313from collections .abc import Mapping
1414from operator import attrgetter
1515
1616from .collections import Counter , FrozenCounter
1717from .conversions import try_conversion , parse_bool
18- from .format import format_int , format_repr , format_sample
1918from .xml import ElementFactory , xml , merge_siblings
19+ from .format import (
20+ format_int ,
21+ format_repr ,
22+ format_sample ,
23+ format_timestamp_numrepr ,
24+ )
2025
2126
2227tag = ElementFactory ()
@@ -905,14 +910,15 @@ def from_strings(cls, iterable, pattern, bad_threshold=0):
905910 pattern = pattern )
906911
907912 @classmethod
908- def from_numbers (cls , pattern , epoch = datetime .utcfromtimestamp (0 ),
909- unit = timedelta (seconds = 1 )):
913+ def from_numbers (cls , pattern , offset = 0 , scale = 1 ):
910914 """
911915 Class method for constructing an instance wrapped in a :class:`NumRepr`
912916 to indicate a numeric representation of a set of timestamps (e.g. day
913- offset from the UNIX epoch; a different *epoch* may be specified as
914- a :class:`~datetime.datetime`, and a different *unit* as a
915- :class:`~datetime.timedelta`, which defaults to 1 second).
917+ offset from the UNIX epoch). A different epoch may be specified as a
918+ numeric *offset*, and a different epoch *scale* as a numeric number of
919+ seconds). The default offset and scale are 0 and 1 which is equivalent
920+ to a seconds offset from the UNIX epoch (i.e. a traditional UNIX
921+ timestamp).
916922
917923 Constructed with an *sample* of number, a *pattern* (which can be a
918924 :class:`StrRepr` instance if the numbers are themselves represented as
@@ -925,9 +931,6 @@ def from_numbers(cls, pattern, epoch=datetime.utcfromtimestamp(0),
925931 else :
926932 num_pattern = pattern
927933 dt_counter = Counter ()
928- unix_epoch = datetime .utcfromtimestamp (0 )
929- offset = (epoch - unix_epoch ).total_seconds ()
930- scale = unit .total_seconds ()
931934 for value , count in num_pattern .values .sample .items ():
932935 dt_value = datetime .utcfromtimestamp ((value * scale ) + offset )
933936 dt_counter [dt_value ] = count
@@ -1208,27 +1211,13 @@ class NumRepr(Repr):
12081211
12091212 def __str__ (self ):
12101213 type_ , scale , offset = self .pattern
1211- delta = timedelta (seconds = scale )
1212- unit = ', ' .join (
1213- '{count}{prop}' .format (
1214- count = '{value}*' .format (value = value ) if value != 1 else '' ,
1215- prop = prop )
1216- for prop in ('days' , 'seconds' , 'microseconds' )
1217- for value in (getattr (delta , prop ),)
1218- if value
1219- )
1220- if not offset % 86400 :
1221- epoch = datetime .utcfromtimestamp (offset ).date ().isoformat ()
1222- else :
1223- epoch = datetime .utcfromtimestamp (offset ).isoformat ()
1224- if type_ is Int :
1225- template = 'int {unit} after {epoch} of {self.content}'
1226- elif type_ is Float :
1227- template = 'float {unit} after {epoch} of {self.content}'
1228- else :
1229- assert False , 'str(num-repr) of {self.content!r}' .format (
1230- self = self , unit = unit , epoch = epoch )
1231- return template .format (self = self , unit = unit , epoch = epoch )
1214+ try :
1215+ type_name = {Int : 'int' , Float : 'float' }[type_ ]
1216+ except KeyError :
1217+ assert False , 'str(num-repr) of {self.content!r}' .format (self = self )
1218+ return '{type_name} {numrepr} of {self.content}' .format (
1219+ self = self , type_name = type_name ,
1220+ numrepr = format_timestamp_numrepr (offset , scale ))
12321221
12331222 def __xml__ (self ):
12341223 type_ , scale , offset = self .pattern
0 commit comments