1# -*- coding: utf-8 -*- 2"""Cocoa timestamp implementation.""" 3 4import decimal 5 6from dfdatetime import definitions 7from dfdatetime import factory 8from dfdatetime import interface 9 10 11class CocoaTimeEpoch(interface.DateTimeEpoch): 12 """Cocoa time epoch.""" 13 14 def __init__(self): 15 """Initializes a Cocoa time epoch.""" 16 super(CocoaTimeEpoch, self).__init__(2001, 1, 1) 17 18 19class CocoaTime(interface.DateTimeValues): 20 """Cocoa timestamp. 21 22 The Cocoa timestamp is a floating point value that contains the number of 23 seconds since 2001-01-01 00:00:00 (also known as the Cocoa epoch). 24 Negative values represent date and times predating the Cocoa epoch. 25 26 Attributes: 27 is_local_time (bool): True if the date and time value is in local time. 28 """ 29 # The difference between January 1, 2001 and January 1, 1970 in seconds. 30 _COCOA_TO_POSIX_BASE = -978307200 31 32 _EPOCH = CocoaTimeEpoch() 33 34 def __init__(self, time_zone_offset=None, timestamp=None): 35 """Initializes a Cocoa timestamp. 36 37 Args: 38 time_zone_offset (Optional[int]): time zone offset in number of minutes 39 from UTC or None if not set. 40 timestamp (Optional[float]): Cocoa timestamp. 41 """ 42 super(CocoaTime, self).__init__(time_zone_offset=time_zone_offset) 43 self._precision = definitions.PRECISION_1_SECOND 44 self._timestamp = timestamp 45 46 @property 47 def timestamp(self): 48 """float: Cocoa timestamp or None if not set.""" 49 return self._timestamp 50 51 def _GetNormalizedTimestamp(self): 52 """Retrieves the normalized timestamp. 53 54 Returns: 55 float: normalized timestamp, which contains the number of seconds since 56 January 1, 1970 00:00:00 and a fraction of second used for increased 57 precision, or None if the normalized timestamp cannot be determined. 58 """ 59 if self._normalized_timestamp is None: 60 if self._timestamp is not None: 61 self._normalized_timestamp = ( 62 decimal.Decimal(self._timestamp) - self._COCOA_TO_POSIX_BASE) 63 64 if self._time_zone_offset: 65 self._normalized_timestamp -= self._time_zone_offset * 60 66 67 return self._normalized_timestamp 68 69 def CopyFromDateTimeString(self, time_string): 70 """Copies a Cocoa timestamp from a date and time string. 71 72 Args: 73 time_string (str): date and time value formatted as: 74 YYYY-MM-DD hh:mm:ss.######[+-]##:## 75 76 Where # are numeric digits ranging from 0 to 9 and the seconds 77 fraction can be either 3 or 6 digits. The time of day, seconds 78 fraction and time zone offset are optional. The default time zone 79 is UTC. 80 81 Raises: 82 ValueError: if the time string is invalid or not supported. 83 """ 84 date_time_values = self._CopyDateTimeFromString(time_string) 85 86 year = date_time_values.get('year', 0) 87 month = date_time_values.get('month', 0) 88 day_of_month = date_time_values.get('day_of_month', 0) 89 hours = date_time_values.get('hours', 0) 90 minutes = date_time_values.get('minutes', 0) 91 seconds = date_time_values.get('seconds', 0) 92 microseconds = date_time_values.get('microseconds', None) 93 time_zone_offset = date_time_values.get('time_zone_offset', 0) 94 95 timestamp = self._GetNumberOfSecondsFromElements( 96 year, month, day_of_month, hours, minutes, seconds) 97 timestamp += self._COCOA_TO_POSIX_BASE 98 99 timestamp = float(timestamp) 100 if microseconds is not None: 101 timestamp += float(microseconds) / definitions.MICROSECONDS_PER_SECOND 102 103 self._normalized_timestamp = None 104 self._timestamp = timestamp 105 self._time_zone_offset = time_zone_offset 106 107 def CopyToDateTimeString(self): 108 """Copies the Cocoa timestamp to a date and time string. 109 110 Returns: 111 str: date and time value formatted as: YYYY-MM-DD hh:mm:ss.###### or 112 None if the timestamp cannot be copied to a date and time string. 113 """ 114 if self._timestamp is None: 115 return None 116 117 number_of_days, hours, minutes, seconds = self._GetTimeValues( 118 int(self._timestamp)) 119 120 year, month, day_of_month = self._GetDateValuesWithEpoch( 121 number_of_days, self._EPOCH) 122 123 microseconds = int( 124 (self._timestamp % 1) * definitions.MICROSECONDS_PER_SECOND) 125 126 return '{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}.{6:06d}'.format( 127 year, month, day_of_month, hours, minutes, seconds, microseconds) 128 129 130factory.Factory.RegisterDateTimeValues(CocoaTime) 131