Skip to content

Commit

Permalink
* **Fix:** Fixed 23.98, 29.97 DF, 29.97 NDF, 59.94 and 59.94 NDF roll…
Browse files Browse the repository at this point in the history
…over to ``00:00:00:00`` after 24 hours.
  • Loading branch information
eoyilmaz committed Feb 3, 2021
1 parent ab3de5e commit bde8463
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 33 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
Changes
=======

1.3.1
=====

* **Fix:** Fixed 23.98, 29.97 DF, 29.97 NDF, 59.94 and 59.94 NDF rollover to ``00:00:00:00`` after 24 hours.

1.3.0
=====

Expand Down
71 changes: 48 additions & 23 deletions tests/test_timecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,30 +418,10 @@ def test_timecode_init_16(self):
self.assertEqual('00:08:19:23', tc.__str__())

def test_timecode_init_17(self):
tc = Timecode('29.97', frames=2589408)
self.assertEqual('23:59:59;29', tc.__str__())

def test_timecode_init_18(self):
tc = Timecode('29.97', frames=2589409)
self.assertEqual('00:00:00;00', tc.__str__())

def test_timecode_init_19(self):
tc = Timecode('29.97', frames=2589409, force_non_drop_frame=True)
self.assertEqual('00:00:00:00', tc.__str__())

def test_timecode_init_20(self):
tc = Timecode('59.94', frames=5178816)
self.assertEqual('23:59:59;59', tc.__str__())

def test_timecode_init_21(self):
tc = Timecode('59.94', frames=5178817)
self.assertEqual('00:00:00;00', tc.__str__())

def test_timecode_init_22(self):
tc = Timecode('25', 421729315)
self.assertEqual('19:23:14:23', tc.__str__())

def test_timecode_init_23(self):
def test_timecode_init_18(self):
tc = Timecode('29.97', 421729315)
self.assertEqual('19:23:14;23', tc.__str__())
self.assertTrue(tc.drop_frame)
Expand Down Expand Up @@ -1214,9 +1194,13 @@ def test_op_overloads_mult_8(self):
tc3 = tc * tc2
tc4 = tc * 720
self.assertEqual(224121600, tc3._frames)
self.assertEqual("04:09:35:23", tc3.__str__())
self.assertEqual("01:59:59:23", tc3.__str__())
self.assertEqual(224121600, tc4._frames)
self.assertEqual("04:09:35:23", tc4.__str__())
self.assertEqual("01:59:59:23", tc4.__str__())
tc5 = Timecode('23.98', frames=311280 * 720) # should equal to this amount of frames
self.assertEqual("01:59:59:23", tc5.__str__())
tc5 = Timecode('23.98', frames=172800) # should equal to this amount of frames
self.assertEqual("01:59:59:23", tc5.__str__())

def test_op_overloads_mult_9(self):
tc = Timecode('ms', '03:36:09.230')
Expand Down Expand Up @@ -1725,3 +1709,44 @@ def test_fraction_lib_from_python3_raises_import_error_for_python2(self):
with mock.patch.dict(sys.modules, {'fractions': None}):
# the coverage should be now 100%
tc = Timecode('24')

def test_rollover_for_23_98(self):
"""test for bug report #33
"""
tc = Timecode('23.98', '23:58:47:00')
self.assertEqual(2071849, tc.frames)
tc.add_frames(24)
self.assertEqual(2071873, tc.frames)
self.assertEqual('23:58:48:00', tc.__repr__())

def test_rollover_for_29_97_1(self):
tc = Timecode('29.97', frames=2589408)
self.assertEqual('23:59:59;29', tc.__str__())

def test_rollover_for_29_97_2(self):
tc = Timecode('29.97', frames=2589409)
self.assertEqual('00:00:00;00', tc.__str__())

def test_rollover_for_29_97_3(self):
tc = Timecode('29.97', frames=2589409, force_non_drop_frame=True)
self.assertEqual('23:58:33:18', tc.__str__())

def test_rollover_for_29_97_4(self):
tc = Timecode('29.97', frames=2592001, force_non_drop_frame=True)
self.assertEqual('00:00:00:00', tc.__str__())

def test_rollover_for_59_94_DF_1(self):
tc = Timecode('59.94', frames=5178816)
self.assertEqual('23:59:59;59', tc.__str__())

def test_rollover_for_59_94_DF_2(self):
tc = Timecode('59.94', frames=5178817)
self.assertEqual('00:00:00;00', tc.__str__())

def test_rollover_for_59_94_NDF_1(self):
tc = Timecode('59.94', frames=5184000, force_non_drop_frame=True)
self.assertEqual('23:59:59:59', tc.__str__())

def test_rollover_for_59_94_NDF_2(self):
tc = Timecode('59.94', frames=5184001, force_non_drop_frame=True)
self.assertEqual('00:00:00:00', tc.__str__())
18 changes: 8 additions & 10 deletions timecode/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

__version__ = '1.3.0'
__version__ = '1.3.1'


class Timecode(object):
Expand Down Expand Up @@ -126,7 +126,6 @@ def framerate(self, framerate): # lint:ok
:param framerate:
:return:
"""

# Convert rational frame rate to float
numerator = None
denominator = None
Expand Down Expand Up @@ -260,21 +259,21 @@ def frames_to_tc(self, frames):
:returns str: the string representation of the current time code
"""
ffps = float(self.framerate)

if self.drop_frame:
# Number of frames to drop on the minute marks is the nearest
# integer to 6% of the framerate
ffps = float(self.framerate)
drop_frames = int(round(ffps * .066666))
else:
ffps = float(self._int_framerate)
drop_frames = 0

# Number of frames in an hour
frames_per_hour = int(round(ffps * 60 * 60))
# Number of frames in a day - timecode rolls over after 24 hours
frames_per_24_hours = frames_per_hour * 24
# Number of frames per ten minutes
frames_per_10_minutes = int(round(ffps * 60 * 10))

# Number of frames in a day - timecode rolls over after 24 hours
frames_per_24_hours = int(round(ffps * 60 * 60 * 24))

# Number of frames per minute is the round of the framerate * 60 minus
# the number of dropped frames
frames_per_minute = int(round(ffps) * 60) - drop_frames
Expand All @@ -289,8 +288,7 @@ def frames_to_tc(self, frames):
d = frame_number // frames_per_10_minutes
m = frame_number % frames_per_10_minutes
if m > drop_frames:
frame_number += (drop_frames * 9 * d) + \
drop_frames * ((m - drop_frames) // frames_per_minute)
frame_number += (drop_frames * 9 * d) + drop_frames * ((m - drop_frames) // frames_per_minute)
else:
frame_number += drop_frames * 9 * d

Expand Down

0 comments on commit bde8463

Please sign in to comment.