Calculating weekdays and dates with Go

Terminal with Mouse Input

The MouseLeft event comes up if the user clicks and releases the left mouse button. The payload enclosed with the event indicates the coordinates at which the mouse pointer was located at the time of the click. Line 47 needs to dynamically convert the event received as a generic interface{} type to a ui.Mouse type; it then uses Y to access the (vertical) y-value of the click position.

The wdayPick() function in line 86 determines the clicked weekday. It can do that because the program knows from the UI layout that Sunday is at the click position with a y-value of 4, Monday at 5, and so on through Saturday at position 10. The function discards any other position, returning an error, so that the main program simply ignores the click.

If the user has done their mental arithmetic correctly and selected the right weekday, the condition in line 53 is true, and the BorderStyle.Fg attribute sets the weekday widget's frame to green. The following call to randDate() in line 56 fetches a new date task, and the success counter wins is incremented by one. However, if the user guesses wrong, line 59 colors the widget's frame red and sets wins back to zero. Life can be hard!

To refresh the success counter graphically, the call to displayTask() in line 63 changes the widget's contents, and the call ui.Render() with both widgets as parameters updates the current status in the terminal. To make sure that the red or green border that provides user feedback only appears briefly and then disappears again, line 65 starts a Go routine that runs in parallel; it first sleeps for 200ms thanks to time.After(), then resets the window's frame to the original White (which actually looks gray), and displays the whole thing with ui.Render(). That's how dynamics come into play, thanks simply to the standard parallelism features built into Go.

Text in Color

The text displayed in the widgets can also be colored using termui if so desired – not with an attribute like the widget borders, but using special tags in the text string on display. The date to be calculated appears in black thanks to this, and the number of successfully completed tasks in green; lines 80 to 81 include corresponding color commands in the text to be displayed with (fg:black) and (fg:green).

Tricky Date Arithmetic

Selecting a random day of the year is more difficult than you might think. Sure, most years have 365 days, but in a leap year with 366 days, even February 29 should occur every now and then. Thanks to the Duration type from the time package, Go offers a method to calculate the time span between January 1 of the year investigated and the same date of the following year. Unfortunately, it refuses to express this in days, but uses hours instead.

The reason for this is the mess that occurs when a leap second [5] or the summer/winter time changeover occurs between two dates. Does that count as a fraction of a day or not? Go forces the programmer to multiply the hour difference by 24 to get the day number – as an indication that this may not be entirely true.

It is easier to use the Unix epoch time on Linux; this gives you the number of seconds that elapsed since January 1, 1970. It does not include leap seconds that have occurred, but gives the same timestamp to the times before and during a leap second. The randDate() function from line 93 in Listing 1 determines the Unix time for January 1st of the investigated year as well as the time stamp for January 1 of the following year and determines the time difference in seconds.

The rand.Intn() function then selects a random number between   (inclusive) and the timestamp of January 1 of the following year (exclusive) from the math/rand package and adds the value to the start date. The result is a second timestamp sometime in the current year, which the time.Unix() function converts into a time.Time object from the Go standard library, whose month and day are output by Month() and Day(). Since Unix seconds are available as int64 and the random functions from math/rand expect and return normal ints, line 102 needs to mediate between the two and convert the types accordingly.

The random number generator provided by Go still has the unpleasant feature of supplying the same random values whenever you call the program; this is unlikely to offer users any lasting training benefits in the long run. For this reason, line 98 taps into a new entropy source, initializes it with the current time in nanoseconds as the seed, and thus creates the new random number generator in the r1 variable. Its Intn() method therefore comes up with new random sequences each time the dateday binary is called.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Command Line: cal and date

    The legacy cal and date tools help users keep track of the time and date. You can even change the system time with a single shell command.

  • SuperKaramba Workshop

    If you can’t find the SuperKaramba theme you’re looking for, you can always build your own.

  • Programming Snapshot – Mileage AI

    On the basis of training data in the form of daily car mileage, Mike Schilli's AI program tries to identify patterns in driving behavior and make forecasts.

  • At a Glance

    Using extensions in Go and Ruby, Mike Schilli adapts the WTF terminal dashboard tool to meet his personal needs.

  • Perl: Math Tricks

    A trick that anybody can learn lets you determine the day of the week from the date. We’ll apply some Perl technology to discover whether the method is reliable.

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More