Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT added support for centiseconds in the TimeElementsWithFractionOfSeconds #282

Merged
merged 5 commits into from
May 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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