Skip to content

Fix/asc writer timestamps format#2032

Open
Ju-Daeng-E wants to merge 7 commits intohardbyte:mainfrom
Ju-Daeng-E:fix/asc-writer-timestamps-format
Open

Fix/asc writer timestamps format#2032
Ju-Daeng-E wants to merge 7 commits intohardbyte:mainfrom
Ju-Daeng-E:fix/asc-writer-timestamps-format

Conversation

@Ju-Daeng-E
Copy link

@Ju-Daeng-E Ju-Daeng-E commented Feb 24, 2026

Summary of Changes

  • Added timestamps_format parameter to ASCWriter.__init__() ("absolute" or "relative", default "absolute")
  • The value is written into the base hex timestamps ... header line so external tools (CANalyzer, CANoe, etc.) can interpret the file correctly
  • Raises ValueError for unsupported values
  • No behaviour change for existing code — default is "absolute"

Related Issues / Pull Requests

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Refactoring
  • Other (please describe):

Checklist

  • I have added or updated documentation as appropriate.
  • I have followed the contribution guide.
  • I have added or updated tests as appropriate.
  • I have added a news fragment for towncrier.
  • All checks and tests pass (tox).

Additional Notes

The timestamps_format parameter only affects the header line.
The actual per-message timestamp values written by on_message_received()
are not modified — callers are responsible for passing appropriately scaled timestamps.

Allow callers to choose between 'absolute' (default, existing behaviour)
and 'relative' when creating an ASC log file. The value is written into
the 'base hex  timestamps ...' header line so that other tools
(CANalyzer, CANoe, etc.) can interpret the file correctly.

Closes hardbyte#2022
@zariiii9003
Copy link
Collaborator

You're changing the header, but not the actual timestamps. According to the documentation that is not correct:

timestamps indicates whether the timestamps are written absolute to the start of the measurement
or relative to the preceding event.

@Ju-Daeng-E
Copy link
Author

Thank you for the helpful feedback! I'll revisit the implementation and make sure the timestamp values are properly converted as well.

…ust header

Previously, log_event() always subtracted self.started from every timestamp
regardless of timestamps_format, meaning "relative" mode only changed the
header line while writing identical data to "absolute" mode.

Per the ASC format specification:
- "absolute": each timestamp is an offset from the start of measurement
- "relative": each timestamp is a delta from the preceding event

Fix log_event() to compute per-event deltas when timestamps_format="relative",
and update self.last_timestamp after each event so the next delta is correct.

Also add two tests that verify the actual values written to the file differ
between the two modes (3-message uneven spacing exposes the distinction at msg3:
absolute writes 1.0, relative writes 0.7).

Update changelog fragment to describe the semantic difference accurately.
for m in msgs:
writer.on_message_received(m)

with can.ASCReader(self.test_file_name, relative_timestamp=True) as reader:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instantiate the ASCReader with relative_timestamp=False. For the roundtrip tests i'd prefer to see the same timestamps as in the original messages.

can/io/asc.py Outdated
self,
file: StringPathLike | TextIO,
channel: int = 1,
timestamps_format: str = "absolute",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
timestamps_format: str = "absolute",
timestamps_format: Literal["absolute", "relative"] = "absolute",

can/io/asc.py Outdated
if self.timestamps_format == "absolute":
# offsets from the start of measurement
written_timestamp = (
timestamp - self.started if timestamp >= self.started else timestamp
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd simplify this: You can move timestamp = max(timestamp, self.last_timestamp) out of the if-clause.
Then inside of the if-else blocks you only have written_timestamp = timestamp - self.started and written_timestamp = timestamp - self.last_timestamp

Reviewer feedback received (zariiii9003):

1. Use Literal type hint for timestamps_format parameter
   - Changed: timestamps_format: str = "absolute"
   - To:      timestamps_format: Literal["absolute", "relative"] = "absolute"
   - Added Literal to typing imports

2. Simplify log_event timestamp computation
   - Moved monotonic clamp out of if/else blocks:
     timestamp = max(timestamp, self.last_timestamp)
   - Each branch now contains only simple arithmetic:
     absolute: written_timestamp = timestamp - self.started
     relative: written_timestamp = timestamp - self.last_timestamp

3. Use relative_timestamp=False in roundtrip tests
   - Updated test_write_relative_timestamp_roundtrip and
     test_write_absolute_timestamps_are_offsets_from_start to use
     relative_timestamp=False so assertions verify original message
     timestamps are recovered (100.0, 100.3, 101.0) rather than
     file-stored offsets (0.0, 0.3, 1.0)

Additional issues found and fixed during review:

4. Removed outdated TODO comment in ASCReader
   - Removed: "TODO - what is this used for? The ASC Writer only prints
     absolute" — no longer accurate since ASCWriter now supports both
     "absolute" and "relative" formats

5. Lowered assertAlmostEqual precision from places=5 to places=3
   - The datetime triggerblock roundtrip (fromtimestamp -> strftime ->
     strptime -> timestamp) only preserves millisecond precision due to
     the ".NNN" format. places=5 (5 microseconds) is stricter than what
     the format can guarantee; places=3 (0.5 ms) correctly reflects the
     actual precision limit. Verified empirically: sub-millisecond
     timestamps incur ~0.456 ms error which passes places=3 but fails
     places=5.

6. Updated docstrings for both modified roundtrip tests to accurately
   describe the new assertion semantics (original timestamp recovery)
@Ju-Daeng-E
Copy link
Author

The CI failures appear to be caused by a coveralls.io outage that has been ongoing since February 25th. I'll retry once the service is restored. Please let me know if there are any other parts of the implementation that need to be reviewed. Thank you for your feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: ASCWriter should support configurable timestamp format (absolute vs relative)

2 participants