+1 vote
asked by (370 points)
Hello all, i'm completely new here, and twine in general.

The last two weeks i've been watching lots of tutorials on YT, and a whole bunch of threads explaining how to do certain things.

I have an idea to create a relatively big, open world management game, i already know how to use some macros, but right now i can't continue without having a decent, simple, easy to use date and calendar system that counts time (only hours and minutes).

The story format i'm using is Sugarcube 2.21.0, on Twine 2.2.1.

I never dabbled in JS before, or any kind of coding in general, hence my ignorance.

My other problem is that most of the threads i find about how to make a clock system, are either for twine 1 or earlier versions of sugarcube, and not applicable to my case.

What i'm looking for essentially is a timer that counts time as a normal clock would, but only counts time through entering passages, for example, a sleep passage makes time go by 8hours, another makes time pass by 1minute, and so forth. And if it could count days and months as well, that'd be perfect.

I know this question gets asked a lot, and i don't want to add to the pile, but i'm tired of banging my head against the wall.

Can someone help me, please?

3 Answers

+1 vote
answered by (8.5k points)
selected by
Best answer

In the simplest case, for Earth dates in the Gregorian calendar, just use the standard JavaScript Date object. Set some value to it at the beginning of your game (in StoryInit or your starting passage) and you can always refer to it later to add or change the "current" time.

<<set $now = new Date("2238-07-05T10:30:00Z")>>

The Date object, for all its faults, has the neat ability that its numbers "overflow". For example, if you'd add 20 hours to this particular date and print it, it would be the morning of the 6th July, not the 30th hour of the 5th July.

<<run $now.setHours($now.getHours() + 20)>>
<<= $now.toGMTString()>>
/* prints "Fri, 06 Jul 2238 06:30:00 GMT" */

You can add some macros around this, in particular for the display, and you can also look at the moment.js module if you want even better control over dates and times. But to know what exactly to suggest here we'd need way more specifics about your requirements for manipulating and displaying the date and time.

For an example of a bit of possible "chrome" to polish your game with, take a look at the dyClockJS module.

commented by (370 points)
Thanks a lot for the detailed explanation.

You cleared things a bit more for me, but now i see my greatest obstacle will be JavaScript, as everytime i see javascripts i get a small seizure, how big and complex they are, specially for me, one who never programed anything in my life.

This is all very new, and very different from anything i've done, but i'll get there in time.

Thanks a lot again.

Any kind of help is appreciated and welcome! =)
+1 vote
answered by (30.8k points)
commented by (370 points)
Thank you for your reply, but seeing as i'm still watching tutorials and learning to control Sugarcube, all of these leave me with more answers than questions. I'll learn eventually though, at least i have three links to some examples i can apply in the future.


Thank you again. =)
+2 votes
answered by (8.6k points)
  • Create a new passage called "Game Clock".
  • Add a widget tag to this passage.
  • Paste Mad Exile's Gregorian Date & Time Widgets into this passage:
	Date & Time Widget Setup
	window.GameDays to [
		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
	window.GameMonths to [
		"Jan", "Feb", "Mar", "Apr", "May", "Jun",
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"

		Below we have to use the multi-parameter version of the Date
		constructor, rather than the date string version, because the
		date string version treats a missing timezone offset as UTC.
		While there are ways to determine players' timezone offsets,
		so they could be added to a date string, it's more convenient
		simply to use the multi-parameter constructor.

		The point of this is so that you can simply initialize the game
		world clock to whatever date and time you wish without having to
		worry about the players' timezone offsets, while still ensuring
		that they all see the same game world dates and times.
	/* params: year , month(0-based) , day , hour(24H) , minute [, second ] */
	$gameDate to new Date(2015, 2, 17, 3, 24); /* e.g. Mar 17, 2015 03:24 */

	Date & Time Advancement Widget Definitions
/* Adds the specified number of minutes. */
<<widget "addmins">>\
<<run $gameDate.setMinutes($gameDate.getMinutes() + $args[0])>>\

/* Adds the specified number of hours. */
<<widget "addhours">>\
<<run $gameDate.setHours($gameDate.getHours() + $args[0])>>\

/* Adds the specified number of days. */
<<widget "adddays">>\
<<run $gameDate.setHours($gameDate.getHours() + $args[0] * 24)>>\

	Date & Time Printing Widget Definitions
/* Prints the current date ("{weekday} {month} {day}, {year}"). */
<<widget "date">>\
<<print String.format("{0} {1} {2}, {3}",

/* Prints the current time (12H). */
<<widget "time12hr">>\
<<if $gameDate.getHours() eq 0>>\
<<elseif $gameDate.getHours() gt 12>>\
<<print $gameDate.getHours() - 12>>\
<<print $gameDate.getHours()>>\
<<if $gameDate.getMinutes() lt 10>>0<</if>><<print $gameDate.getMinutes()>> \
<<if $gameDate.getHours() gte 12>>PM<<else>>AM<</if>>\

/* Prints the current time (24H). */
<<widget "time24hr">>\
<<if $gameDate.getHours() lt 10>>0<</if>><<print $gameDate.getHours()>>:\
<<if $gameDate.getMinutes() lt 10>>0<</if>><<print $gameDate.getMinutes()>>\

/* Prints the current date and time (12H). */
<<widget "datetime">><<date>> <<time12hr>> (<<time24hr>>)<</widget>>
  • To advance the time 5 minutes in a passage, type <<addmins 5>> somewhere into the passage.
  • To advance 7 hours, <<addhours 7>>
  • To advance 30 days, <<adddays 30>>
commented by (370 points)

Thank you for your help.

I eventually got this code to work, the only things i'm missing right now are hou to make if statements regarding specific days and months!

I can set up shop hours no problem, but setting up certain events that take place only on certain days and months, now that i can't do. I tried looking into the written code, to see if what i'm seeking is there, and either it isn't or i'm just blind.

I tried lots of ways to refer to specific days, these are some of my attempts:

   \<<if $gameDate.getUTCDay() gte "mon">>
  It's closed.

   \<<if $gameDate.getUTCDay() is "Mon">>
  It's closed.

   \<<if $gameDate.getUTCDay() is "Monday">>
  It's closed.

   \<<if $gameDate.getUTCDay() is "monday">>
  It's closed.

   \<<if $window.GameDays is "mon">>
  It's closed.

   \<<if $gameDate.getUTCDay("mon") gte "mon">>
  It's closed.

   \<<if $gameDate.getUTCDay() is "mon">>
  It's closed.
   \<<if $gameDate.getDay("mon")>>
   \<<if $gameDate.getDay("tue")>>

I'm sure i'm doing something wrong,..

commented by (8.6k points)
<<if $gameDate.getDay() == 0>>It is Sunday
  <<elseif $gameDate.getDay() == 1>>It is Monday
  <<elseif $gameDate.getDay() == 2>>It is Tuesday
  <<elseif $gameDate.getDay() == 3>>It is Wednesday
  <<elseif $gameDate.getDay() == 4>>It is Thursday
  <<elseif $gameDate.getDay() == 5>>It is Friday
  <<elseif $gameDate.getDay() == 6>>It is Saturday

<<if $gameDate.getMonth() == 0>>It is January
  <<elseif $gameDate.getMonth() == 1>>It is February
  <<elseif $gameDate.getMonth() == 2>>It is March
  <<elseif $gameDate.getMonth() == 3>>It is April
  <<elseif $gameDate.getMonth() == 4>>It is May
  <<elseif $gameDate.getMonth() == 5>>It is June
  <<elseif $gameDate.getMonth() == 6>>It is July
  <<elseif $gameDate.getMonth() == 7>>It is August
  <<elseif $gameDate.getMonth() == 8>>It is September
  <<elseif $gameDate.getMonth() == 9>>It is October
  <<elseif $gameDate.getMonth() == 10>>It is November
  <<elseif $gameDate.getMonth() == 11>>It is December


commented by (370 points)

Thanks a whole bunch, this makes everything much easier! yeslaugh

commented by (8.6k points)
No problem, good luck!
commented by (30.8k points)

You can use the .toLocaleString() function to shorten just about all of the above code.  For example:

<<-$gameDate.toLocaleString("en-US", { weekday: 'long', month: 'short', day: 'numeric', year: 'numeric' } )>>

That would output something like "Monday, Oct. 8, 2018".  It's not limited to the date either, you can have it show the time as well by adding that to the options.  See the documentation linked to above for the various option settings.

commented by (170 points)


I've been trying to use a date and time tool/widget and it seems this one worked. Mainly to show it on the sidebar as so:

Time: <<time24h>>
Date: <<date>>

I've also removed the year from the widget since I did not need it and it worked perfectly:

<<print String.format("{0} {1} {2}, {3}",

I can add days, hours and so on, but I've tried to create a way to set the time so that it can be more flexible. Like so:

/* Date & Time Setting Widget Definitions */
/* Sets the specified number of minutes. */
<<widget "setmins">>\
<<run $gameDate.setUTCMinutes($gameDate.setUTCMinutes() + $args[0])>>\

/* Sets the specified number of hours. */
<<widget "sethours">>\
<<run $gameDate.setUTCHours($gameDate.setUTCHours() + $args[0])>>\

/* Sets the specified number of days. */
<<widget "setdays">>\
<<run $gameDate.setUTCHours($gameDate.setUTCHours() + $args[0] * 24)>>\

It's, obviously, mainly a copy/paster of the advance time of Mad Exile's /* Adds ... */. I thought it could work, but it displays this:

Time: :
Date: NaN,

The character goes to sleep. So I need a day to pass and the time to always be 8:00 (24h). The code looks like this:

/* Sets hours */
<<sethours 09>>
/* Sets minutes */
<<setmins 00>>

/* Adds 1 day-Pass time */
<<adddays 1>>

Adding things works like a charm. But it seems like I'm far from knowing how to change the "add" command into a "set" one.

I hope that's clear enough and that it isn't too much to ask for. I can't figure out how to solve it, but something tells me it's simple when I look at the code I'm using for reference (not that I'd be able to create it...).

Welcome to Twine Q&A, where you can ask questions and receive answers from other members of the community.

You can also find hints and information on Twine on the official wiki and the old forums archive.

See a spam question? Flag it instead of downvoting. A question flagged enough times will automatically be hidden while moderators review it.