To do this we’re going to create a custom dialog, show it to the user, and then update the dialog every half second to keep the timing fairly close without putting too much strain on our computer. We will use some of the date functions to get the current time, get the time at midnight on New Years Eve, compare the two, and get the amount of time remaining.
Without further ado, let’s get into it.
string newyear;
qword nwyr;
qword now;
int nowunix;
int newunix;
string timeleft;
string timeleftarray[];
int secondsleft;
int days;
int hours;
int minutes;
int seconds;
string daylabel;
string hourlabel;
string minutelabel;
string secondlabel;
int updateTime() {
now = GetLocalTime();
nowunix = DateToUnix(now);
secondsleft = newunix-nowunix;
timeleft = SecondsToTime(secondsleft);
timeleftarray = ExplodeString(timeleft, ":");
hours = DecimalToInteger(timeleftarray[0]);
minutes = DecimalToInteger(timeleftarray[1]);
seconds = DecimalToInteger(timeleftarray[2]);
days = hours/24;
hours = hours%24;
if (days == 1) {
daylabel = "day";
}
else {
daylabel = "days";
}
if (hours == 1) {
hourlabel = "hour";
}
else {
hourlabel = "hours";
}
if (minutes == 1) {
minutelabel = "minute";
}
else {
minutelabel = "minutes";
}
if (seconds == 1) {
secondlabel = "second";
}
else {
secondlabel = "seconds";
}
return ERROR_NONE;
}
int main() {
newyear = "2018-01-01T00:00:00";
nwyr = StringToDate(newyear, 2);
newunix = DateToUnix(nwyr);
updateTime();
DialogBox("TimeLeftDlg", "TL_");
return ERROR_NONE;
}
int TL_load() {
DialogSetTimer(500, 1);
EditSetText(101, FormatString("%d %s, %02d %s, %02d %s, %02d %s left", days, daylabel, hours, hourlabel, minutes, minutelabel, seconds, secondlabel));
}
int TL_timer(int id) {
updateTime();
EditSetText(101, FormatString("%d %s, %02d %s, %02d %s, %02d %s left", days, daylabel, hours, hourlabel, minutes, minutelabel, seconds, secondlabel));
}
#resource
TimeLeftDlg DIALOG 0, 0, 180, 44
STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "It's Almost The New Year!"
FONT 8, "MS Sans Serif"
{
CONTROL "", 101, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 6, 8, 140, 8, 0
CONTROL "until the New Year!", 102, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 6, 16, 160, 8, 0
CONTROL "Stop", IDCANCEL, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 126, 24, 45, 12
}
#endresource
Please note that if you’re using this script exactly as written it will count up after the new year.
So the first thing that we do is create a whole bunch of global variables. These variables will be used throughout the script to keep track of how much time is left and also keep track of the labels to print everything out in a more human friendly form. These variables are purposefully left global so that they can be updated in one function and then used in another without having to pass all of variables around.
string newyear;
qword nwyr;
qword now;
int nowunix;
int newunix;
string timeleft;
string timeleftarray[];
int secondsleft;
int days;
int hours;
int minutes;
int seconds;
string daylabel;
string hourlabel;
string minutelabel;
string secondlabel;
Next we will create a function to do the calculations and update the variables to the current values. We’ll also do the logic to update the textual values. I’ll explain this section in detail below.
int updateTime() {
now = GetLocalTime();
nowunix = DateToUnix(now);
secondsleft = newunix-nowunix;
timeleft = SecondsToTime(secondsleft);
timeleftarray = ExplodeString(timeleft, ":");
hours = DecimalToInteger(timeleftarray[0]);
minutes = DecimalToInteger(timeleftarray[1]);
seconds = DecimalToInteger(timeleftarray[2]);
days = hours/24;
hours = hours%24;
if (days == 1) {
daylabel = "day";
}
else {
daylabel = "days";
}
if (hours == 1) {
hourlabel = "hour";
}
else {
hourlabel = "hours";
}
if (minutes == 1) {
minutelabel = "minute";
}
else {
minutelabel = "minutes";
}
if (seconds == 1) {
secondlabel = "second";
}
else {
secondlabel = "seconds";
}
return ERROR_NONE;
}
The first thing that we have to do is get the current time. GetLocalTime will give us the current time in the current timezone as a QWORD. We need to find a way to easily compare times, and the easiest way to do that in general is to get the Unix epoch equivalent, or the number of seconds since January 1st, 1970. We then take the Unix time of the new year and subtract the current time from that, giving us the number of seconds between the dates. We then convert the time back into a QWORD to use with other Legato functions. We use SecondsToTime to convert seconds into a string that is in “Hours:Minutes:Seconds” format, and then explode the result into an array on the colons. This gives us an array with those three values. We take the first and store it as hours, the second as minutes, and third as seconds. Finally we get the number of days by taking the number of hours and dividing by 24, while then using the modulus operation to get the remaining hours in the day. We could work entirely in Unix time, but we’re using Legato functions here to make the code easier to understand.
Finally the last thing to do is to check whether we have to make our label singular by seeing if any of these values is 1. If it is, the label is singular, otherwise the label is made to be plural.
The function that we just made will be called every single update. Now let’s look at what runs when we start the script.
int main() {
newyear = "2018-01-01T00:00:00";
nwyr = StringToDate(newyear, 2);
newunix = DateToUnix(nwyr);
updateTime();
DialogBox("TimeLeftDlg", "TL_");
return ERROR_NONE;
}
Here we define the new year as midnight on the 1st of January 2018, convert it to a date format, then convert it to unix time. We use that value in the updateTime function. We then call the function we just went through, open our dialog box, and return.
int TL_load() {
DialogSetTimer(500, 1);
EditSetText(101, FormatString("%d %s, %02d %s, %02d %s, %02d %s left", days, daylabel, hours, hourlabel, minutes, minutelabel, seconds, secondlabel));
}
int TL_timer(int id) {
updateTime();
EditSetText(101, FormatString("%d %s, %02d %s, %02d %s, %02d %s left", days, daylabel, hours, hourlabel, minutes, minutelabel, seconds, secondlabel));
}
These two functions are pretty similar. One is called when the dialog first opens, the other is called when the timer ticks. The load function starts the timer running and then updates the text in the dialog to the values we just calculated in the updateTime function. The timer function runs the updateTime function and then updates the text in the dialog. That’s all we have to do with the dialog, as the “Stop” button uses IDCANCEL and will close the dialog, causing the main function to continue and finish.
#resource
TimeLeftDlg DIALOG 0, 0, 180, 44
STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_CAPTION
CAPTION "It's Almost The New Year!"
FONT 8, "MS Sans Serif"
{
CONTROL "", 101, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 6, 8, 140, 8, 0
CONTROL "until the New Year!", 102, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 6, 16, 160, 8, 0
CONTROL "Stop", IDCANCEL, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 126, 24, 45, 12
}
#endresource
Finally we have the resource for the dialog. I’ve created a small dialog with the title “It’s Almost The New Year!”, two small text controls, and a cancel button. The first static string control is left blank as that is the value that we update each time the timer ticks.
This script can be updated or extended fairly easily. You can change the day that you are counting down to, or even add in an initial dialog to choose the date dynamically.
To end the year, I’ve created a small script that will help us count down to ringing in the new year. We use some of Legato’s date functions to compare the dates between now and midnight on New Years Eve, and then we use a dialog to display these results to our user.
From all of us here at Novaworks, have a wonderful New Year and we hope that your 2018 will bring you many new experiences and excitement.
Joshua Kwiatkowski is a developer at Novaworks, primarily working on Novaworks’ cloud-based solution, GoFiler Online. He is a graduate of the Rochester Institute of Technology with a Bachelor of Science degree in Game Design and Development. He has been with the company since 2013. |
Additional Resources
Novaworks’ Legato Resources
Legato Script Developers LinkedIn Group
Primer: An Introduction to Legato