Skip to content

Commit

Permalink
Added support for centisecond and decimillisecond precisions (log2tim…
Browse files Browse the repository at this point in the history
  • Loading branch information
rick-slin authored May 4, 2024
1 parent 790074c commit 0ec1ef3
Show file tree
Hide file tree
Showing 4 changed files with 417 additions and 2 deletions.
6 changes: 6 additions & 0 deletions dfdatetime/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@

DECISECONDS_PER_SECOND = 10

CENTISECONDS_PER_SECOND = 100

MILLISECONDS_PER_SECOND = 1000

DECIMICROSECONDS_PER_SECOND = 10000

MICROSECONDS_PER_DAY = 86400000000
MICROSECONDS_PER_SECOND = 1000000
MICROSECONDS_PER_DECISECOND = 100000
Expand All @@ -23,7 +27,9 @@
NANOSECONDS_PER_DAY = 86400000000000
NANOSECONDS_PER_SECOND = 1000000000
NANOSECONDS_PER_DECISECOND = 100000000
NANOSECONDS_PER_CENTISECOND = 10000000
NANOSECONDS_PER_MILLISECOND = 1000000
NANOSECONDS_PER_DECIMILISECOND = 100000
NANOSECONDS_PER_MICROSECOND = 1000

PRECISION_1_DAY = '1d'
Expand Down
117 changes: 115 additions & 2 deletions dfdatetime/precisions.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ def CopyNanosecondsToFractionOfSecond(cls, nanoseconds):
nanoseconds (int): number of nanoseconds.
Returns:
decimal.Decimal: fraction of second, which must be a value between 0.0
and 1.0.
decimal.Decimal: fraction of second, which must be a value between 0.0 and
1.0.
"""
raise NotImplementedError()

Expand Down Expand Up @@ -99,6 +99,60 @@ def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
f'{hours:02d}:{minutes:02d}:{seconds:02d}')


class CentisecondsPrecisionHelper(DateTimePrecisionHelper):
"""Centiseconds (10 ms) precision helper."""

@classmethod
def CopyNanosecondsToFractionOfSecond(cls, nanoseconds):
"""Copies the number of nanoseconds to a fraction of second value.
Args:
nanoseconds (int): number of nanoseconds.
Returns:
decimal.Decimal: fraction of second, which must be a value between 0.0 and
1.0.
Raises:
ValueError: if the number of nanoseconds is out of bounds.
"""
if nanoseconds < 0 or nanoseconds >= definitions.NANOSECONDS_PER_SECOND:
raise ValueError(
f'Number of nanoseconds value: {nanoseconds:d} out of bounds.')

centiseconds, _ = divmod(
nanoseconds, definitions.NANOSECONDS_PER_CENTISECOND)
return decimal.Decimal(centiseconds) / definitions.CENTISECONDS_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 (decimal.Decimal): 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(
f'Fraction of second value: {fraction_of_second:f} out of bounds.')

year, month, day_of_month, hours, minutes, seconds = time_elements_tuple
centiseconds = int(fraction_of_second * definitions.CENTISECONDS_PER_SECOND)

return (f'{year:04d}-{month:02d}-{day_of_month:02d} '
f'{hours:02d}:{minutes:02d}:{seconds:02d}.{centiseconds:02d}')


class MillisecondsPrecisionHelper(DateTimePrecisionHelper):
"""Milliseconds precision helper."""

Expand Down Expand Up @@ -153,6 +207,63 @@ def CopyToDateTimeString(cls, time_elements_tuple, fraction_of_second):
f'{hours:02d}:{minutes:02d}:{seconds:02d}.{milliseconds:03d}')


class DecimillisecondsPrecisionHelper(DateTimePrecisionHelper):
"""Decimilliseconds (100 microseconds) precision helper."""

@classmethod
def CopyNanosecondsToFractionOfSecond(cls, nanoseconds):
"""Copies the number of nanoseconds to a fraction of second value.
Args:
nanoseconds (int): number of nanoseconds.
Returns:
decimal.Decimal: fraction of second, which must be a value between 0.0
and 1.0.
Raises:
ValueError: if the number of nanoseconds is out of bounds.
"""
if nanoseconds < 0 or nanoseconds >= definitions.NANOSECONDS_PER_SECOND:
raise ValueError(
f'Number of nanoseconds value: {nanoseconds:d} out of bounds.')

decimiliseconds, _ = divmod(
nanoseconds, definitions.NANOSECONDS_PER_DECIMILISECOND)
return (
decimal.Decimal(decimiliseconds) /
definitions.DECIMICROSECONDS_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 (decimal.Decimal): 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(
f'Fraction of second value: {fraction_of_second:f} out of bounds.')

year, month, day_of_month, hours, minutes, seconds = time_elements_tuple
decimicroseconds = int(
fraction_of_second * definitions.DECIMICROSECONDS_PER_SECOND)

return (f'{year:04d}-{month:02d}-{day_of_month:02d} '
f'{hours:02d}:{minutes:02d}:{seconds:02d}.{decimicroseconds:04d}')


class MicrosecondsPrecisionHelper(DateTimePrecisionHelper):
"""Microseconds precision helper."""

Expand Down Expand Up @@ -263,6 +374,8 @@ class PrecisionHelperFactory(object):
"""Date time precision helper factory."""

_PRECISION_CLASSES = {
definitions.PRECISION_10_MILLISECONDS: CentisecondsPrecisionHelper,
definitions.PRECISION_100_MICROSECONDS: DecimillisecondsPrecisionHelper,
definitions.PRECISION_1_MICROSECOND: MicrosecondsPrecisionHelper,
definitions.PRECISION_1_MILLISECOND: MillisecondsPrecisionHelper,
definitions.PRECISION_1_NANOSECOND: NanosecondsPrecisionHelper,
Expand Down
57 changes: 57 additions & 0 deletions tests/precisions.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,35 @@ def testCopyToDateTimeString(self):
precision_helper.CopyToDateTimeString((2018, 1, 2, 19, 45, 12), 4.123456)


class CentisecondsPrevisionHelperTest(unittest.TestCase):
"""Tests for the centiseconds prevision helper."""

def testCopyNanosecondsToFractionOfSecond(self):
"""Tests the CopyNanosecondsToFractionOfSecond function."""
precision_helper = precisions.CentisecondsPrecisionHelper

fraction_of_second = precision_helper.CopyNanosecondsToFractionOfSecond(
123456789)
self.assertEqual(fraction_of_second, decimal.Decimal('0.12'))

with self.assertRaises(ValueError):
precision_helper.CopyNanosecondsToFractionOfSecond(-1)

with self.assertRaises(ValueError):
precision_helper.CopyNanosecondsToFractionOfSecond(1000000000)

def testCopyToDateTimeString(self):
"""Tests the CopyToDateTimeString function."""
precision_helper = precisions.CentisecondsPrecisionHelper

date_time_string = precision_helper.CopyToDateTimeString(
(2018, 1, 2, 19, 45, 12), 0.123456)
self.assertEqual(date_time_string, '2018-01-02 19:45:12.12')

with self.assertRaises(ValueError):
precision_helper.CopyToDateTimeString((2018, 1, 2, 19, 45, 12), 4.123456)


class MillisecondsPrecisionHelperTest(unittest.TestCase):
"""Tests for the milliseconds precision helper."""

Expand Down Expand Up @@ -85,6 +114,34 @@ def testCopyToDateTimeString(self):
precision_helper.CopyToDateTimeString((2018, 1, 2, 19, 45, 12), 4.123456)


class DeciMillisecondsPrevisionHelperTest(unittest.TestCase):
"""Tests for the decimilliseconds precision helper."""
def testCopyNanosecondsToFractionOfSecond(self):
"""Tests the CopyNanosecondsToFractionOfSecond function."""
precision_helper = precisions.DecimillisecondsPrecisionHelper

fraction_of_second = precision_helper.CopyNanosecondsToFractionOfSecond(
123456789)
self.assertEqual(fraction_of_second, decimal.Decimal('0.1234'))

with self.assertRaises(ValueError):
precision_helper.CopyNanosecondsToFractionOfSecond(-1)

with self.assertRaises(ValueError):
precision_helper.CopyNanosecondsToFractionOfSecond(1000000000)

def testCopyToDateTimeString(self):
"""Tests the CopyToDateTimeString function."""
precision_helper = precisions.DecimillisecondsPrecisionHelper

date_time_string = precision_helper.CopyToDateTimeString(
(2018, 1, 2, 19, 45, 12), 0.123456)
self.assertEqual(date_time_string, '2018-01-02 19:45:12.1234')

with self.assertRaises(ValueError):
precision_helper.CopyToDateTimeString((2018, 1, 2, 19, 45, 12), 4.123456)


class MicrosecondsPrecisionHelperTest(unittest.TestCase):
"""Tests for the microseconds precision helper."""

Expand Down
Loading

0 comments on commit 0ec1ef3

Please sign in to comment.