time_tracker 1.1.1 copy "time_tracker: ^1.1.1" to clipboard
time_tracker: ^1.1.1 copied to clipboard

A Dart object that records time-status changes and can be started, paused, resumed, and ended.

Time Tracker #

Dart

Introduction #

A commonly required task consists in recording the time a process starts, is paused/resumed, and the time it is completed. An object of type TimeTracker is designed to perform this job. It is similar to a StopWatch, however instead of elapsed ticks it records a DateTime point whenever its status changes.

The image below shows the available states (blue font) defined by the enum TimeStatus and available transitions (orange arrows) defined by the class TimeTracker.

TimeStatus

Status changing methods are printed with green font. Calling a status changing method where there is no transition defined has no effect. For example: calling the method end() when the object has status TimeStatus.ready has no effect.

In addition to methods for recording time points, the mixin TimeTracker provides helper methods for json-serialization. It is recommended that classes with TimeTracker override the equality operator such that a deserialized object will compare equal to the original object.

Usage #

To use this library include time_tracker as a dependency in your pubspec.yaml file.

The example below shows how to construct an object of type TennisMatch with the mixin TimeTracker. The object records its own time points. Note: The getter hashCode and the equality operator are overriden so that decoded objects are equal when compared with the original object.

import 'package:exception_templates/exception_templates.dart';
import 'package:time_tracker/time_tracker.dart';

/// Demonstrates how to use TimeTracker.
class TennisMatch with TimeTracker {
  final List<String> players;

  /// Note the use of the constructor `super.startNow()`.
  /// This creates an instance of TennisMatch with status: started
  /// and records the instantiation time as the first time point.
  TennisMatch(List<String> players) : players = List.of(players);

  /// Constructs an object from a json map.
  factory TennisMatch.fromJson(Map<String, Object?> json) {
    if (json case {'players': List players}) {
      // Use `initTrackerfromJson` to initializer the time tracker.
      return TennisMatch(players.cast<String>())..initTrackerfromJson(json);
    } else {
      throw ErrorOf<TennisMatch>(
        message: 'Error in TennisMatch.fromJson',
        invalidState: ' Found map: $json',
      );
    }
  }

  @override
  Map<String, Object?> toJson() {
    // Providing the entries related to the time tracker.
    final json = trackerToJson();
    // Adding the rest of the entries.
    json['players'] = players;
    return json;
  }

  @override
  int get hashCode => Object.hash(trackerHashCode, players);

  /// Returns `true` if the two instances have the same time status,
  /// time points, and player list.
  @override
  bool operator ==(Object other) {
    return other is TennisMatch &&
        players.equal(other.players) &&
        trackerEqual(other);
  }

  @override
  String toString() {
    return 'TennisMatch: players: $players | status: ${status.name} '
        '| duration: $duration';
  }
}

The program below demonstrates how to use an object of type TennisMatch to start, pause, resume, and end the match. It also shows how to serialize and deserialize the object using 'dart:convert'.

void main() async {
  /// Create object (start time is recorded)
  final match = TennisMatch(['Tim', 'Andy']);
  print('----- Create an object of type TennisMatch -----');
  print(match);
  match.start();

  print('Status: ${match.status.name} at: ${match.startTime}');
  await Future.delayed(const Duration(milliseconds: 3), () {
    // Pause object
    match.pause();
    print('Status: ${match.status.name} at: ${match.lastTimePoint}');
  });

  await Future.delayed(const Duration(milliseconds: 1), () {
    // Resume object
    match.resume();
    print('Status: ${match.status.name} at: ${match.lastTimePoint}');
  });

  await Future.delayed(const Duration(milliseconds: 2), () {
    // Mark object as ended.
    match.end();
    print('Status: ${match.status.name} at: ${match.lastTimePoint}');
  });

  print('');
  print('---------- Json Encoding -------------');
  final jsonString = jsonEncode(match);
  print('Serialized object:');
  print(jsonString);

  var decodedMatch = TennisMatch.fromJson(jsonDecode(jsonString));
  print('');
  print('Deserialized object:');
  print(decodedMatch);

  print('');
  print('match == decodedMatch: ${match == decodedMatch}');
}
Click to show the console output.
$ dart example/bin/time_tracker_example.dart

$ dart example/bin/time_tracker_example.dart
----- Create an object of type TennisMatch -----
TennisMatch: players: [Tim, Andy] | status: ready | duration: 0:00:00.000000

Status: started at: 2025-10-09 23:53:16.841832
Status: paused at: 2025-10-09 23:53:19.854479
Status: resumed at: 2025-10-09 23:53:20.858332
Status: ended at: 2025-10-09 23:53:22.859459

---------- Json Encoding -------------
Serialized object:
{"status":{"timeStatus":"ended"},"timePoints":[1760050396841832,1760050399854479,1760050400858332,1760050402859459],"players":["Tim","Andy"]}

Deserialized object:
TennisMatch: players: [Tim, Andy] | status: ended | duration: 0:00:05.013774

match == decodedMatch: true

Example #

The source code of the program shown above can be found in the folder example.

Features and bugs #

Please file feature requests and bugs at the issue tracker.

3
likes
160
points
215
downloads

Publisher

verified publishersimphotonics.com

Weekly Downloads

A Dart object that records time-status changes and can be started, paused, resumed, and ended.

Repository (GitHub)
View/report issues

Topics

#time-tracking #duration #time-log #pause #resume

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

exception_templates, serialize_enum

More

Packages that depend on time_tracker