scribeGriff Studios

Books • Algorithms • Dart • HTML5 • CSS3

To content | To menu | To search

Keeping Time with Dart - The Stopwatch, DateTime and Timer Classes

All that really belongs to us is time; even he who has nothing else has that. - Baltasar Gracian

Time is free, but it's priceless. You can't own it, but you can use it. You can't keep it, but you can spend it. Once you've lost it, you can never get it back. - Harvey Mackay

It was the best of times, it was the worst of times... - Charles Dickens

Time cannot be absolutely defined, and there is an inseparable relation between time and signal velocity. - Albert Einstein

Introduction


The ability to determine time of day, the date, or to calculate elapsed time is just one of several fundamental capabilities to be found in just about every modern programming language. We frequently need to answer the question "when did this event happen?" or "how long has it been since this other event happened?". Dart's [1] time keeping methodology is divided among the Stopwatch, DateTime and Timer classes. In this article, we'll take a look at each one, starting with the Stopwatch class.

The Stopwatch Class

Methods provided by the Stopwatch class, which is in the dart:core library, include a reset() method as well as a technique to start the watch as soon as it is instantiated, if desired. You may start, stop and reset the stopwatch instance as necessary depending on your application. The following code snippets show some different ways of instantiating a Stopwatch provided for illustration purposes (note the double period is a method cascade used in this case when it is desired to start the watch as soon as it is instantiated):

// Declare a global variable watch of type Stopwatch
class KeepingTime {
  Stopwatch watch;

  // instantiate and start the watch in the constructor method
  KeepingTime() {
    watch = new Stopwatch..start();
    //etc

or establishing methods to start, stop and reset:

class KeepingTime {
  Stopwatch watch;

  KeepingTime() {
    watch = new Stopwatch();
  }

  startWatch() {
    watch.start();
  }

  stopWatch() {
    watch.stop();
  }

  resetWatch() {
    watch.reset();
  }
  // etc

The following example implements a simple 2 second delay and outputs information regarding the delay to a browser window. Note that we have embedded our watch expressions directly within the string literals using string interpolation with ${expression}:

import 'dart:html';

class KeepingTime {
  Stopwatch watch;

  KeepingTime() {
    watch = new Stopwatch();
  }

  void delay2s() {
    watch.start();
    while (watch.elapsedMilliseconds < 2000);
    watch.stop();
    var s1 = "The watch frequency is ${watch.frequency}<br>";
    var s2 = "The number of clock ticks since start was called is "
        "${watch.elapsedTicks} ticks<br>";
    var s3 = "The elapsed time in msecs is ${watch.elapsedMilliseconds} ms<br>";
    var s4 = "The elapsed time in usecs is ${watch.elapsedMicroseconds} us<br>";
    watch.reset();
    var s5 = "We have reset the watch:<br>";
    var s6 = "Now the number of ticks is ${watch.elapsedTicks}.<br>";
    var s = "$s1 $s2 $s3 $s4 $s5 $s6";
    write(s);
  }

  void write(String message) {
    querySelector('#text').appendHtml(message);
  }
}

void main() {
  new KeepingTime().delay2s();
}

In a browser window, we get the following output:

The watch frequency is 1000000 hz
The number of clock ticks since start was called is 2000000 ticks
The elapsed time in msecs is 2000 ms
The elapsed time in usecs is 2000000 us
We have reset the watch:
Now the number of ticks is 0.

Keep in mind that resetting the watch neither starts nor stops it, it merely resets the elapsed count to zero.

The next technique we would like to cover for keeping time with Dart is the DateTime class.

The DateTime Class

The DateTime class is an abstract class that implements Comparable and comes with a robust set of methods and constructors. We can, for example, construct a new DateTime instance with the current date time value. The timeZone of this instance is set to the local time-zone by default.

DateTime creationTime = new DateTime.now();
print("Right this millisecond, the time is $creationTime");
print("and we're in the '${creationTime.timeZoneName}' time zone.");

// Outputs:
//Right this millisecond, the time is 2012-10-16 20:52:55.295
//and we're in the 'Central Daylight Time' time zone.

Some additional examples of the DateTime class in Dart:

print(new DateTime(1970, 1, 1, 0, 0, 0, 0));
print(new DateTime.fromMillisecondsSinceEpoch(0));
print(new DateTime.now().difference(new DateTime.fromMillisecondsSinceEpoch(0)));
print("${((new DateTime.now().difference(new DateTime.fromMillisecondsSinceEpoch(0))).inDays).toString()} days since epoch.");

// Outputs:
//1970-01-01 00:00:00.000
//1969-12-31 18:00:00.000
//375122:22:17.746
//15630 days since epoch.

Notice the last two print statements. We have made use of the Difference method of the DateTime class to return a value of type Duration representing the time span from epoch to the current time. The Duration class has a number of useful fields. In the last print statement, for example, we convert the duration since epoch, returned as hours:minutes:seconds:milliseconds to days. We then employ the toString() method from the DateTime interface to allow us to combine the calculated number of days (of type Number) to a string.

This next example may be a bit contrived, but it does bring together a couple of the methods that we have just talked about. Let's say we want to know the "age" of an instance at some given time in the future relative to the time in which it was created. We could monitor elapsed time by using a watch created with the Stopwatch class which starts when we create our instance, similar to an example we explored earlier. An alternative approach might be to use the DateTime class in the following manner:

// We've just created an instance of something 
// that we'd like to track its age so we
// will also create a new Date at the same moment.
DateTime creationTime = new DateTime.now();
// Then, at any point in the future, we can determine 
// the age of our instance as follows:
var age = new DateTime.now().difference(creationTime);
print("My instance is now ${age.inHours} hrs old");

The duration class also has fields inDays, inMinutes, inSeconds and in Milliseconds. In order to demonstrate our example, though, we will have to simulate the passage of time and for that, we will use a watch:

DateTime creationTime = new DateTime.now();
Stopwatch watch = new Stopwatch()..start();
while (watch.elapsedMilliseconds < 5000);
watch.stop();
var age = new DateTime.now().difference(creationTime);
print("The age of your instance is ${age.inMilliseconds/1000} secs.");
//Outputs:
//The age of your instance is 5.0 secs.

Note that duration can have a negative value. Before we move on to the Timer class, here is an example of a simple class that provides a time stamp of the form:

  • Long: 9:56pm Tue 16-Oct-2012
  • Short: 9:56pm 10/16/2012

You can call the class as follows:

// To return the long form:
String timeStamp = new TimeStamp().stamp();
// To return the short form:
String timeStamp = new TimeStamp().stamp(true);

Here's the class:

// HashMap class resides in Dart's collection library.
import 'dart:collection';

class TimeStamp {

  HashMap months = new HashMap();
  HashMap weekdays = new HashMap();
  DateTime currentTime = new DateTime.now();
  int year, month, day, hour, minute, weekday;

  TimeStamp() {
    year = currentTime.year;
    month = currentTime.month;
    day = currentTime.day;
    hour = currentTime.hour;
    minute = currentTime.minute;
    weekday = currentTime.weekday;

    months[1] = 'Jan';
    months[2] = 'Feb';
    months[3] = 'Mar';
    months[4] = 'Apr';
    months[5] = 'May';
    months[6] = 'Jun';
    months[7] = 'Jul';
    months[8] = 'Aug';
    months[9] = 'Sep';
    months[10] = 'Oct';
    months[11] = 'Nov';
    months[12] = 'Dec';

    weekdays[1] = 'Mon';
    weekdays[2] = 'Tue';
    weekdays[3] = 'Wed';
    weekdays[4] = 'Thu';
    weekdays[5] = 'Fri';
    weekdays[6] = 'Sat';
    weekdays[7] = 'Sun';
  }

  String stamp([bool short = false]) {
    String timeStamp;
    String meridian;
    String minutes = minute < 10 ? '0$minute' : '$minute';

    if (hour >= 12) {
      if (hour > 12) hour -= 12;
      meridian = 'pm';
    } else {
      meridian = 'am';
    }

    if (short) {
      return timeStamp = '$hour:$minutes$meridian $month/$day/$year';
    } else {
      return timeStamp = '$hour:$minutes$meridian ${weekdays[weekday]} '
          '$day-${months[month]}-$year';
    }
  }
}

Dart also has a DateFormat class that is accessible through hosted package intl. Just add the intl package to your pubspec.yaml file. To use this method to add a date stamp, you can simply do the following:

import 'package:intl/intl.dart';
void main() {
  var now = new DateTime.now();
  var timeStamp = new DateFormat("h:mma EEE d-MMM-yyyy");
  String formatTime = timeStamp.format(now);
  print(formatTime);
}

Prints the formatted time as:

  • 1:54PM Mon 22-Apr-2013

Refer to the API reference for a complete list of format options, or, for an additional example, take a look at this question on stackoverflow.

Method Execution using a Timer

Dart now has a Timer class available through the dart:async library for both client and server applications. The class provides two factory constructors:

  • factory Timer(duration, Function callback): Creates a new timer. The callback is invoked after a given duration has passed.
  • factory Timer.periodic(duration, void callback(Timer timer)): Creates a new repeating timer. The callback is invoked repeatedly after a given duration has passed until cancelled.

There is static method run() which enables an asynchronous one-shot execution of a callback as well as an abstract method cancel() for cancelling the repeating timer. An example of using the timer to repeatedly execute a method in a class is as follows:

import 'dart:html';
import 'dart:async';

class progressMonitor {
  static const scaleRate = 100;
  static const finished = 90;
  DateTime startTime = new DateTime.now();
  Timer timer;
  var progress;

  progressMonitor()
      : progress = 0;

  void startMonitor() {
    const interval = 1000;
    const progressRate = const Duration(milliseconds:interval);
    querySelector('#text').appendHtml("I'm never going to finish this project."
        "  I'm only now starting!<br>");
    timer = new Timer.periodic(progressRate, (Timer timer) => runMonitor(interval));
  }

  void runMonitor(var interval) {
    var s, s1, s2;
   if (progress >= finished) {
      timer.cancel();
      var finishTime = new DateTime.now();
      var hours = finishTime.hour;
      var minutes = finishTime.minute;
      var seconds = finishTime.second;
      hours > 12 ? hours -= 12 : hours;
      s1 = "Yay! I'm all done and it's only $minutes minutes after $hours, "
          "give or take about $seconds seconds.<br>";
      s2 = "In fact, it only took ${finishTime.difference(startTime).inSeconds}"
          " seconds to finish.  Well, that wasn't so bad!<br>";
      s = "$s1 $s2";
    } else {
      progress += progressRate / scaleRate;
      s = "I'm never going to finish this project.  "
          "I'm only $progress% done with it.<br>";
    }
    write(s);
  }

  void write(String message) {
    querySelector('#text').appendHtml(message);
  }
}

void main() {
  new progressMonitor().startMonitor();
}

The program prints the following in a browser window:

I'm never going to finish this project. I'm only now starting!
I'm never going to finish this project. I'm only 10% done with it.
I'm never going to finish this project. I'm only 20% done with it.
I'm never going to finish this project. I'm only 30% done with it.
I'm never going to finish this project. I'm only 40% done with it.
I'm never going to finish this project. I'm only 50% done with it.
I'm never going to finish this project. I'm only 60% done with it.
I'm never going to finish this project. I'm only 70% done with it.
I'm never going to finish this project. I'm only 80% done with it.
I'm never going to finish this project. I'm only 90% done with it.
Yay! I'm all done and it's only 48 minutes after 9, give or take about 24 seconds.
In fact, it only took 10 seconds to finish. Well, that wasn't so bad!

For more examples of running a reoccurring function in Dart, check out Seth Ladd's answer on stackoverflow.


Acknowledgements

Thanks to Florian Loitsch for suggestions on the use of the Stopwatch class.


Works Cited

[1] Dart's Homepage

submit to reddit
Google+
Richard Griffith

Author: Richard Griffith

Keep in touch with the latest updates. Subscribe to the RSS Feed for this category.

Comments (0)

Be the first to comment on this article

Add a comment This post's comments feed

no attachment



You might also like

angular-and-dart-iconj.jpg

Today's @NgDirective: Get Up to Speed Using Angular with Dart

Although I spend most of my time working with Dart using Polymer, it's hard not to find the announcement of AngularDart a compelling reason to take it out for a spin. And I confess, the more I use Angular with Dart, the more I'm convinced it is going to be a major component of my Dart toolbox for the foreseeable future. I had come across Jesus Rodriguez's introduction to the model driven framework with his appropriately named blog post Why Does Angular.js Rock?. In this article, we look at the Dart equivalents of the examples Jesus presented.

Continue reading

future-word-cloud-dart.png

Iterables, Futures, and Future.wait() in Dart

Several days ago while working with Dart, I was coding up a problem that required that I iterate over a function that returns its value represented as a Future. The variables that I needed to pass to this function were read from an external file and stored in a List using a Stream. To evaluate the function for each element in the List, I was tempted to use a simple forEach() to pass the elements to the function returning a Future. But I was soon going to discover a much better way for dealing with a scenario such as this.

Continue reading