22
33from __future__ import division
44
5- import time as _time
65import math
76import calendar
87import datetime
9- import warnings
108import locale as _locale
119
1210from contextlib import contextmanager
1917from .tz import Timezone , UTC , FixedTimezone , local_timezone
2018from .tz .timezone_info import TimezoneInfo
2119from .formatting import FORMATTERS
22- from ._compat import PY33 , basestring
20+ from .helpers import timestamp
21+ from ._compat import basestring
2322from .constants import (
2423 SUNDAY , MONDAY , TUESDAY , WEDNESDAY ,
2524 THURSDAY , FRIDAY , SATURDAY ,
@@ -156,25 +155,44 @@ def __new__(cls, year, month, day,
156155 def __init__ (self , year , month , day ,
157156 hour = 0 , minute = 0 , second = 0 , microsecond = 0 ,
158157 tzinfo = UTC ):
159- self .__float_timestamp = None
160-
161- # If a TimezoneInfo is passed we do not convert:
158+ # If a TimezoneInfo is passed we do not convert
162159 if isinstance (tzinfo , TimezoneInfo ):
163160 self ._tz = tzinfo .tz
164161
165- self ._datetime = datetime .datetime (
162+ self ._year = year
163+ self ._month = month
164+ self ._day = day
165+ self ._hour = hour
166+ self ._minute = minute
167+ self ._second = second
168+ self ._microsecond = microsecond
169+ self ._tzinfo = tzinfo
170+
171+ dt = datetime .datetime (
166172 year , month , day ,
167173 hour , minute , second , microsecond ,
168- tzinfo = tzinfo
174+ tzinfo
169175 )
170176 else :
171177 self ._tz = self ._safe_create_datetime_zone (tzinfo )
172178
173- self . _datetime = self ._tz .convert (datetime .datetime (
179+ dt = self ._tz .convert (datetime .datetime (
174180 year , month , day ,
175181 hour , minute , second , microsecond
176182 ), dst_rule = self ._TRANSITION_RULE )
177183
184+ self ._year = dt .year
185+ self ._month = dt .month
186+ self ._day = dt .day
187+ self ._hour = dt .hour
188+ self ._minute = dt .minute
189+ self ._second = dt .second
190+ self ._microsecond = dt .microsecond
191+ self ._tzinfo = dt .tzinfo
192+
193+ self ._timestamp = None
194+ self ._datetime = dt
195+
178196 @classmethod
179197 def instance (cls , dt , tz = UTC ):
180198 """
@@ -482,12 +500,15 @@ def microsecond_(self, microsecond):
482500 def _setter (self , ** kwargs ):
483501 kwargs ['tzinfo' ] = None
484502
485- return self .instance (self ._datetime . replace (** kwargs ), self . _tz )
503+ return self ._tz . convert (self .replace (** kwargs ))
486504
487505 def timezone_ (self , tz ):
488506 tz = self ._safe_create_datetime_zone (tz )
489507
490- return self .instance (self ._datetime .replace (tzinfo = None ), tz )
508+ dt = self .copy ()
509+ dt ._tz = tz
510+
511+ return dt
491512
492513 def tz_ (self , tz ):
493514 return self .timezone_ (tz )
@@ -497,35 +518,35 @@ def timestamp_(self, timestamp, tz=UTC):
497518
498519 @property
499520 def year (self ):
500- return self ._datetime . year
521+ return self ._year
501522
502523 @property
503524 def month (self ):
504- return self ._datetime . month
525+ return self ._month
505526
506527 @property
507528 def day (self ):
508- return self ._datetime . day
529+ return self ._day
509530
510531 @property
511532 def hour (self ):
512- return self ._datetime . hour
533+ return self ._hour
513534
514535 @property
515536 def minute (self ):
516- return self ._datetime . minute
537+ return self ._minute
517538
518539 @property
519540 def second (self ):
520- return self ._datetime . second
541+ return self ._second
521542
522543 @property
523544 def microsecond (self ):
524- return self ._datetime . microsecond
545+ return self ._microsecond
525546
526547 @property
527548 def tzinfo (self ):
528- return self ._datetime . tzinfo
549+ return self ._tzinfo
529550
530551 @property
531552 def day_of_week (self ):
@@ -545,39 +566,30 @@ def days_in_month(self):
545566
546567 @property
547568 def timestamp (self ):
548- return int (self .float_timestamp - self . _datetime . microsecond / 1e6 )
569+ return int (self .float_timestamp // 1 )
549570
550571 @property
551572 def float_timestamp (self ):
552- if self .__float_timestamp is not None :
553- return self .__float_timestamp
554-
555- # If Python > 3.3 we use the native function
556- # else we emulate it
557- if PY33 :
558- self .__float_timestamp = self ._datetime .timestamp ()
559- elif self ._datetime .tzinfo is None :
560- self .__float_timestamp = _time .mktime (
561- (self .year , self .month , self .day ,
562- self .hour , self .minute , self .second ,
563- - 1 , - 1 , - 1 )) + self .microsecond / 1e6
564-
565- else :
566- self .__float_timestamp = (self ._datetime - self ._EPOCH ).total_seconds ()
573+ if self ._timestamp is None :
574+ self ._timestamp = timestamp (
575+ self ._year , self ._month , self ._day ,
576+ self ._hour , self ._minute , self ._second , self ._microsecond ,
577+ self ._tzinfo
578+ )
567579
568- return self .__float_timestamp
580+ return self ._timestamp
569581
570582 @property
571583 def week_of_month (self ):
572- return math .ceil (self .day / DAYS_PER_WEEK )
584+ return math .ceil (self ._day / DAYS_PER_WEEK )
573585
574586 @property
575587 def age (self ):
576588 return self .diff ().in_years ()
577589
578590 @property
579591 def quarter (self ):
580- return int (math .ceil (self .month / 3 ))
592+ return int (math .ceil (self ._month / 3 ))
581593
582594 @property
583595 def offset (self ):
@@ -599,7 +611,7 @@ def utc(self):
599611
600612 @property
601613 def is_dst (self ):
602- return self ._datetime . tzinfo .is_dst
614+ return self .tzinfo .is_dst
603615
604616 @property
605617 def timezone (self ):
@@ -617,7 +629,7 @@ def get_timezone(self):
617629 return self ._tz
618630
619631 def get_offset (self ):
620- return int (self ._datetime . utcoffset (). total_seconds () )
632+ return int (self ._tzinfo . offset )
621633
622634 def with_date (self , year , month , day ):
623635 """
@@ -634,12 +646,11 @@ def with_date(self, year, month, day):
634646
635647 :rtype: Pendulum
636648 """
637- dt = self ._datetime .replace (
638- year = int (year ), month = int (month ), day = int (day ),
639- tzinfo = None
649+ dt = self .replace (
650+ year = int (year ), month = int (month ), day = int (day )
640651 )
641652
642- return self .instance (dt , self . _tz )
653+ return self ._tz . convert (dt )
643654
644655 def with_time (self , hour , minute , second , microsecond = 0 ):
645656 """
@@ -940,7 +951,7 @@ def get_formatter(cls):
940951
941952 def __str__ (self ):
942953 if self ._to_string_format is None :
943- return self ._datetime . isoformat ()
954+ return self .isoformat ()
944955
945956 return self .format (self ._to_string_format , formatter = 'classic' )
946957
@@ -2174,25 +2185,16 @@ def timetuple(self):
21742185 def utctimetuple (self ):
21752186 return self ._datetime .utctimetuple ()
21762187
2177- def date (self ):
2178- return self ._datetime .date ()
2179-
2180- def time (self ):
2181- return self ._datetime .time ()
2182-
2183- def timetz (self ):
2184- return self ._datetime .timetz ()
2185-
21862188 def replace (self , year = None , month = None , day = None , hour = None ,
21872189 minute = None , second = None , microsecond = None , tzinfo = True ):
2188- year = year if year is not None else self ._datetime . year
2189- month = month if month is not None else self ._datetime . month
2190- day = day if day is not None else self ._datetime . day
2191- hour = hour if hour is not None else self ._datetime . hour
2192- minute = minute if minute is not None else self ._datetime . minute
2193- second = second if second is not None else self ._datetime . second
2194- microsecond = microsecond if microsecond is not None else self ._datetime . microsecond
2195- tzinfo = tzinfo if tzinfo is not True else self ._datetime . tzinfo
2190+ year = year if year is not None else self ._year
2191+ month = month if month is not None else self ._month
2192+ day = day if day is not None else self ._day
2193+ hour = hour if hour is not None else self ._hour
2194+ minute = minute if minute is not None else self ._minute
2195+ second = second if second is not None else self ._second
2196+ microsecond = microsecond if microsecond is not None else self ._microsecond
2197+ tzinfo = tzinfo if tzinfo is not True else self ._tzinfo
21962198
21972199 return self .instance (
21982200 self ._datetime .replace (year = year , month = month , day = day ,
@@ -2203,33 +2205,18 @@ def replace(self, year=None, month=None, day=None, hour=None,
22032205 def astimezone (self , tz = None ):
22042206 return self .instance (self ._datetime .astimezone (tz ))
22052207
2206- def ctime (self ):
2207- return self ._datetime .ctime ()
2208-
22092208 def isoformat (self , sep = 'T' ):
22102209 return self ._datetime .isoformat (sep )
22112210
22122211 def utcoffset (self ):
2213- return self ._datetime .utcoffset ()
2212+ return self ._tzinfo .utcoffset (self )
22142213
22152214 def tzname (self ):
22162215 return self ._datetime .tzname ()
22172216
22182217 def dst (self ):
22192218 return self ._datetime .dst ()
22202219
2221- def toordinal (self ):
2222- return self ._datetime .toordinal ()
2223-
2224- def weekday (self ):
2225- return self ._datetime .weekday ()
2226-
2227- def isoweekday (self ):
2228- return self ._datetime .isoweekday ()
2229-
2230- def isocalendar (self ):
2231- return self ._datetime .isocalendar ()
2232-
22332220 def __format__ (self , format_spec ):
22342221 if len (format_spec ) > 0 :
22352222 return self .strftime (format_spec )
@@ -2250,11 +2237,18 @@ def _getstate(self):
22502237 )
22512238
22522239 def __setstate__ (self , year , month , day , hour , minute , second , microsecond , tz ):
2240+ self ._year = year
2241+ self ._month = year
2242+ self ._day = year
2243+ self ._hour = year
2244+ self ._minute = year
2245+ self ._second = year
22532246 self ._datetime = tz .convert (datetime .datetime (
22542247 year , month , day ,
22552248 hour , minute , second , microsecond
22562249 ))
22572250 self ._tz = tz
2251+ self ._tzinfo = self ._datetime .tzinfo
22582252
22592253 def __reduce__ (self ):
22602254 return self .__class__ , self ._getstate ()
0 commit comments