Page 1 of 1

New timestamp class

Posted: Thu Jan 01, 2015 1:53 pm
by Administrator
Time is something we work with very often in our scripts, but has historically been a bit of a bother to manage cleanly. So, today, I decided to write up a class to handle it that is roughly based off Carbon for PHP.

To use this module, you need to require it at the top of your main script like so:

Code: Select all

require('timestamp');
This new class, Timestamp, supports method-chaining. That is, function calls to modify its time value will return a new object instead of actually modify the calling object. This means we can do something like this:

Code: Select all

local later = Timestamp:now():addhours(1):addMinutes(30);
This will give us a Timestamp object that is 'now' plus an hour and a half. It also supports adding/subtracting everything else you could want: seconds, days, months, years. You can also create arbitrary timestamps for any date and time you can think of. Or get the timestamp for now, today, yesterday, or tomorrow.


Here's an example:

Code: Select all

	local now = Timestamp:now();
	print("Now:\t", now);

	local past = now:subSeconds(30);
	print("-30 sec:", past);
	print("\t\tIs past?", past:isPast(), past:diffForHumans(), "\n");

	local later = now:addHours(12):addMinutes(90):addSeconds(32);
	print("Later:\t", later);

	local today = Timestamp:today();
	print("Today:\t", today);

	local yesterday = Timestamp:yesterday();
	print("Yesterday:", yesterday);

	local nextMonth = now:addMonths(1);
	print("Next month:", nextMonth);

	local arbitrary = Timestamp(2016, 6, 12, 8, 52);
	print("Arbitrary:", arbitrary);

	print("Year-month:", arbitrary:format("%Y-%m"));

	print("Now less than arbitrary?", now < arbitrary);
Output:

Code: Select all

Now:            2015-01-01  12:38:51
-30 sec:        2015-01-01  12:38:21
                Is past?        true    30 seconds ago

Later:          2015-01-02  02:09:23
Today:          2015-01-01  00:00:00
Yesterday:      2014-12-31  00:00:00
Next month:     2015-02-01  12:38:51
Arbitrary:      2016-06-12  08:52:00
Year-month:     2016-06
Now less than arbitrary?        true
When adding/subtracting months, it properly keeps track of how many days are in each month instead of just assuming some number. If you add/subtract any number that overflows its bounds (such as adding 13 months when there are only 12 in a year), it will also increment the required fields.

The isPast() method will be quite handy. Very often we want to trigger some event(s) after some time has past. Instead of:

Code: Select all

doSomethingTimestamp = os.time() + 3;

...

if( os.time() > doSomethingTimestamp ) then
  doSomething();
end
We can simply:

Code: Select all

doSomethingTimestamp = Timestamp:now():addSeconds(3);

...

if( doSomethingTimestamp:isPast() ) then
  doSomething();
end

What other features do you think could be useful?

Re: New timestamp class

Posted: Thu Jan 01, 2015 9:00 pm
by rock5
How about the difference between 2 times? Eg.

Code: Select all

start = Timestamp:now()
...
print("Elapsed time: ",Timestamp:now()-start)
So I take it this is now very accurate, no fractions of a second?

Re: New timestamp class

Posted: Fri Jan 02, 2015 11:29 am
by Administrator
Sure, difference between times makes sense, but I wasn't sure how to go about it. Returning a new Timestamp doesn't make sense there as it would act like like some time around 1970 (UNIX/POSIX timestamps all count the number of seconds since the epoch). Returning the number of seconds difference between the two should work though. We could also have diffInMinutes(), diffInHours(), diffInDays(), etc. functions. I think I also want to work in timezones.



This class does not use high-precision timers. There's one major problem with those: even though they use 64-bit integers, they run out of space very quickly and can only store up to a few years. Also, they depend entirely on things like the user's hardware and when it was booted up, so the timers are really only valid during runtime of a single process to keep track of very fine time differences. Things that they are terrible for: network applications (only valid on the originating machine), saving to file (may not be valid when reading it), working with real time values (ex. we want to compare the time to 5 o'clock), or displaying it to the user. POSIX timestamps take care of all those things much more readily.

Now, we could have a hybrid: internally use the high-precision timer to record fractions of a second and store that with the class. Time operations like now(), or difference functions could include the fractional seconds, but things like today(), or creating from an arbitrary date, would not bother with such granularity. Of course, again, the problem becomes whether or not this is actually necessary (at this point, why not just use the high-precision timer class?), and the problem of actually calculating it (because high-precision timers are again only useful for comparing against each other--not against an actual clock).

Re: New timestamp class

Posted: Fri Jan 02, 2015 2:07 pm
by rock5
Returning diff in seconds seems adequate. 'time' seems to be adequate for timing things.