Commit cf36f5df authored by Hilko Bengen's avatar Hilko Bengen

New upstream version 20180110

parent 1af3ae03
dfdatetime (20171228-1) unstable; urgency=low
dfdatetime (20180110-1) unstable; urgency=low
* Auto-generated
-- Log2Timeline <log2timeline-dev@googlegroups.com> Thu, 28 Dec 2017 10:11:45 +0100
\ No newline at end of file
-- Log2Timeline <log2timeline-dev@googlegroups.com> Wed, 10 Jan 2018 07:04:54 +0100
\ No newline at end of file
......@@ -5,4 +5,4 @@ dfDateTime, or Digital Forensics date and time, provides date and time
objects to preserve accuracy and precision.
"""
__version__ = '20171228'
__version__ = '20180110'
......@@ -68,7 +68,7 @@ class CocoaTime(interface.DateTimeValues):
timestamp = float(timestamp)
if microseconds is not None:
timestamp += float(microseconds) / 1000000
timestamp += float(microseconds) / definitions.MICROSECONDS_PER_SECOND
self.timestamp = timestamp
self.is_local_time = False
......@@ -84,7 +84,7 @@ class CocoaTime(interface.DateTimeValues):
return None, None
timestamp = self.timestamp - self._COCOA_TO_POSIX_BASE
remainder = int((timestamp % 1) * 10000000)
remainder = int((timestamp % 1) * self._100NS_PER_SECOND)
return int(timestamp), remainder
def CopyToDateTimeString(self):
......@@ -103,7 +103,8 @@ class CocoaTime(interface.DateTimeValues):
year, month, day_of_month = self._GetDateValues(
number_of_days, 2001, 1, 1)
microseconds = int((self.timestamp % 1) * 1000000)
microseconds = int(
(self.timestamp % 1) * definitions.MICROSECONDS_PER_SECOND)
return '{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}.{6:06d}'.format(
year, month, day_of_month, hours, minutes, seconds, microseconds)
......@@ -117,5 +118,6 @@ class CocoaTime(interface.DateTimeValues):
if self.timestamp is None:
return
timestamp = (self.timestamp - self._COCOA_TO_POSIX_BASE) * 1000000
timestamp = definitions.MICROSECONDS_PER_SECOND * (
self.timestamp - self._COCOA_TO_POSIX_BASE)
return int(timestamp)
......@@ -10,6 +10,16 @@ Also see:
from __future__ import unicode_literals
SECONDS_PER_DAY = 24 * 60 * 60
DECISECONDS_PER_SECOND = 10
MILLISECONDS_PER_SECOND = 1000
MICROSECONDS_PER_SECOND = 1000000
MICROSECONDS_PER_DECISECOND = 100000
MICROSECONDS_PER_MILLISECOND = 1000
PRECISION_1_DAY = '1d'
PRECISION_1_HOUR = '1h'
PRECISION_1_NANOSECOND = '1ns'
......
......@@ -29,9 +29,6 @@ class DelphiDateTime(interface.DateTimeValues):
# The difference between Dec 30, 1899 and Jan 1, 1970 in days.
_DELPHI_TO_POSIX_BASE = 25569
# The number of seconds per day.
_SECONDS_PER_DAY = 86400
# The number of microseconds per day.
_MICROSECONDS_PER_DAY = 86400000000
......@@ -76,7 +73,7 @@ class DelphiDateTime(interface.DateTimeValues):
timestamp = self._GetNumberOfSecondsFromElements(
year, month, day_of_month, hours, minutes, seconds)
timestamp = float(timestamp) / self._SECONDS_PER_DAY
timestamp = float(timestamp) / definitions.SECONDS_PER_DAY
timestamp += self._DELPHI_TO_POSIX_BASE
if microseconds is not None:
timestamp += float(microseconds) / self._MICROSECONDS_PER_DAY
......@@ -94,9 +91,9 @@ class DelphiDateTime(interface.DateTimeValues):
if self.timestamp is None:
return None, None
timestamp = (
(self.timestamp - self._DELPHI_TO_POSIX_BASE) * self._SECONDS_PER_DAY)
remainder = int((timestamp % 1) * 10000000)
timestamp = definitions.SECONDS_PER_DAY * (
self.timestamp - self._DELPHI_TO_POSIX_BASE)
remainder = int((timestamp % 1) * self._100NS_PER_SECOND)
return int(timestamp), remainder
def CopyToDateTimeString(self):
......@@ -109,7 +106,7 @@ class DelphiDateTime(interface.DateTimeValues):
if self.timestamp is None:
return
number_of_seconds = self.timestamp * self._SECONDS_PER_DAY
number_of_seconds = self.timestamp * definitions.SECONDS_PER_DAY
number_of_days, hours, minutes, seconds = self._GetTimeValues(
int(number_of_seconds))
......@@ -117,7 +114,8 @@ class DelphiDateTime(interface.DateTimeValues):
year, month, day_of_month = self._GetDateValues(
number_of_days, 1899, 12, 30)
microseconds = int((number_of_seconds % 1) * 1000000)
microseconds = int(
(number_of_seconds % 1) * definitions.MICROSECONDS_PER_SECOND)
return '{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}.{6:06d}'.format(
year, month, day_of_month, hours, minutes, seconds, microseconds)
......
......@@ -26,7 +26,8 @@ class FakeTime(interface.DateTimeValues):
super(FakeTime, self).__init__()
# Note that time.time() and divmod return floating point values.
timestamp, fraction_of_second = divmod(time.time(), 1)
self._microseconds = int(fraction_of_second * 1000000)
self._microseconds = int(
fraction_of_second * definitions.MICROSECONDS_PER_SECOND)
self._number_of_seconds = int(timestamp)
self.precision = definitions.PRECISION_1_MICROSECOND
......@@ -68,7 +69,8 @@ class FakeTime(interface.DateTimeValues):
return None, None
if self._microseconds is not None:
return self._number_of_seconds, self._microseconds * 10
return self._number_of_seconds, (
self._microseconds * self._100NS_PER_MICROSECOND)
return self._number_of_seconds, None
......@@ -106,7 +108,8 @@ class FakeTime(interface.DateTimeValues):
if self._number_of_seconds is None:
return
if self._microseconds is not None:
return (self._number_of_seconds * 1000000) + self._microseconds
timestamp = self._number_of_seconds * definitions.MICROSECONDS_PER_SECOND
if self._microseconds is None:
return timestamp
return self._number_of_seconds * 1000000
return timestamp + self._microseconds
......@@ -90,7 +90,7 @@ class FATDateTime(interface.DateTimeValues):
raise ValueError('Seconds value out of bounds.')
number_of_seconds = (((hours * 60) + minutes) * 60) + seconds
number_of_seconds += number_of_days * self._SECONDS_PER_DAY
number_of_seconds += number_of_days * definitions.SECONDS_PER_DAY
return number_of_seconds
def CopyFromDateTimeString(self, time_string):
......@@ -152,8 +152,7 @@ class FATDateTime(interface.DateTimeValues):
number_of_days, hours, minutes, seconds = self._GetTimeValues(
self._number_of_seconds)
year, month, day_of_month = self._GetDateValues(
number_of_days, 1980, 1, 1)
year, month, day_of_month = self._GetDateValues(number_of_days, 1980, 1, 1)
return '{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}'.format(
year, month, day_of_month, hours, minutes, seconds)
......@@ -167,4 +166,5 @@ class FATDateTime(interface.DateTimeValues):
if self._number_of_seconds is None or self._number_of_seconds < 0:
return
return (self._number_of_seconds + self._FAT_DATE_TO_POSIX_BASE) * 1000000
return definitions.MICROSECONDS_PER_SECOND * (
self._number_of_seconds + self._FAT_DATE_TO_POSIX_BASE)
......@@ -67,9 +67,9 @@ class Filetime(interface.DateTimeValues):
self.timestamp = self._GetNumberOfSecondsFromElements(
year, month, day_of_month, hours, minutes, seconds)
self.timestamp += self._FILETIME_TO_POSIX_BASE
self.timestamp *= 1000000
self.timestamp *= definitions.MICROSECONDS_PER_SECOND
self.timestamp += date_time_values.get('microseconds', 0)
self.timestamp *= 10
self.timestamp *= self._100NS_PER_MICROSECOND
self.is_local_time = False
......@@ -84,7 +84,7 @@ class Filetime(interface.DateTimeValues):
self.timestamp > self._UINT64_MAX):
return None, None
timestamp, remainder = divmod(self.timestamp, 10000000)
timestamp, remainder = divmod(self.timestamp, self._100NS_PER_SECOND)
timestamp -= self._FILETIME_TO_POSIX_BASE
return timestamp, remainder
......@@ -99,7 +99,7 @@ class Filetime(interface.DateTimeValues):
self.timestamp > self._UINT64_MAX):
return
timestamp, remainder = divmod(self.timestamp, 10000000)
timestamp, remainder = divmod(self.timestamp, self._100NS_PER_SECOND)
number_of_days, hours, minutes, seconds = self._GetTimeValues(timestamp)
year, month, day_of_month = self._GetDateValues(
......@@ -118,5 +118,6 @@ class Filetime(interface.DateTimeValues):
self.timestamp > self._UINT64_MAX):
return
timestamp, _ = divmod(self.timestamp, 10)
return timestamp - (self._FILETIME_TO_POSIX_BASE * 1000000)
timestamp, _ = divmod(self.timestamp, self._100NS_PER_MICROSECOND)
return timestamp - (
self._FILETIME_TO_POSIX_BASE * definitions.MICROSECONDS_PER_SECOND)
......@@ -112,4 +112,4 @@ class HFSTime(interface.DateTimeValues):
return
timestamp = self.timestamp - self._HFS_TO_POSIX_BASE
return timestamp * 1000000
return timestamp * definitions.MICROSECONDS_PER_SECOND
......@@ -10,7 +10,7 @@ from dfdatetime import decorators
class DateTimeValues(object):
"""Defines the date time values interface.
"""Date time values interface.
This is the super class of different date and time representations.
......@@ -22,8 +22,13 @@ class DateTimeValues(object):
_DAYS_PER_MONTH = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
# The number of seconds in a day
_SECONDS_PER_DAY = 24 * 60 * 60
_100NS_PER_SECOND = 10000000
_100NS_PER_DECISECOND = 1000000
_100NS_PER_MILLISECOND = 10000
_100NS_PER_MICROSECOND = 10
_INT64_MIN = -(1 << 63)
_INT64_MAX = (1 << 63) - 1
def __init__(self):
"""Initializes date time values."""
......@@ -500,13 +505,13 @@ class DateTimeValues(object):
return 365
def _GetNumberOfSecondsFromElements(
self, year, month, day, hours, minutes, seconds):
self, year, month, day_of_month, hours, minutes, seconds):
"""Retrieves the number of seconds from the date and time elements.
Args:
year (int): year e.g. 1970.
month (int): month of year.
day(int): day of month.
day_of_month (int): day of month.
hours (int): hours.
minutes (int): minutes.
seconds (int): seconds.
......@@ -517,7 +522,7 @@ class DateTimeValues(object):
Raises:
ValueError: if the time elements are invalid.
"""
if not year or not month or not day:
if not year or not month or not day_of_month:
return
# calendar.timegm does not sanity check the time elements.
......@@ -537,9 +542,14 @@ class DateTimeValues(object):
elif seconds not in range(0, 60):
raise ValueError('Seconds value: {0!s} out of bounds.'.format(seconds))
# Note that calendar.timegm() does not raise when date is: 2013-02-29.
days_per_month = self._GetDaysPerMonth(year, month)
if day_of_month < 1 or day_of_month > days_per_month:
raise ValueError('Day of month value out of bounds.')
# calendar.timegm requires the time tuple to contain at least
# 6 integer values.
time_elements_tuple = (year, month, day, hours, minutes, seconds)
time_elements_tuple = (year, month, day_of_month, hours, minutes, seconds)
number_of_seconds = calendar.timegm(time_elements_tuple)
......
......@@ -23,8 +23,6 @@ class JavaTime(interface.DateTimeValues):
be one of the PRECISION_VALUES in definitions.
timestamp (int): Java timestamp.
"""
_INT64_MIN = -(1 << 63)
_INT64_MAX = (1 << 63) - 1
def __init__(self, timestamp=None):
"""Initializes a Java timestamp.
......@@ -60,10 +58,11 @@ class JavaTime(interface.DateTimeValues):
self.timestamp = self._GetNumberOfSecondsFromElements(
year, month, day_of_month, hours, minutes, seconds)
self.timestamp *= 1000
self.timestamp *= definitions.MILLISECONDS_PER_SECOND
if microseconds:
milliseconds, _ = divmod(microseconds, 1000)
milliseconds, _ = divmod(
microseconds, definitions.MILLISECONDS_PER_SECOND)
self.timestamp += milliseconds
self.is_local_time = False
......@@ -79,8 +78,9 @@ class JavaTime(interface.DateTimeValues):
self.timestamp > self._INT64_MAX):
return None, None
timestamp, milliseconds = divmod(self.timestamp, 1000)
return timestamp, milliseconds * 10000
timestamp, milliseconds = divmod(
self.timestamp, definitions.MILLISECONDS_PER_SECOND)
return timestamp, milliseconds * self._100NS_PER_MILLISECOND
def CopyToDateTimeString(self):
"""Copies the Java timestamp to a date and time string.
......@@ -93,7 +93,8 @@ class JavaTime(interface.DateTimeValues):
self.timestamp > self._INT64_MAX):
return
timestamp, milliseconds = divmod(self.timestamp, 1000)
timestamp, milliseconds = divmod(
self.timestamp, definitions.MILLISECONDS_PER_SECOND)
number_of_days, hours, minutes, seconds = self._GetTimeValues(timestamp)
year, month, day_of_month = self._GetDateValues(
......@@ -112,4 +113,4 @@ class JavaTime(interface.DateTimeValues):
self.timestamp > self._INT64_MAX):
return
return self.timestamp * 1000
return self.timestamp * definitions.MICROSECONDS_PER_MILLISECOND
# -*- coding: utf-8 -*-
"""OLE automation date (or Floatingtime or Application time) implementation."""
from __future__ import unicode_literals
from dfdatetime import definitions
from dfdatetime import interface
class OLEAutomationDate(interface.DateTimeValues):
"""OLE Automation date.
The OLE Automation date is a floating point value that contains the number of
days since 1899-12-30 (also known as the OLE Automation date epoch), and the
fractional part represents the fraction of a day since midnight. Negative
values represent date and times predating the OLE Automation date epoch.
Also see:
https://msdn.microsoft.com/en-us/library/system.datetime.tooadate(v=vs.110).aspx
Attributes:
is_local_time (bool): True if the date and time value is in local time.
precision (str): precision of the date and time value, which should
be one of the PRECISION_VALUES in definitions.
timestamp (float): OLE Automation date.
"""
# The difference between Dec 30, 1899 and Jan 1, 1970 in days.
_OLE_AUTOMATION_DATE_TO_POSIX_BASE = 25569
def __init__(self, timestamp=None):
"""Initializes an OLE Automation date.
Args:
timestamp (Optional[float]): OLE Automation date.
"""
super(OLEAutomationDate, self).__init__()
self.precision = definitions.PRECISION_1_MICROSECOND
self.timestamp = timestamp
def CopyFromDateTimeString(self, time_string):
"""Copies an OLE Automation date from a date and time string.
Args:
time_string (str): date and time value formatted as:
YYYY-MM-DD hh:mm:ss.######[+-]##:##
Where # are numeric digits ranging from 0 to 9 and the seconds
fraction can be either 3 or 6 digits. The time of day, seconds
fraction and time zone offset are optional. The default time zone
is UTC.
Raises:
ValueError: if the time string is invalid or not supported.
"""
date_time_values = self._CopyDateTimeFromString(time_string)
year = date_time_values.get('year', 0)
month = date_time_values.get('month', 0)
day_of_month = date_time_values.get('day_of_month', 0)
hours = date_time_values.get('hours', 0)
minutes = date_time_values.get('minutes', 0)
seconds = date_time_values.get('seconds', 0)
microseconds = date_time_values.get('microseconds', None)
timestamp = self._GetNumberOfSecondsFromElements(
year, month, day_of_month, hours, minutes, seconds)
timestamp = float(timestamp)
if microseconds is not None:
timestamp += float(microseconds) / definitions.MICROSECONDS_PER_SECOND
timestamp /= definitions.SECONDS_PER_DAY
timestamp += self._OLE_AUTOMATION_DATE_TO_POSIX_BASE
self.timestamp = timestamp
self.is_local_time = False
def CopyToStatTimeTuple(self):
"""Copies the OLE Automation date to a stat timestamp tuple.
Returns:
tuple[int, int]: a POSIX timestamp in seconds and the remainder in
100 nano seconds or (None, None) on error.
"""
if self.timestamp is None:
return None, None
timestamp = self.timestamp - self._OLE_AUTOMATION_DATE_TO_POSIX_BASE
timestamp *= definitions.SECONDS_PER_DAY
remainder = int((timestamp % 1) * self._100NS_PER_SECOND)
return int(timestamp), remainder
def CopyToDateTimeString(self):
"""Copies the OLE Automation date to a date and time string.
Returns:
str: date and time value formatted as:
YYYY-MM-DD hh:mm:ss.######
"""
if self.timestamp is None:
return
timestamp = self.timestamp * definitions.SECONDS_PER_DAY
number_of_days, hours, minutes, seconds = self._GetTimeValues(
int(timestamp))
year, month, day_of_month = self._GetDateValues(
number_of_days, 1899, 12, 30)
microseconds = int((timestamp % 1) * definitions.MICROSECONDS_PER_SECOND)
return '{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}.{6:06d}'.format(
year, month, day_of_month, hours, minutes, seconds, microseconds)
def GetPlasoTimestamp(self):
"""Retrieves a timestamp that is compatible with plaso.
Returns:
int: a POSIX timestamp in microseconds or None on error.
"""
if self.timestamp is None:
return
timestamp = self.timestamp - self._OLE_AUTOMATION_DATE_TO_POSIX_BASE
timestamp *= definitions.SECONDS_PER_DAY
timestamp *= definitions.MICROSECONDS_PER_SECOND
return int(timestamp)
......@@ -100,7 +100,7 @@ class PosixTime(interface.DateTimeValues):
if self.timestamp is None:
return
return self.timestamp * 1000000
return self.timestamp * definitions.MICROSECONDS_PER_SECOND
class PosixTimeInMicroseconds(interface.DateTimeValues):
......@@ -149,7 +149,7 @@ class PosixTimeInMicroseconds(interface.DateTimeValues):
self.timestamp = self._GetNumberOfSecondsFromElements(
year, month, day_of_month, hours, minutes, seconds)
self.timestamp *= 1000000
self.timestamp *= definitions.MICROSECONDS_PER_SECOND
self.timestamp += microseconds
self.is_local_time = False
......@@ -164,8 +164,9 @@ class PosixTimeInMicroseconds(interface.DateTimeValues):
if self.timestamp is None:
return None, None
timestamp, microseconds = divmod(self.timestamp, 1000000)
return timestamp, microseconds * 10
timestamp, microseconds = divmod(
self.timestamp, definitions.MICROSECONDS_PER_SECOND)
return timestamp, microseconds * self._100NS_PER_MICROSECOND
def CopyToDateTimeString(self):
"""Copies the POSIX timestamp to a date and time string.
......@@ -177,7 +178,8 @@ class PosixTimeInMicroseconds(interface.DateTimeValues):
if self.timestamp is None:
return
timestamp, microseconds = divmod(self.timestamp, 1000000)
timestamp, microseconds = divmod(
self.timestamp, definitions.MICROSECONDS_PER_SECOND)
number_of_days, hours, minutes, seconds = self._GetTimeValues(timestamp)
year, month, day_of_month = self._GetDateValues(
......
# -*- coding: utf-8 -*-
"""Date and time precision helpers."""
from __future__ import unicode_literals
from dfdatetime import definitions
class DateTimePrecisionHelper(object):
"""Date time precision helper interface.
This is the super class of different date and time precision helpers.
Time precision helpers provide functionality for converting date and time
values between different precisions.
"""
@classmethod
def CopyMicrosecondsToFractionOfSecond(cls, microseconds):
"""Copies the number of microseconds to a fraction of second value.
Args:
microseconds (int): number of microseconds.
Returns:
float: fraction of second, which must be a value between 0.0 and 1.0.
"""
raise NotImplementedError()
@classmethod
def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
"""Copies the time elements and fraction of second to a string.
Args:
time_elements_tuple (tuple[int, int, int, int, int, int]):
time elements, contains year, month, day of month, hours, minutes and
seconds.
fraction_of_second (float): fraction of second, which must be a value
between 0.0 and 1.0.
Returns:
str: date and time value formatted as: YYYY-MM-DD hh:mm:ss with fraction
of second part that corresponds to the precision.
"""
raise NotImplementedError()
class SecondsPrecisionHelper(DateTimePrecisionHelper):
"""Seconds precision helper."""
@classmethod
def CopyMicrosecondsToFractionOfSecond(cls, microseconds):
"""Copies the number of microseconds to a fraction of second value.
Args:
microseconds (int): number of microseconds.
Returns:
float: fraction of second, which must be a value between 0.0 and 1.0.
For the seconds precision helper this will always be 0.0.
Raises:
ValueError: if the number of microseconds is out of bounds.
"""
if microseconds < 0 or microseconds >= definitions.MICROSECONDS_PER_SECOND:
raise ValueError(
'Number of microseconds value: {0:d} out of bounds.'.format(
microseconds))
return 0.0
@classmethod
def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
"""Copies the time elements and fraction of second to a string.
Args:
time_elements_tuple (tuple[int, int, int, int, int, int]):
time elements, contains year, month, day of month, hours, minutes and
seconds.
fraction_of_second (float): fraction of second, which must be a value
between 0.0 and 1.0.
Returns:
str: date and time value formatted as:
YYYY-MM-DD hh:mm:ss
Raises:
ValueError: if the fraction of second is out of bounds.
"""
if fraction_of_second < 0.0 or fraction_of_second >= 1.0:
raise ValueError('Fraction of second value: {0:f} out of bounds.'.format(
fraction_of_second))
return '{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}'.format(
time_elements_tuple[0], time_elements_tuple[1], time_elements_tuple[2],
time_elements_tuple[3], time_elements_tuple[4], time_elements_tuple[5])
class MillisecondsPrecisionHelper(DateTimePrecisionHelper):
"""Milliseconds precision helper."""
@classmethod
def CopyMicrosecondsToFractionOfSecond(cls, microseconds):
"""Copies the number of microseconds to a fraction of second value.
Args:
microseconds (int): number of microseconds.
Returns:
float: fraction of second, which must be a value between 0.0 and 1.0.
Raises:
ValueError: if the number of microseconds is out of bounds.
"""
if microseconds < 0 or microseconds >= definitions.MICROSECONDS_PER_SECOND:
raise ValueError(
'Number of microseconds value: {0:d} out of bounds.'.format(
microseconds))
milliseconds, _ = divmod(
microseconds, definitions.MICROSECONDS_PER_MILLISECOND)
return float(milliseconds) / definitions.MILLISECONDS_PER_SECOND
@classmethod
def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
"""Copies the time elements and fraction of second to a string.
Args:
time_elements_tuple (tuple[int, int, int, int, int, int]):
time elements, contains year, month, day of month, hours, minutes and
seconds.
fraction_of_second (float): fraction of second, which must be a value
between 0.0 and 1.0.
Returns:
str: date and time value formatted as:
YYYY-MM-DD hh:mm:ss.###
Raises:
ValueError: if the fraction of second is out of bounds.
"""
if fraction_of_second < 0.0 or fraction_of_second >= 1.0:
raise ValueError('Fraction of second value: {0:f} out of bounds.'.format(
fraction_of_second))
milliseconds = int(fraction_of_second * definitions.MILLISECONDS_PER_SECOND)
return '{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}.{6:03d}'.format(
time_elements_tuple[0], time_elements_tuple[1], time_elements_tuple[2],
time_elements_tuple[3], time_elements_tuple[4], time_elements_tuple[5],
milliseconds)
class MicrosecondsPrecisionHelper(DateTimePrecisionHelper):
"""Microseconds precision helper."""
@classmethod
def CopyMicrosecondsToFractionOfSecond(cls, microseconds):
"""Copies the number of microseconds to a fraction of second value.
Args:
microseconds (int): number of microseconds.
Returns:
float: fraction of second, which must be a value between 0.0 and 1.0.
Raises:
ValueError: if the number of microseconds is out of bounds.
"""
if microseconds < 0 or microseconds >= definitions.MICROSECONDS_PER_SECOND:
raise ValueError(
'Number of microseconds value: {0:d} out of bounds.'.format(
microseconds))
return float(microseconds) / definitions.MICROSECONDS_PER_SECOND
@classmethod
def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
"""Copies the time elements and fraction of second to a string.
Args:
time_elements_tuple (tuple[int, int, int, int, int, int]):
time elements, contains year, month, day of month, hours, minutes and
seconds.
fraction_of_second (float): fraction of second, which must be a value
between 0.0 and 1.0.
Returns:
str: date and time value formatted as:
YYYY-MM-DD hh:mm:ss.######
Raises:
ValueError: if the fraction of second is out of bounds.
"""
if fraction_of_second < 0.0 or fraction_of_second >= 1.0:
raise ValueError('Fraction of second value: {0:f} out of bounds.'.format(
fraction_of_second))
microseconds = int(fraction_of_second * definitions.MICROSECONDS_PER_SECOND)
return '{0:04d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}.{6:06d}'.format(
time_elements_tuple[0], time_elements_tuple[1], time_elements_tuple[2],
time_elements_tuple[3], time_elements_tuple[4], time_elements_tuple[5],
microseconds)
class PrecisionHelperFactory(object):
"""Date time precision helper factory."""
_PRECISION_CLASSES = {
definitions.PRECISION_1_MICROSECOND: MicrosecondsPrecisionHelper,
definitions.PRECISION_1_MILLISECOND: MillisecondsPrecisionHelper,
definitions.PRECISION_1_SECOND: SecondsPrecisionHelper,
}
@classmethod
def CreatePrecisionHelper(cls, precision):
"""Creates a precision helper.
Args:
precision (str): precision of the date and time value, which should
be one of the PRECISION_VALUES in definitions.
Returns:
class: date time precision helper class.
Raises:
ValueError: if the precision value is unsupported.
"""
precision_helper_class = cls._PRECISION_CLASSES.get(precision, None)
if not precision_helper_class:
raise ValueError('Unsupported precision: {0!s}'.format(precision))